watcher_run Subroutine

private subroutine watcher_run(self)

Run the main watch loop until termination.

Termination conditions: - The sentinel file .fpm-watch.stop exists, or - The process receives an external termination (e.g., Ctrl+C).

Each iteration performs: 1. Sleep for poll seconds. 2. Scan for changes (fingerprints). 3. If changes were found, sleep for debounce seconds and rescan. 4. If fpm.toml changed, rebuild watch list. 5. Otherwise, run the computed fpm command (with target injection for run/test), notify plugins, and accept fingerprints.

Type Bound

watcher_t

Arguments

Type IntentOptional Attributes Name
class(watcher_t), intent(inout) :: self

Calls

proc~~watcher_run~~CallsGraph proc~watcher_run watcher_t%watcher_run exists exists proc~watcher_run->exists proc~accept_changes accept_changes proc~watcher_run->proc~accept_changes proc~any_manifest_changed any_manifest_changed proc~watcher_run->proc~any_manifest_changed proc~build_run_command build_run_command proc~watcher_run->proc~build_run_command proc~handle_manifest_change handle_manifest_change proc~watcher_run->proc~handle_manifest_change proc~log_info log_info proc~watcher_run->proc~log_info proc~on_after_run_all feature_manager_t%on_after_run_all proc~watcher_run->proc~on_after_run_all proc~on_before_run_all feature_manager_t%on_before_run_all proc~watcher_run->proc~on_before_run_all proc~on_change_detected_all feature_manager_t%on_change_detected_all proc~watcher_run->proc~on_change_detected_all proc~rebuild_watch_list rebuild_watch_list proc~watcher_run->proc~rebuild_watch_list proc~report_changes report_changes proc~watcher_run->proc~report_changes proc~run_command_and_report run_command_and_report proc~watcher_run->proc~run_command_and_report proc~scan_changes scan_changes proc~watcher_run->proc~scan_changes proc~sleep_seconds sleep_seconds proc~watcher_run->proc~sleep_seconds basename basename proc~any_manifest_changed->basename proc~inject_names_into_cmd inject_names_into_cmd proc~build_run_command->proc~inject_names_into_cmd proc~handle_manifest_change->proc~log_info proc~handle_manifest_change->proc~rebuild_watch_list proc~manifest_key_from_files manifest_key_from_files proc~handle_manifest_change->proc~manifest_key_from_files proc~on_manifest_changed_all feature_manager_t%on_manifest_changed_all proc~handle_manifest_change->proc~on_manifest_changed_all colorize colorize proc~log_info->colorize proc~feat_after_noop watch_feature_t%feat_after_noop proc~on_after_run_all->proc~feat_after_noop proc~feat_before_noop watch_feature_t%feat_before_noop proc~on_before_run_all->proc~feat_before_noop proc~feat_change_noop watch_feature_t%feat_change_noop proc~on_change_detected_all->proc~feat_change_noop proc~rebuild_watch_list->proc~log_info proc~compute_watch_files_from_settings compute_watch_files_from_settings proc~rebuild_watch_list->proc~compute_watch_files_from_settings proc~ftoa ftoa proc~rebuild_watch_list->proc~ftoa proc~init_fingerprints init_fingerprints proc~rebuild_watch_list->proc~init_fingerprints proc~rebuild_watch_list->proc~manifest_key_from_files proc~on_watch_list_built_all feature_manager_t%on_watch_list_built_all proc~rebuild_watch_list->proc~on_watch_list_built_all proc~print_banner print_banner proc~rebuild_watch_list->proc~print_banner proc~print_file_list print_file_list proc~rebuild_watch_list->proc~print_file_list str str proc~rebuild_watch_list->str proc~report_changes->colorize proc~report_changes->proc~ftoa proc~report_changes->str proc~run_command_and_report->colorize proc~run_command_and_report->proc~ftoa run run proc~run_command_and_report->run proc~run_command_and_report->str proc~file_fingerprint file_fingerprint proc~scan_changes->proc~file_fingerprint proc~sleep_os sleep_os proc~sleep_seconds->proc~sleep_os proc~sleep_spin sleep_spin proc~sleep_seconds->proc~sleep_spin proc~compute_watch_files_from_settings->proc~log_info proc~compute_watch_files_from_settings->basename proc~compute_watch_files_from_settings->proc~ftoa proc~compute_watch_files_from_settings->str add add proc~compute_watch_files_from_settings->add build_model build_model proc~compute_watch_files_from_settings->build_model dep dep proc~compute_watch_files_from_settings->dep get_package_data get_package_data proc~compute_watch_files_from_settings->get_package_data is_executable_target is_executable_target proc~compute_watch_files_from_settings->is_executable_target join_path join_path proc~compute_watch_files_from_settings->join_path new_dependency_tree new_dependency_tree proc~compute_watch_files_from_settings->new_dependency_tree proc~dfs_mark_bool dfs_mark_bool proc~compute_watch_files_from_settings->proc~dfs_mark_bool proc~dfs_mark_mask dfs_mark_mask proc~compute_watch_files_from_settings->proc~dfs_mark_mask proc~filter_watch_files filter_watch_files proc~compute_watch_files_from_settings->proc~filter_watch_files proc~gather_files_with_mask gather_files_with_mask proc~compute_watch_files_from_settings->proc~gather_files_with_mask proc~is_run_or_test is_run_or_test proc~compute_watch_files_from_settings->proc~is_run_or_test proc~normalize_path normalize_path proc~compute_watch_files_from_settings->proc~normalize_path proc~push_file_with_mask push_file_with_mask proc~compute_watch_files_from_settings->proc~push_file_with_mask proc~select_names_or_all select_names_or_all proc~compute_watch_files_from_settings->proc~select_names_or_all proc~trim_or_empty trim_or_empty proc~compute_watch_files_from_settings->proc~trim_or_empty targets_from_sources targets_from_sources proc~compute_watch_files_from_settings->targets_from_sources proc~hash_block hash_block proc~file_fingerprint->proc~hash_block proc~init_fingerprints->proc~file_fingerprint proc~manifest_key_from_files->basename proc~manifest_key_from_files->proc~file_fingerprint features features proc~manifest_key_from_files->features proc~fnv1a_mix_i64 fnv1a_mix_i64 proc~manifest_key_from_files->proc~fnv1a_mix_i64 proc~fnv1a_mix_str fnv1a_mix_str proc~manifest_key_from_files->proc~fnv1a_mix_str proc~feat_manifest_noop watch_feature_t%feat_manifest_noop proc~on_manifest_changed_all->proc~feat_manifest_noop proc~feat_list_noop watch_feature_t%feat_list_noop proc~on_watch_list_built_all->proc~feat_list_noop proc~print_banner->colorize proc~print_banner->proc~ftoa proc~print_banner->str proc~active_features active_features proc~print_banner->proc~active_features proc~active_profile active_profile proc~print_banner->proc~active_profile proc~command_mode command_mode proc~print_banner->proc~command_mode proc~trim_or_default trim_or_default proc~print_banner->proc~trim_or_default proc~print_file_list->colorize proc~print_file_list->str get_os_type get_os_type proc~sleep_os->get_os_type interface~fpm_watch_sleep_seconds fpm_watch_sleep_seconds proc~sleep_os->interface~fpm_watch_sleep_seconds proc~join_csv join_csv proc~active_features->proc~join_csv proc~active_profile->proc~trim_or_default proc~dfs_mark_bool->proc~dfs_mark_bool dependencies dependencies proc~dfs_mark_bool->dependencies proc~find_ptr_index find_ptr_index proc~dfs_mark_bool->proc~find_ptr_index proc~dfs_mark_mask->proc~dfs_mark_mask proc~dfs_mark_mask->dependencies proc~dfs_mark_mask->proc~find_ptr_index proc~filter_watch_files->basename proc~filter_watch_files->proc~normalize_path glob glob proc~filter_watch_files->glob proc~fnv1a_mix_str->proc~fnv1a_mix_i64 include_dependencies include_dependencies proc~gather_files_with_mask->include_dependencies proc~vec_push_unique vec_push_unique proc~gather_files_with_mask->proc~vec_push_unique proc~hash_block->proc~fnv1a_mix_i64 proc~push_file_with_mask->proc~vec_push_unique proc~select_names_or_all->basename proc~select_names_or_all->is_executable_target proc~select_names_or_all->glob proc~vec_push_unique->exists proc~vec_push_unique->proc~normalize_path proc~is_ignored_path is_ignored_path proc~vec_push_unique->proc~is_ignored_path proc~is_in_dep_dirs is_in_dep_dirs proc~vec_push_unique->proc~is_in_dep_dirs proc~vec_grow vec_grow proc~vec_push_unique->proc~vec_grow proc~is_ignored_path->proc~normalize_path proc~contains_path_fragment contains_path_fragment proc~is_ignored_path->proc~contains_path_fragment proc~starts_with starts_with proc~is_ignored_path->proc~starts_with proc~is_in_dep_dirs->proc~normalize_path proc~is_in_dep_dirs->proc~starts_with proc~ends_with ends_with proc~contains_path_fragment->proc~ends_with

Source Code

   subroutine watcher_run(self)
      class(watcher_t), intent(inout) :: self

      integer :: changed_count
      type(string_t), allocatable :: changed(:)
      character(len=:), allocatable :: cmd
      integer :: exitstat, j, idx
      real :: secs

      integer(int64) :: rate, t_last_rescan, t_now
      real :: dt
      if (self%cfg%w%once) return

      call system_clock(count_rate=rate)
      if (rate <= 0_int64) rate = 1000_int64
      call system_clock(t_last_rescan)

      do
         if (exists(".fpm-watch.stop")) exit

         call sleep_seconds(self%cfg%w%poll)

         call scan_changes(self%files, self%fp_prev, self%fp_now, self%changed_idx, changed_count)

         if (changed_count > 0) then
            call sleep_seconds(self%cfg%w%debounce)
            call scan_changes(self%files, self%fp_prev, self%fp_now, self%changed_idx, changed_count)
         end if

         if (changed_count > 0) then
            if (any_manifest_changed(self%files, self%changed_idx, changed_count)) then
               call handle_manifest_change(self)
               cycle
            end if

            allocate(changed(changed_count))
            do j = 1, changed_count
               idx = self%changed_idx(j)
               if (idx >= 1 .and. idx <= size(self%files)) then
                  changed(j)%s = self%files(idx)%s
               else
                  changed(j)%s = ""
               end if
            end do

            call self%fm%on_change_detected_all(changed)
            call report_changes(self%files, self%changed_idx, changed_count, self%cfg%w)

            cmd = build_run_command( &
               settings      = self%cfg%settings,    &
               full_cmdline  = self%cfg%fpm_cmdline, &
               cmd_prefix    = self%cfg%cmd_prefix,  &
               cmd_rest      = self%cfg%cmd_rest,    &
               roots         = self%roots,           &
               file_mask     = self%file_mask,       &
               changed_idx   = self%changed_idx,     &
               changed_count = changed_count )

            call self%fm%on_before_run_all(cmd)
            call run_command_and_report(cmd, self%cfg%w, exitstat, secs)
            call self%fm%on_after_run_all(exitstat, secs)

            call accept_changes(self%fp_prev, self%fp_now, self%changed_idx, changed_count)

            deallocate(changed)
         end if

         if (self%cfg%w%rescan > 0.0) then
            call system_clock(t_now)
            if (t_now < t_last_rescan) then
               t_last_rescan = t_now
            else
               dt = real(t_now - t_last_rescan) / real(rate)
               if (dt >= self%cfg%w%rescan) then
                  call log_info(self%cfg%w, "rescan triggered -> rebuilding watch list")
                  call rebuild_watch_list(self, print_header=.false.)
                  call system_clock(t_last_rescan)
               end if
            end if
         end if
      end do
   end subroutine watcher_run