From 7c0e4646d694c384fd1c1932182a65731d600979 Mon Sep 17 00:00:00 2001 From: Ivan Towlson Date: Mon, 16 Sep 2024 15:17:34 +1200 Subject: [PATCH] Fix watch with workdir not working on Windows Signed-off-by: itowlson --- src/commands/watch/filters.rs | 44 ++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/commands/watch/filters.rs b/src/commands/watch/filters.rs index 11f4777b8d..970266697f 100644 --- a/src/commands/watch/filters.rs +++ b/src/commands/watch/filters.rs @@ -125,7 +125,7 @@ fn create_source_globs(cid: &str, c: &v2::Component) -> Option> { build .watch .iter() - .filter_map(|w| Path::new(workdir).join(w).to_str().map(String::from)) + .map(|w| concatenate_glob_friendly(workdir, w)) .collect() }) .unwrap_or_else(|| build.watch.clone()); @@ -137,6 +137,20 @@ fn create_source_globs(cid: &str, c: &v2::Component) -> Option> { } } +/// Using Path::join on Windows correctly joins with a backslash. But the watchexec glob +/// engines hates backslashes. So we must always use forward slashes in glob expressions, +/// and in workdirs, and for concatenating the two. (We could use Path::join on Unix but +/// the signature ends up a bit different because to_str returns an Option, so...) +fn concatenate_glob_friendly(workdir: &str, watch_glob: &str) -> String { + if PathBuf::from(watch_glob).is_absolute() { + watch_glob.to_string() + } else if workdir.ends_with('/') { + format!("{workdir}{watch_glob}") + } else { + format!("{workdir}/{watch_glob}") + } +} + #[async_trait] impl FilterFactory for ManifestFilterFactory { async fn build_filter( @@ -207,3 +221,31 @@ impl watchexec::filter::Filterer for CompositeFilterer { Ok(false) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn joining_workdir_always_uses_forward_slash() { + assert_eq!( + "work/src/**/*.rs", + concatenate_glob_friendly("work", "src/**/*.rs") + ); + assert_eq!( + "work/src/**/*.rs", + concatenate_glob_friendly("work/", "src/**/*.rs") + ); + + #[cfg(not(target_os = "windows"))] + assert_eq!( + "/global/src/**/*.rs", + concatenate_glob_friendly("work", "/global/src/**/*.rs") + ); + #[cfg(target_os = "windows")] + assert_eq!( + "D:/global/src/**/*.rs", + concatenate_glob_friendly("work", "D:/global/src/**/*.rs") + ); + } +}