Compute watched files and masks from current fpm settings.
This is the primary "graph to watchlist" entry point.
files: normalized, unique file paths to watch.file_mask: a bitmask per file that encodes which root target(s) the
file belongs to (used for name injection on run/test).roots: root executable/test targets. roots(r)%mask is a 1-bit mask.manifest_key: placeholder output (computed elsewhere); set to 0 here.build_secs: sum of secs_model + secs_targets + secs_watch.secs_model: time spent building the fpm model.secs_targets: time spent expanding sources into targets.secs_watch: time spent collecting and filtering file paths.bit_size(0_int64) (typically 64 roots).| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(fpm_build_settings), | intent(inout) | :: | settings | |||
| type(watch_opts_t), | intent(in) | :: | w | |||
| type(string_t), | intent(out), | allocatable | :: | files(:) | ||
| integer(kind=int64), | intent(out), | allocatable | :: | file_mask(:) | ||
| type(root_info_t), | intent(out), | allocatable | :: | roots(:) | ||
| integer(kind=int64), | intent(out) | :: | manifest_key | |||
| real, | intent(out) | :: | build_secs | |||
| real, | intent(out) | :: | secs_model | |||
| real, | intent(out) | :: | secs_targets | |||
| real, | intent(out) | :: | secs_watch |
subroutine compute_watch_files_from_settings(settings, w, files, file_mask, roots, manifest_key, build_secs, secs_model, secs_targets, secs_watch) class(fpm_build_settings), intent(inout) :: settings type(watch_opts_t), intent(in) :: w type(string_t), allocatable, intent(out) :: files(:) integer(int64), allocatable, intent(out) :: file_mask(:) type(root_info_t), allocatable, intent(out) :: roots(:) integer(int64), intent(out) :: manifest_key real, intent(out) :: build_secs real, intent(out) :: secs_model, secs_targets, secs_watch type(package_config_t), allocatable :: package type(fpm_model_t), allocatable :: model type(build_target_ptr), allocatable :: targets(:) type(error_t), allocatable :: err type(dependency_tree_t) :: tree logical, allocatable :: keep(:) logical, allocatable :: visited(:) integer(int64), allocatable :: target_mask(:) type(string_t), allocatable :: dep_dirs(:) integer :: i, r, nroots integer(int64) :: rate, t0, t1, tw0, tw1 integer :: n_before, n_after secs_model = 0.0 secs_targets = 0.0 secs_watch = 0.0 build_secs = 0.0 call system_clock(count_rate=rate) if (rate <= 0_int64) rate = 1000_int64 allocate(package, model) call get_package_data(package, "fpm.toml", err, apply_defaults=.true.) if (allocated(err)) then write(error_unit,'(a)') "fpm-watch: manifest error: " // err%message stop 1 end if call new_dependency_tree(tree, build_dir=trim_or_empty(settings%build_dir), path_to_config=trim_or_empty(settings%path_to_config)) call tree%add(package, err) if (allocated(err)) then write(error_unit,'(a)') "fpm-watch: dependency error: " // err%message stop 1 end if if (w%watch_deps) then call collect_dep_dirs(tree, dep_dirs) if (w%verbosity >= 1) then call log_info(w, "deps: watching dependency sources (deps=" // str(size(dep_dirs)) // ")") end if else if (allocated(dep_dirs)) deallocate(dep_dirs) allocate(dep_dirs(0)) end if call system_clock(t0) call build_model(model, settings, package, err) call system_clock(t1) secs_model = real(t1 - t0) / real(rate) if (allocated(err)) then write(error_unit,'(a)') "fpm-watch: model error: " // err%message stop 1 end if call system_clock(t0) call targets_from_sources(targets, model, settings%prune, package%library, err) call system_clock(t1) secs_targets = real(t1 - t0) / real(rate) if (allocated(err)) then write(error_unit,'(a)') "fpm-watch: targets error: " // err%message stop 1 end if call system_clock(tw0) allocate(keep(size(targets))) keep = .false. select type (s => settings) type is (fpm_test_settings) do i = 1, size(targets) if (targets(i)%ptr%is_executable_target(FPM_SCOPE_TEST)) keep(i) = .true. end do type is (fpm_run_settings) if (s%example) then call select_names_or_all(targets, FPM_SCOPE_EXAMPLE, s%name, keep) else call select_names_or_all(targets, FPM_SCOPE_APP, s%name, keep) end if class default keep = .true. end select nroots = count(keep) allocate(visited(size(targets))) visited = .false. if (is_run_or_test(settings) .and. nroots > 0 .and. nroots <= bit_size(0_int64)) then allocate(roots(nroots)) allocate(target_mask(size(targets))) target_mask = 0_int64 r = 0 do i = 1, size(targets) if (.not. keep(i)) cycle r = r + 1 roots(r)%name = basename(targets(i)%ptr%output_file, suffix=.false.) roots(r)%mask = shiftl(1_int64, r-1) call dfs_mark_mask(targets(i)%ptr, targets, target_mask, roots(r)%mask) end do visited = (target_mask /= 0_int64) else if (allocated(roots)) deallocate(roots) allocate(roots(0)) if (allocated(target_mask)) deallocate(target_mask) if (all(keep)) then visited = .true. else do i = 1, size(targets) if (keep(i)) call dfs_mark_bool(targets(i)%ptr, targets, visited) end do end if end if if (w%watch_deps) then call gather_files_with_mask(targets, visited, target_mask, files, file_mask, trim_or_empty(settings%build_dir), dep_dirs) else call gather_files_with_mask(targets, visited, target_mask, files, file_mask, trim_or_empty(settings%build_dir)) end if if (w%watch_deps) then call push_file_with_mask(files, file_mask, "fpm.toml", trim_or_empty(settings%build_dir), 0_int64, dep_dirs) else call push_file_with_mask(files, file_mask, "fpm.toml", trim_or_empty(settings%build_dir), 0_int64) end if do i = 1, tree%ndep if (.not. allocated(tree%dep(i)%proj_dir)) cycle if (len_trim(tree%dep(i)%proj_dir) == 0) cycle if (w%watch_deps) then call push_file_with_mask(files, file_mask, join_path(tree%dep(i)%proj_dir, "fpm.toml"), trim_or_empty(settings%build_dir), 0_int64, dep_dirs) else call push_file_with_mask(files, file_mask, join_path(tree%dep(i)%proj_dir, "fpm.toml"), trim_or_empty(settings%build_dir), 0_int64) end if end do n_before = 0 if (allocated(files)) n_before = size(files) call filter_watch_files(files, w%include, w%ignore, file_mask) n_after = 0 if (allocated(files)) n_after = size(files) if (w%debug) then call log_info(w, "debug: watch files filtered: " // str(n_before) // " -> " // str(n_after)) end if call system_clock(tw1) secs_watch = real(tw1 - tw0) / real(rate) build_secs = secs_model + secs_targets + secs_watch manifest_key = 0_int64 if (w%verbosity >= 1) then call log_info(w, "timings: model=" // ftoa(secs_model) // "s targets=" // ftoa(secs_targets) // "s watchlist=" // ftoa(secs_watch) // "s") call log_info(w, "targets: total=" // str(size(targets)) // " closure=" // str(count(visited))) end if deallocate(package, model) if (allocated(targets)) deallocate(targets) if (allocated(keep)) deallocate(keep) if (allocated(visited)) deallocate(visited) if (allocated(target_mask)) deallocate(target_mask) if (allocated(dep_dirs)) deallocate(dep_dirs) contains subroutine collect_dep_dirs(tree, dep_dirs) type(dependency_tree_t), intent(in) :: tree type(string_t), allocatable, intent(out) :: dep_dirs(:) integer :: i if (tree%ndep <= 0) then allocate(dep_dirs(0)) return end if allocate(dep_dirs(tree%ndep)) do i = 1, tree%ndep if (allocated(tree%dep(i)%proj_dir)) then dep_dirs(i)%s = normalize_path(trim(tree%dep(i)%proj_dir)) else dep_dirs(i)%s = "" end if end do end subroutine collect_dep_dirs end subroutine compute_watch_files_from_settings