ignore: fix improper hidden filtering

This commit fixes a bug where `rg --hidden .` would behave differently
with respect to ignore filtering than `rg --hidden ./`. In particular,
this was due to a bug where the directory name `.` caused the leading
`.` in a hidden directory to get stripped, which in turn caused the
ignore rules to fail.

Fixes #807
This commit is contained in:
Andrew Gallant 2018-02-14 18:15:17 -05:00
parent b71a110ccf
commit 361698b90a
No known key found for this signature in database
GPG Key ID: B2E3A4923F8B0D44
2 changed files with 30 additions and 2 deletions

View File

@ -66,6 +66,12 @@ impl Glob {
pub fn is_only_dir(&self) -> bool { pub fn is_only_dir(&self) -> bool {
self.is_only_dir self.is_only_dir
} }
/// Returns true if and only if this glob has a `**/` prefix.
fn has_doublestar_prefix(&self) -> bool {
self.actual.starts_with("**/")
|| (self.actual == "**" && self.is_only_dir)
}
} }
/// Gitignore is a matcher for the globs in one or more gitignore files /// Gitignore is a matcher for the globs in one or more gitignore files
@ -278,7 +284,10 @@ impl Gitignore {
// BUT, a file name might not have any directory components to it, // BUT, a file name might not have any directory components to it,
// in which case, we don't want to accidentally strip any part of the // in which case, we don't want to accidentally strip any part of the
// file name. // file name.
if !is_file_name(path) { //
// As an additional special case, if the root is just `.`, then we
// shouldn't try to strip anything, e.g., when path begins with a `.`.
if self.root != Path::new(".") && !is_file_name(path) {
if let Some(p) = strip_prefix(&self.root, path) { if let Some(p) = strip_prefix(&self.root, path) {
path = p; path = p;
// If we're left with a leading slash, get rid of it. // If we're left with a leading slash, get rid of it.
@ -454,7 +463,7 @@ impl GitignoreBuilder {
// prefix. // prefix.
if !literal_separator { if !literal_separator {
// ... but only if we don't already have a **/ prefix. // ... but only if we don't already have a **/ prefix.
if !(glob.actual.starts_with("**/") || (glob.actual == "**" && glob.is_only_dir)) { if !glob.has_doublestar_prefix() {
glob.actual = format!("**/{}", glob.actual); glob.actual = format!("**/{}", glob.actual);
} }
} }
@ -620,6 +629,12 @@ mod tests {
ignored!(ig29, ROOT, "node_modules/ ", "node_modules", true); ignored!(ig29, ROOT, "node_modules/ ", "node_modules", true);
ignored!(ig30, ROOT, "**/", "foo/bar", true); ignored!(ig30, ROOT, "**/", "foo/bar", true);
ignored!(ig31, ROOT, "path1/*", "path1/foo"); ignored!(ig31, ROOT, "path1/*", "path1/foo");
ignored!(ig32, ROOT, ".a/b", ".a/b");
ignored!(ig33, "./", ".a/b", ".a/b");
ignored!(ig34, ".", ".a/b", ".a/b");
ignored!(ig35, "./.", ".a/b", ".a/b");
ignored!(ig36, "././", ".a/b", ".a/b");
ignored!(ig37, "././.", ".a/b", ".a/b");
not_ignored!(ignot1, ROOT, "amonths", "months"); not_ignored!(ignot1, ROOT, "amonths", "months");
not_ignored!(ignot2, ROOT, "monthsa", "months"); not_ignored!(ignot2, ROOT, "monthsa", "months");

View File

@ -1232,6 +1232,19 @@ clean!(regression_599, "^$", "input.txt", |wd: WorkDir, mut cmd: Command| {
assert_eq!(expected, lines); assert_eq!(expected, lines);
}); });
// See: https://github.com/BurntSushi/ripgrep/issues/807
clean!(regression_807, "test", ".", |wd: WorkDir, mut cmd: Command| {
wd.create(".gitignore", ".a/b");
wd.create_dir(".a/b");
wd.create_dir(".a/c");
wd.create(".a/b/file", "test");
wd.create(".a/c/file", "test");
cmd.arg("--hidden");
let lines: String = wd.stdout(&mut cmd);
assert_eq!(lines, format!("{}:test\n", path(".a/c/file")));
});
// See: https://github.com/BurntSushi/ripgrep/issues/1 // See: https://github.com/BurntSushi/ripgrep/issues/1
clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| { clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| {
let sherlock = let sherlock =