summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2016-09-25 18:31:41 -0400
committerAndrew Gallant <jamslam@gmail.com>2016-09-25 18:31:41 -0400
commited94aedf2746172a16e2ed3933eeaf1f41602fc6 (patch)
tree44122fbb8a657f76d9ff628419f7131011854961
parentfd5ae2f7955aac1f8603713cef307a333676a467 (diff)
Permit whitelisting hidden files in ignores.
Fixes #90
-rw-r--r--src/gitignore.rs13
-rw-r--r--src/ignore.rs18
-rw-r--r--src/pathutil.rs18
-rw-r--r--tests/tests.rs9
4 files changed, 47 insertions, 11 deletions
diff --git a/src/gitignore.rs b/src/gitignore.rs
index 4d90be82..e05dc582 100644
--- a/src/gitignore.rs
+++ b/src/gitignore.rs
@@ -31,7 +31,7 @@ use std::path::{Path, PathBuf};
use regex;
use glob;
-use pathutil::strip_prefix;
+use pathutil::{is_file_name, strip_prefix};
/// Represents an error that can occur when parsing a gitignore file.
#[derive(Debug)]
@@ -115,8 +115,15 @@ impl Gitignore {
if let Some(p) = strip_prefix("./", path) {
path = p;
}
- if let Some(p) = strip_prefix(&self.root, path) {
- path = p;
+ // Strip any common prefix between the candidate path and the root
+ // of the gitignore, to make sure we get relative matching right.
+ // 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
+ // file name.
+ if !is_file_name(path) {
+ if let Some(p) = strip_prefix(&self.root, path) {
+ path = p;
+ }
}
if let Some(p) = strip_prefix("/", path) {
path = p;
diff --git a/src/ignore.rs b/src/ignore.rs
index 9a33dde6..d24909c5 100644
--- a/src/ignore.rs
+++ b/src/ignore.rs
@@ -227,16 +227,10 @@ impl Ignore {
if let Some(is_ignored) = self.ignore_match(path, mat) {
return is_ignored;
}
- if self.ignore_hidden && is_hidden(&path) {
- debug!("{} ignored because it is hidden", path.display());
- return true;
- }
+ let mut whitelisted = false;
if !self.no_ignore {
- let mut whitelisted = false;
for id in self.stack.iter().rev() {
let mat = id.matched(path, is_dir);
- // println!("path: {}, mat: {:?}, id: {:?}",
- // path.display(), mat, id);
if let Some(is_ignored) = self.ignore_match(path, mat) {
if is_ignored {
return true;
@@ -264,6 +258,7 @@ impl Ignore {
// If this path is whitelisted by an ignore, then
// fallthrough and let the file type matcher have a
// say.
+ whitelisted = true;
break;
}
}
@@ -271,7 +266,14 @@ impl Ignore {
}
let mat = self.types.matched(path, is_dir);
if let Some(is_ignored) = self.ignore_match(path, mat) {
- return is_ignored;
+ if is_ignored {
+ return true;
+ }
+ whitelisted = true;
+ }
+ if !whitelisted && self.ignore_hidden && is_hidden(&path) {
+ debug!("{} ignored because it is hidden", path.display());
+ return true;
}
false
}
diff --git a/src/pathutil.rs b/src/pathutil.rs
index ba4b17bd..3a020fa6 100644
--- a/src/pathutil.rs
+++ b/src/pathutil.rs
@@ -98,3 +98,21 @@ pub fn is_hidden<P: AsRef<Path>>(path: P) -> bool {
false
}
}
+
+/// Returns true if this file path is just a file name. i.e., Its parent is
+/// the empty string.
+#[cfg(unix)]
+pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
+ use std::os::unix::ffi::OsStrExt;
+ use memchr::memchr;
+
+ let path = path.as_ref().as_os_str().as_bytes();
+ memchr(b'/', path).is_none()
+}
+
+/// Returns true if this file path is just a file name. i.e., Its parent is
+/// the empty string.
+#[cfg(not(unix))]
+pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
+ path.as_ref().parent().map(|p| p.is_empty()).unwrap_or(false)
+}
diff --git a/tests/tests.rs b/tests/tests.rs
index a937959b..85ca1164 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -694,6 +694,15 @@ clean!(regression_67, "test", ".", |wd: WorkDir, mut cmd: Command| {
assert_eq!(lines, path("dir/bar:test\n"));
});
+// See: https://github.com/BurntSushi/ripgrep/issues/90
+clean!(regression_90, "test", ".", |wd: WorkDir, mut cmd: Command| {
+ wd.create(".gitignore", "!.foo");
+ wd.create(".foo", "test");
+
+ let lines: String = wd.stdout(&mut cmd);
+ assert_eq!(lines, ".foo:test\n");
+});
+
// See: https://github.com/BurntSushi/ripgrep/issues/20
sherlock!(feature_20, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
cmd.arg("--no-filename");