diff --git a/lib/src/filter/tagged.rs b/lib/src/filter/tagged.rs index d1659e7..036d077 100644 --- a/lib/src/filter/tagged.rs +++ b/lib/src/filter/tagged.rs @@ -137,7 +137,11 @@ impl TaggedFilterer { let gc = self.glob_compiled.borrow(); if let Some(igs) = gc.as_ref() { trace!("checking against compiled Glob filters"); - match igs.matched(path, is_dir) { + match if path.strip_prefix(&self.origin).is_ok() { + igs.matched_path_or_any_parents(path, is_dir) + } else { + igs.matched(path, is_dir) + } { Match::None => { trace!("no match (fail)"); tag_match = false; @@ -155,7 +159,11 @@ impl TaggedFilterer { let ngc = self.not_glob_compiled.borrow(); if let Some(ngs) = ngc.as_ref() { trace!("checking against compiled NotGlob filters"); - match ngs.matched(path, is_dir) { + match if path.strip_prefix(&self.origin).is_ok() { + ngs.matched_path_or_any_parents(path, is_dir) + } else { + ngs.matched(path, is_dir) + } { Match::None => { trace!("no match (pass)"); tag_match = true; diff --git a/lib/tests/filter_tagged_paths.rs b/lib/tests/filter_tagged_paths.rs index e706645..e62ec0d 100644 --- a/lib/tests/filter_tagged_paths.rs +++ b/lib/tests/filter_tagged_paths.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; use watchexec::{ error::RuntimeError, @@ -12,22 +12,22 @@ use watchexec::{ trait Harness { fn check_path( &self, - path: &str, + path: PathBuf, file_type: Option, ) -> std::result::Result; fn path_pass(&self, path: &str, file_type: Option, pass: bool) { - let path = if let Some(suf) = path.strip_prefix("/test/") { let origin = dunce::canonicalize(".").unwrap(); - origin.join(suf).to_string_lossy().to_string() + let full_path = if let Some(suf) = path.strip_prefix("/test/") { + origin.join(suf) } else { - path.to_string() + origin.join(path) }; tracing::info!(?path, ?file_type, ?pass, "check"); assert_eq!( - self.check_path(&path, file_type).unwrap(), + self.check_path(full_path, file_type).unwrap(), pass, "{} {:?} (expected {})", match file_type { @@ -70,14 +70,11 @@ trait Harness { impl Harness for TaggedFilterer { fn check_path( &self, - path: &str, + path: PathBuf, file_type: Option, ) -> std::result::Result { let event = Event { - tags: vec![Tag::Path { - path: path.into(), - file_type, - }], + tags: vec![Tag::Path { path, file_type }], metadata: Default::default(), }; @@ -113,6 +110,18 @@ fn not_filter(pat: &str) -> Filter { } } +trait FilterExt { + fn in_path(self) -> Self; +} + +impl FilterExt for Filter { + fn in_path(mut self) -> Self { + let origin = dunce::canonicalize(".").unwrap(); + self.in_path = Some(origin); + self + } +} + #[tokio::test] async fn empty_filter_passes_everything() { let filterer = filt(&[]).await; @@ -424,152 +433,75 @@ async fn ignores_take_precedence() { // The following tests check that the "buggy"/"confusing" watchexec v1 behaviour // is no longer present. +fn watchexec_v1_confusing_suite(filterer: Arc) { + filterer.file_does_pass("apples"); + filterer.file_does_pass("apples/carrots/cauliflowers/oranges"); + filterer.file_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); + filterer.file_does_pass("apples/oranges/bananas"); + filterer.dir_does_pass("apples"); + filterer.dir_does_pass("apples/carrots/cauliflowers/oranges"); + filterer.dir_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); + + filterer.file_does_pass("raw-prunes"); + filterer.dir_does_pass("raw-prunes"); + filterer.file_does_pass("raw-prunes/carrots/cauliflowers/oranges"); + filterer.file_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); + filterer.file_does_pass("raw-prunes/oranges/bananas"); + filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/oranges"); + filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); + + filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/oranges"); + filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); + filterer.file_doesnt_pass("prunes/carrots/cauliflowers/oranges"); + filterer.file_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); + filterer.file_doesnt_pass("prunes/oranges/bananas"); +} + #[tokio::test] -#[ignore] async fn ignore_folder_with_bare_match() { - let filterer = filt(&[not_filter("prunes")]).await; - - filterer.file_does_pass("apples"); - filterer.file_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.file_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("apples/oranges/bananas"); - filterer.dir_does_pass("apples"); - filterer.dir_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - - filterer.file_does_pass("raw-prunes"); - filterer.dir_does_pass("raw-prunes"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("raw-prunes/oranges/bananas"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); + let filterer = filt(&[not_filter("prunes").in_path()]).await; filterer.file_doesnt_pass("prunes"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_doesnt_pass("prunes/oranges/bananas"); filterer.dir_doesnt_pass("prunes"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); + watchexec_v1_confusing_suite(filterer); } #[tokio::test] -#[ignore] async fn ignore_folder_with_bare_and_leading_slash() { - let filterer = filt(&[not_filter("/prunes")]).await; - - filterer.file_does_pass("apples"); - filterer.file_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.file_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("apples/oranges/bananas"); - filterer.dir_does_pass("apples"); - filterer.dir_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - - filterer.file_does_pass("raw-prunes"); - filterer.dir_does_pass("raw-prunes"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("raw-prunes/oranges/bananas"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); + let filterer = filt(&[not_filter("/prunes").in_path()]).await; filterer.file_doesnt_pass("prunes"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_doesnt_pass("prunes/oranges/bananas"); filterer.dir_doesnt_pass("prunes"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); + watchexec_v1_confusing_suite(filterer); } #[tokio::test] -#[ignore] async fn ignore_folder_with_bare_and_trailing_slash() { - let filterer = filt(&[not_filter("prunes/")]).await; + let filterer = filt(&[not_filter("prunes/").in_path()]).await; - filterer.file_does_pass("apples"); - filterer.file_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.file_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("apples/oranges/bananas"); - filterer.dir_does_pass("apples"); - filterer.dir_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - - filterer.file_does_pass("raw-prunes"); - filterer.dir_does_pass("raw-prunes"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("raw-prunes/oranges/bananas"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); - - filterer.file_doesnt_pass("prunes"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_doesnt_pass("prunes/oranges/bananas"); + filterer.file_does_pass("prunes"); filterer.dir_doesnt_pass("prunes"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); + watchexec_v1_confusing_suite(filterer); } #[tokio::test] -#[ignore] async fn ignore_folder_with_only_double_double_glob() { - let filterer = filt(&[not_filter("**/prunes/**")]).await; + let filterer = filt(&[not_filter("**/prunes/**").in_path()]).await; - filterer.file_does_pass("apples"); - filterer.file_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.file_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("apples/oranges/bananas"); - filterer.dir_does_pass("apples"); - filterer.dir_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - - filterer.file_does_pass("raw-prunes"); - filterer.dir_does_pass("raw-prunes"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("raw-prunes/oranges/bananas"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); - - filterer.file_doesnt_pass("prunes"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_doesnt_pass("prunes/oranges/bananas"); - filterer.dir_doesnt_pass("prunes"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); + filterer.file_does_pass("prunes"); + filterer.dir_does_pass("prunes"); + watchexec_v1_confusing_suite(filterer); } #[tokio::test] -#[ignore] async fn ignore_folder_with_double_and_double_double_globs() { - let filterer = filt(&[not_filter("**/prunes"), not_filter("**/prunes/**")]).await; - - filterer.file_does_pass("apples"); - filterer.file_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.file_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("apples/oranges/bananas"); - filterer.dir_does_pass("apples"); - filterer.dir_does_pass("apples/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("apples/carrots/cauliflowers/artichokes/oranges"); - - filterer.file_does_pass("raw-prunes"); - filterer.dir_does_pass("raw-prunes"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.file_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_does_pass("raw-prunes/oranges/bananas"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/oranges"); - filterer.dir_does_pass("raw-prunes/carrots/cauliflowers/artichokes/oranges"); + let filterer = filt(&[ + not_filter("**/prunes").in_path(), + not_filter("**/prunes/**").in_path(), + ]) + .await; filterer.file_doesnt_pass("prunes"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.file_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); - filterer.file_doesnt_pass("prunes/oranges/bananas"); filterer.dir_doesnt_pass("prunes"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/oranges"); - filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges"); + watchexec_v1_confusing_suite(filterer); }