diff --git a/.travis.yml b/.travis.yml index 7c3b872d0..52022134f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: rust env: global: - PROJECT_NAME=ripgrep + - RUST_BACKTRACE: full matrix: include: # Nightly channel. diff --git a/appveyor.yml b/appveyor.yml index d2de7e3b2..2aa4c526c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,7 @@ environment: global: PROJECT_NAME: ripgrep + RUST_BACKTRACE: full matrix: - TARGET: i686-pc-windows-gnu CHANNEL: stable diff --git a/ignore/src/gitignore.rs b/ignore/src/gitignore.rs index a4a8e23eb..b44428a37 100644 --- a/ignore/src/gitignore.rs +++ b/ignore/src/gitignore.rs @@ -191,12 +191,13 @@ impl Gitignore { self.matched_stripped(self.strip(path.as_ref()), is_dir) } - /// Returns whether the given path (file or directory) or any of its parent - /// directories matched a pattern in this gitignore matcher. + /// Returns whether the given path (file or directory, and expected to be + /// under the root) or any of its parent directories (up to the root) + /// matched a pattern in this gitignore matcher. /// /// NOTE: This method is more expensive than walking the directory hierarchy - /// top-to-bottom and matching the entries. But, it is useful in cases when - /// a list of paths are available without a hierarchy. + /// top-to-bottom and matching the entries. But, is easier to use in cases + /// when a list of paths are available without a hierarchy. /// /// `is_dir` should be true if the path refers to a directory and false /// otherwise. @@ -206,23 +207,28 @@ impl Gitignore { /// determined by a common suffix of the directory containing this /// gitignore) is stripped. If there is no common suffix/prefix overlap, /// then `path` is assumed to be relative to this matcher. - pub fn matched_recursive>(&self, path: P, is_dir: bool) -> Match<&Glob> { + pub fn matched_path_or_any_parents>( + &self, + path: P, + is_dir: bool, + ) -> Match<&Glob> { if self.is_empty() { return Match::None; } - let mut current_path = self.strip(path.as_ref()); - match self.matched_stripped(current_path, is_dir) { - Match::None => { - while let Some(parent) = current_path.parent() { - match self.matched_stripped(parent, is_dir) { - Match::None => current_path = parent, - a_match => return a_match, - } - } + let mut path = self.strip(path.as_ref()); + debug_assert!( + !path.has_root(), + "path is expect to be under the root" + ); + loop { + match self.matched_stripped(path, is_dir) { + Match::None => match path.parent() { + Some(parent) => path = parent, + None => return Match::None, + }, + a_match => return a_match, } - a_match => return a_match, } - Match::None } /// Like matched, but takes a path that has already been stripped. diff --git a/ignore/tests/gitignore_recursive_tests.gitignore b/ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore similarity index 100% rename from ignore/tests/gitignore_recursive_tests.gitignore rename to ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore diff --git a/ignore/tests/gitignore_recursive_tests.rs b/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs similarity index 91% rename from ignore/tests/gitignore_recursive_tests.rs rename to ignore/tests/gitignore_matched_path_or_any_parents_tests.rs index 2eb53334d..1b3f61842 100644 --- a/ignore/tests/gitignore_recursive_tests.rs +++ b/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs @@ -6,20 +6,31 @@ use std::path::Path; use ignore::gitignore::{Gitignore, GitignoreBuilder}; -const IGNORE_FILE: &'static str = "tests/gitignore_recursive_tests.gitignore"; +const IGNORE_FILE: &'static str = "tests/gitignore_matched_path_or_any_parents_tests.gitignore"; fn get_gitignore() -> Gitignore { let mut builder = GitignoreBuilder::new("ROOT"); - builder.add(IGNORE_FILE); + let error = builder.add(IGNORE_FILE); + assert!(error.is_none(), "failed to open gitignore file"); builder.build().unwrap() } +#[test] +#[should_panic(expected = "path is expect to be under the root")] +fn test_path_should_be_under_root() { + let gitignore = get_gitignore(); + let path = "/tmp/some_file"; + gitignore.matched_path_or_any_parents(Path::new(path), false); + assert!(false); +} + + #[test] fn test_files_in_root() { let gitignore = get_gitignore(); - let m = |path: &str| gitignore.matched_recursive(Path::new(path), false); + let m = |path: &str| gitignore.matched_path_or_any_parents(Path::new(path), false); // 0x assert!(m("ROOT/file_root_00").is_ignore()); @@ -50,7 +61,7 @@ fn test_files_in_root() { #[test] fn test_files_in_deep() { let gitignore = get_gitignore(); - let m = |path: &str| gitignore.matched_recursive(Path::new(path), false); + let m = |path: &str| gitignore.matched_path_or_any_parents(Path::new(path), false); // 0x assert!(m("ROOT/parent_dir/file_deep_00").is_ignore()); @@ -81,7 +92,7 @@ fn test_files_in_deep() { #[test] fn test_dirs_in_root() { let gitignore = get_gitignore(); - let m = |path: &str| gitignore.matched_recursive(Path::new(path), true); + let m = |path: &str| gitignore.matched_path_or_any_parents(Path::new(path), true); // 00 assert!(m("ROOT/dir_root_00").is_ignore()); @@ -168,7 +179,7 @@ fn test_dirs_in_root() { #[test] fn test_dirs_in_deep() { let gitignore = get_gitignore(); - let m = |path: &str| gitignore.matched_recursive(Path::new(path), true); + let m = |path: &str| gitignore.matched_path_or_any_parents(Path::new(path), true); // 00 assert!(m("ROOT/parent_dir/dir_deep_00").is_ignore());