From e52df340fa322ab5c6d5d83e8e18685c95f6c092 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 19 Jun 2026 23:22:04 +0300 Subject: [PATCH] tools: fix `v watch run` not reloading on source changes (fix #27463) (#27501) --- cmd/tools/vwatch.v | 2 +- cmd/tools/vwatch_test.v | 54 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/cmd/tools/vwatch.v b/cmd/tools/vwatch.v index 06f2ca14d..f57c5e724 100644 --- a/cmd/tools/vwatch.v +++ b/cmd/tools/vwatch.v @@ -218,7 +218,7 @@ fn (mut context Context) get_stats_for_affected_vfiles() []VFileStat { mut files := os.ls(path) or { []string{} } next_file: for pf in files { pf_path := os.join_path_single(path, pf) - if context.only_watch.len > 0 { + if context.only_watch.len > 0 && context.only_watch[0] != '' { // in the whitelist mode, first only allow files, which match at least one of the patterns in context.only_watch: mut matched_pattern_idx := -1 for ow_pattern_idx, ow_pattern in context.only_watch { diff --git a/cmd/tools/vwatch_test.v b/cmd/tools/vwatch_test.v index 649c11b0d..7a309a33a 100644 --- a/cmd/tools/vwatch_test.v +++ b/cmd/tools/vwatch_test.v @@ -47,3 +47,57 @@ fn test_watch_keeps_backend_flag_intact() { assert !output.contains('-baend'), output assert !output.contains('Unknown argument `-baend`'), output } + +// Regression test for https://github.com/vlang/v/issues/27463 : +// `v watch run main.v` should recompile and rerun the program, when its source changes. +fn test_watch_run_reloads_on_source_change() { + source_path := os.join_path(tsource_dir, 'reload.v') + marker_path := os.join_path(toutput_dir, 'reload_marker.txt') + os.rm(marker_path) or {} + write_versioned_source(source_path, 'V1')! + + mut process := os.new_process(vexe) + process.set_work_folder(vroot) + process.set_redirect_stdio() + process.use_pgroup = true + // the marker_path argument is passed through to the compiled and run program (see write_versioned_source): + process.set_args(['watch', 'run', source_path, marker_path]) + process.run() + + // wait for the first compile+run to write the marker file: + first_run_done := wait_for_marker(marker_path, 'V1') + + // os.file_last_mod_unix has a 1 second resolution, so make sure the edit lands in a later second, + // otherwise the change detection loop can not notice that the source file was modified at all: + time.sleep(1500 * time.millisecond) + write_versioned_source(source_path, 'V2')! + + // the watcher should detect the change, recompile, and rerun, updating the marker to V2: + reloaded := wait_for_marker(marker_path, 'V2') + + if process.is_alive() { + process.signal_pgkill() + } + process.wait() + output := process.stdout_slurp() + process.stderr_slurp() + process.close() + + assert first_run_done, 'the watched program was never compiled and run\n${output}' + assert reloaded, 'the watcher did not recompile and rerun after the source file changed\n${output}' +} + +fn write_versioned_source(source_path string, version string) ! { + os.write_file(source_path, + "import os\nfn main() {\n\tos.write_file(os.args[1], '${version}') or { panic(err) }\n}\n")! +} + +fn wait_for_marker(marker_path string, expected string) bool { + for _ in 0 .. 300 { + content := os.read_file(marker_path) or { '' } + if content == expected { + return true + } + time.sleep(100 * time.millisecond) + } + return false +} -- 2.39.5