1
0
mirror of https://github.com/BurntSushi/ripgrep.git synced 2025-04-24 17:12:16 +02:00

ignore: remove unused parameter

This commit is contained in:
Andrew Gallant 2019-08-28 20:21:34 -04:00
parent e14f9195e5
commit 5011dba2fd
No known key found for this signature in database
GPG Key ID: B2E3A4923F8B0D44
2 changed files with 373 additions and 389 deletions

View File

@ -14,13 +14,13 @@
// well. // well.
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::{OsString, OsStr}; use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use gitignore::{self, Gitignore, GitignoreBuilder}; use gitignore::{self, Gitignore, GitignoreBuilder};
use pathutil::{is_hidden, strip_prefix};
use overrides::{self, Override}; use overrides::{self, Override};
use pathutil::{is_hidden, strip_prefix};
use types::{self, Types}; use types::{self, Types};
use walk::DirEntry; use walk::DirEntry;
use {Error, Match, PartialErrorBuilder}; use {Error, Match, PartialErrorBuilder};
@ -152,10 +152,7 @@ impl Ignore {
/// ///
/// Note that this can only be called on an `Ignore` matcher with no /// Note that this can only be called on an `Ignore` matcher with no
/// parents (i.e., `is_root` returns `true`). This will panic otherwise. /// parents (i.e., `is_root` returns `true`). This will panic otherwise.
pub fn add_parents<P: AsRef<Path>>( pub fn add_parents<P: AsRef<Path>>(&self, path: P) -> (Ignore, Option<Error>) {
&self,
path: P,
) -> (Ignore, Option<Error>) {
if !self.0.opts.parents if !self.0.opts.parents
&& !self.0.opts.git_ignore && !self.0.opts.git_ignore
&& !self.0.opts.git_exclude && !self.0.opts.git_exclude
@ -197,12 +194,11 @@ impl Ignore {
errs.maybe_push(err); errs.maybe_push(err);
igtmp.is_absolute_parent = true; igtmp.is_absolute_parent = true;
igtmp.absolute_base = Some(absolute_base.clone()); igtmp.absolute_base = Some(absolute_base.clone());
igtmp.has_git = igtmp.has_git = if self.0.opts.git_ignore {
if self.0.opts.git_ignore { parent.join(".git").exists()
parent.join(".git").exists() } else {
} else { false
false };
};
ig = Ignore(Arc::new(igtmp)); ig = Ignore(Arc::new(igtmp));
compiled.insert(parent.as_os_str().to_os_string(), ig.clone()); compiled.insert(parent.as_os_str().to_os_string(), ig.clone());
} }
@ -217,10 +213,7 @@ impl Ignore {
/// returned if it exists. /// returned if it exists.
/// ///
/// Note that all I/O errors are completely ignored. /// Note that all I/O errors are completely ignored.
pub fn add_child<P: AsRef<Path>>( pub fn add_child<P: AsRef<Path>>(&self, dir: P) -> (Ignore, Option<Error>) {
&self,
dir: P,
) -> (Ignore, Option<Error>) {
let (ig, err) = self.add_child_path(dir.as_ref()); let (ig, err) = self.add_child_path(dir.as_ref());
(Ignore(Arc::new(ig)), err) (Ignore(Arc::new(ig)), err)
} }
@ -228,64 +221,49 @@ impl Ignore {
/// Like add_child, but takes a full path and returns an IgnoreInner. /// Like add_child, but takes a full path and returns an IgnoreInner.
fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option<Error>) { fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option<Error>) {
let mut errs = PartialErrorBuilder::default(); let mut errs = PartialErrorBuilder::default();
let custom_ig_matcher = let custom_ig_matcher = if self.0.custom_ignore_filenames.is_empty() {
if self.0.custom_ignore_filenames.is_empty() { Gitignore::empty()
Gitignore::empty() } else {
} else { let (m, err) = create_gitignore(
let (m, err) = &dir,
create_gitignore( &self.0.custom_ignore_filenames,
&dir, self.0.opts.ignore_case_insensitive,
&self.0.custom_ignore_filenames, );
self.0.opts.ignore_case_insensitive, errs.maybe_push(err);
); m
errs.maybe_push(err); };
m let ig_matcher = if !self.0.opts.ignore {
}; Gitignore::empty()
let ig_matcher = } else {
if !self.0.opts.ignore { let (m, err) =
Gitignore::empty() create_gitignore(&dir, &[".ignore"], self.0.opts.ignore_case_insensitive);
} else { errs.maybe_push(err);
let (m, err) = m
create_gitignore( };
&dir, let gi_matcher = if !self.0.opts.git_ignore {
&[".ignore"], Gitignore::empty()
self.0.opts.ignore_case_insensitive, } else {
); let (m, err) =
errs.maybe_push(err); create_gitignore(&dir, &[".gitignore"], self.0.opts.ignore_case_insensitive);
m errs.maybe_push(err);
}; m
let gi_matcher = };
if !self.0.opts.git_ignore { let gi_exclude_matcher = if !self.0.opts.git_exclude {
Gitignore::empty() Gitignore::empty()
} else { } else {
let (m, err) = let (m, err) = create_gitignore(
create_gitignore( &dir,
&dir, &[".git/info/exclude"],
&[".gitignore"], self.0.opts.ignore_case_insensitive,
self.0.opts.ignore_case_insensitive, );
); errs.maybe_push(err);
errs.maybe_push(err); m
m };
}; let has_git = if self.0.opts.git_ignore {
let gi_exclude_matcher = dir.join(".git").exists()
if !self.0.opts.git_exclude { } else {
Gitignore::empty() false
} else { };
let (m, err) =
create_gitignore(
&dir,
&[".git/info/exclude"],
self.0.opts.ignore_case_insensitive,
);
errs.maybe_push(err);
m
};
let has_git =
if self.0.opts.git_ignore {
dir.join(".git").exists()
} else {
false
};
let ig = IgnoreInner { let ig = IgnoreInner {
compiled: self.0.compiled.clone(), compiled: self.0.compiled.clone(),
dir: dir.to_path_buf(), dir: dir.to_path_buf(),
@ -313,16 +291,16 @@ impl Ignore {
let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty(); let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty();
let has_explicit_ignores = !self.0.explicit_ignores.is_empty(); let has_explicit_ignores = !self.0.explicit_ignores.is_empty();
opts.ignore || opts.git_global || opts.git_ignore opts.ignore
|| opts.git_exclude || has_custom_ignore_files || opts.git_global
|| has_explicit_ignores || opts.git_ignore
|| opts.git_exclude
|| has_custom_ignore_files
|| has_explicit_ignores
} }
/// Like `matched`, but works with a directory entry instead. /// Like `matched`, but works with a directory entry instead.
pub fn matched_dir_entry<'a>( pub fn matched_dir_entry<'a>(&'a self, dent: &DirEntry) -> Match<IgnoreMatch<'a>> {
&'a self,
dent: &DirEntry,
) -> Match<IgnoreMatch<'a>> {
let m = self.matched(dent.path(), dent.is_dir()); let m = self.matched(dent.path(), dent.is_dir());
if m.is_none() && self.0.opts.hidden && is_hidden(dent) { if m.is_none() && self.0.opts.hidden && is_hidden(dent) {
return Match::Ignore(IgnoreMatch::hidden()); return Match::Ignore(IgnoreMatch::hidden());
@ -334,11 +312,7 @@ impl Ignore {
/// ignored or not. /// ignored or not.
/// ///
/// The match contains information about its origin. /// The match contains information about its origin.
fn matched<'a, P: AsRef<Path>>( fn matched<'a, P: AsRef<Path>>(&'a self, path: P, is_dir: bool) -> Match<IgnoreMatch<'a>> {
&'a self,
path: P,
is_dir: bool,
) -> Match<IgnoreMatch<'a>> {
// We need to be careful with our path. If it has a leading ./, then // We need to be careful with our path. If it has a leading ./, then
// strip it because it causes nothing but trouble. // strip it because it causes nothing but trouble.
let mut path = path.as_ref(); let mut path = path.as_ref();
@ -350,9 +324,11 @@ impl Ignore {
// return that result immediately. Overrides have the highest // return that result immediately. Overrides have the highest
// precedence. // precedence.
if !self.0.overrides.is_empty() { if !self.0.overrides.is_empty() {
let mat = let mat = self
self.0.overrides.matched(path, is_dir) .0
.map(IgnoreMatch::overrides); .overrides
.matched(path, is_dir)
.map(IgnoreMatch::overrides);
if !mat.is_none() { if !mat.is_none() {
return mat; return mat;
} }
@ -367,8 +343,7 @@ impl Ignore {
} }
} }
if !self.0.types.is_empty() { if !self.0.types.is_empty() {
let mat = let mat = self.0.types.matched(path, is_dir).map(IgnoreMatch::types);
self.0.types.matched(path, is_dir).map(IgnoreMatch::types);
if mat.is_ignore() { if mat.is_ignore() {
return mat; return mat;
} else if mat.is_whitelist() { } else if mat.is_whitelist() {
@ -380,61 +355,70 @@ impl Ignore {
/// Performs matching only on the ignore files for this directory and /// Performs matching only on the ignore files for this directory and
/// all parent directories. /// all parent directories.
fn matched_ignore<'a>( fn matched_ignore<'a>(&'a self, path: &Path, is_dir: bool) -> Match<IgnoreMatch<'a>> {
&'a self, let (mut m_custom_ignore, mut m_ignore, mut m_gi, mut m_gi_exclude, mut m_explicit) = (
path: &Path, Match::None,
is_dir: bool, Match::None,
) -> Match<IgnoreMatch<'a>> { Match::None,
let (mut m_custom_ignore, mut m_ignore, mut m_gi, mut m_gi_exclude, mut m_explicit) = Match::None,
(Match::None, Match::None, Match::None, Match::None, Match::None); Match::None,
);
let any_git = self.parents().any(|ig| ig.0.has_git); let any_git = self.parents().any(|ig| ig.0.has_git);
let mut saw_git = false; let mut saw_git = false;
for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) { for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) {
if m_custom_ignore.is_none() { if m_custom_ignore.is_none() {
m_custom_ignore = m_custom_ignore =
ig.0.custom_ignore_matcher.matched(path, is_dir) ig.0.custom_ignore_matcher
.map(IgnoreMatch::gitignore); .matched(path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if m_ignore.is_none() { if m_ignore.is_none() {
m_ignore = m_ignore =
ig.0.ignore_matcher.matched(path, is_dir) ig.0.ignore_matcher
.map(IgnoreMatch::gitignore); .matched(path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if any_git && !saw_git && m_gi.is_none() { if any_git && !saw_git && m_gi.is_none() {
m_gi = m_gi =
ig.0.git_ignore_matcher.matched(path, is_dir) ig.0.git_ignore_matcher
.map(IgnoreMatch::gitignore); .matched(path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if any_git && !saw_git && m_gi_exclude.is_none() { if any_git && !saw_git && m_gi_exclude.is_none() {
m_gi_exclude = m_gi_exclude =
ig.0.git_exclude_matcher.matched(path, is_dir) ig.0.git_exclude_matcher
.map(IgnoreMatch::gitignore); .matched(path, is_dir)
.map(IgnoreMatch::gitignore);
} }
saw_git = saw_git || ig.0.has_git; saw_git = saw_git || ig.0.has_git;
} }
if self.0.opts.parents { if self.0.opts.parents {
if let Some(abs_parent_path) = self.absolute_base() { if let Some(abs_parent_path) = self.absolute_base() {
let path = abs_parent_path.join(path); let path = abs_parent_path.join(path);
for ig in self.parents().skip_while(|ig|!ig.0.is_absolute_parent) { for ig in self.parents().skip_while(|ig| !ig.0.is_absolute_parent) {
if m_custom_ignore.is_none() { if m_custom_ignore.is_none() {
m_custom_ignore = m_custom_ignore =
ig.0.custom_ignore_matcher.matched(&path, is_dir) ig.0.custom_ignore_matcher
.map(IgnoreMatch::gitignore); .matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if m_ignore.is_none() { if m_ignore.is_none() {
m_ignore = m_ignore =
ig.0.ignore_matcher.matched(&path, is_dir) ig.0.ignore_matcher
.map(IgnoreMatch::gitignore); .matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if any_git && !saw_git && m_gi.is_none() { if any_git && !saw_git && m_gi.is_none() {
m_gi = m_gi =
ig.0.git_ignore_matcher.matched(&path, is_dir) ig.0.git_ignore_matcher
.map(IgnoreMatch::gitignore); .matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if any_git && !saw_git && m_gi_exclude.is_none() { if any_git && !saw_git && m_gi_exclude.is_none() {
m_gi_exclude = m_gi_exclude =
ig.0.git_exclude_matcher.matched(&path, is_dir) ig.0.git_exclude_matcher
.map(IgnoreMatch::gitignore); .matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
} }
saw_git = saw_git || ig.0.has_git; saw_git = saw_git || ig.0.has_git;
} }
@ -446,16 +430,21 @@ impl Ignore {
} }
m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore); m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore);
} }
let m_global = let m_global = if any_git {
if any_git { self.0
self.0.git_global_matcher .git_global_matcher
.matched(&path, is_dir) .matched(&path, is_dir)
.map(IgnoreMatch::gitignore) .map(IgnoreMatch::gitignore)
} else { } else {
Match::None Match::None
}; };
m_custom_ignore.or(m_ignore).or(m_gi).or(m_gi_exclude).or(m_global).or(m_explicit) m_custom_ignore
.or(m_ignore)
.or(m_gi)
.or(m_gi_exclude)
.or(m_global)
.or(m_explicit)
} }
/// Returns an iterator over parent ignore matchers, including this one. /// Returns an iterator over parent ignore matchers, including this one.
@ -535,20 +524,19 @@ impl IgnoreBuilder {
/// The matcher returned won't match anything until ignore rules from /// The matcher returned won't match anything until ignore rules from
/// directories are added to it. /// directories are added to it.
pub fn build(&self) -> Ignore { pub fn build(&self) -> Ignore {
let git_global_matcher = let git_global_matcher = if !self.opts.git_global {
if !self.opts.git_global { Gitignore::empty()
Gitignore::empty() } else {
} else { let mut builder = GitignoreBuilder::new("");
let mut builder = GitignoreBuilder::new(""); builder
builder .case_insensitive(self.opts.ignore_case_insensitive)
.case_insensitive(self.opts.ignore_case_insensitive) .unwrap();
.unwrap(); let (gi, err) = builder.build_global();
let (gi, err) = builder.build_global(); if let Some(err) = err {
if let Some(err) = err { debug!("{}", err);
debug!("{}", err); }
} gi
gi };
};
Ignore(Arc::new(IgnoreInner { Ignore(Arc::new(IgnoreInner {
compiled: Arc::new(RwLock::new(HashMap::new())), compiled: Arc::new(RwLock::new(HashMap::new())),
@ -604,9 +592,10 @@ impl IgnoreBuilder {
/// later names. /// later names.
pub fn add_custom_ignore_filename<S: AsRef<OsStr>>( pub fn add_custom_ignore_filename<S: AsRef<OsStr>>(
&mut self, &mut self,
file_name: S file_name: S,
) -> &mut IgnoreBuilder { ) -> &mut IgnoreBuilder {
self.custom_ignore_filenames.push(file_name.as_ref().to_os_string()); self.custom_ignore_filenames
.push(file_name.as_ref().to_os_string());
self self
} }
@ -678,10 +667,7 @@ impl IgnoreBuilder {
/// Process ignore files case insensitively /// Process ignore files case insensitively
/// ///
/// This is disabled by default. /// This is disabled by default.
pub fn ignore_case_insensitive( pub fn ignore_case_insensitive(&mut self, yes: bool) -> &mut IgnoreBuilder {
&mut self,
yes: bool,
) -> &mut IgnoreBuilder {
self.opts.ignore_case_insensitive = yes; self.opts.ignore_case_insensitive = yes;
self self
} }
@ -742,19 +728,21 @@ mod tests {
} }
} }
fn tmpdir(prefix: &str) -> TempDir { fn tmpdir() -> TempDir {
TempDir::new().unwrap() TempDir::new().unwrap()
} }
#[test] #[test]
fn explicit_ignore() { fn explicit_ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join("not-an-ignore"), "foo\n!bar"); wfile(td.path().join("not-an-ignore"), "foo\n!bar");
let (gi, err) = Gitignore::new(td.path().join("not-an-ignore")); let (gi, err) = Gitignore::new(td.path().join("not-an-ignore"));
assert!(err.is_none()); assert!(err.is_none());
let (ig, err) = IgnoreBuilder::new() let (ig, err) = IgnoreBuilder::new()
.add_ignore(gi).build().add_child(td.path()); .add_ignore(gi)
.build()
.add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
assert!(ig.matched("foo", false).is_ignore()); assert!(ig.matched("foo", false).is_ignore());
assert!(ig.matched("bar", false).is_whitelist()); assert!(ig.matched("bar", false).is_whitelist());
@ -763,7 +751,7 @@ mod tests {
#[test] #[test]
fn git_exclude() { fn git_exclude() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git/info")); mkdirp(td.path().join(".git/info"));
wfile(td.path().join(".git/info/exclude"), "foo\n!bar"); wfile(td.path().join(".git/info/exclude"), "foo\n!bar");
@ -776,7 +764,7 @@ mod tests {
#[test] #[test]
fn gitignore() { fn gitignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
wfile(td.path().join(".gitignore"), "foo\n!bar"); wfile(td.path().join(".gitignore"), "foo\n!bar");
@ -789,7 +777,7 @@ mod tests {
#[test] #[test]
fn gitignore_no_git() { fn gitignore_no_git() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "foo\n!bar"); wfile(td.path().join(".gitignore"), "foo\n!bar");
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
@ -801,7 +789,7 @@ mod tests {
#[test] #[test]
fn ignore() { fn ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".ignore"), "foo\n!bar"); wfile(td.path().join(".ignore"), "foo\n!bar");
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
@ -813,13 +801,14 @@ mod tests {
#[test] #[test]
fn custom_ignore() { fn custom_ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
let custom_ignore = ".customignore"; let custom_ignore = ".customignore";
wfile(td.path().join(custom_ignore), "foo\n!bar"); wfile(td.path().join(custom_ignore), "foo\n!bar");
let (ig, err) = IgnoreBuilder::new() let (ig, err) = IgnoreBuilder::new()
.add_custom_ignore_filename(custom_ignore) .add_custom_ignore_filename(custom_ignore)
.build().add_child(td.path()); .build()
.add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
assert!(ig.matched("foo", false).is_ignore()); assert!(ig.matched("foo", false).is_ignore());
assert!(ig.matched("bar", false).is_whitelist()); assert!(ig.matched("bar", false).is_whitelist());
@ -829,14 +818,15 @@ mod tests {
// Tests that a custom ignore file will override an .ignore. // Tests that a custom ignore file will override an .ignore.
#[test] #[test]
fn custom_ignore_over_ignore() { fn custom_ignore_over_ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
let custom_ignore = ".customignore"; let custom_ignore = ".customignore";
wfile(td.path().join(".ignore"), "foo"); wfile(td.path().join(".ignore"), "foo");
wfile(td.path().join(custom_ignore), "!foo"); wfile(td.path().join(custom_ignore), "!foo");
let (ig, err) = IgnoreBuilder::new() let (ig, err) = IgnoreBuilder::new()
.add_custom_ignore_filename(custom_ignore) .add_custom_ignore_filename(custom_ignore)
.build().add_child(td.path()); .build()
.add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
assert!(ig.matched("foo", false).is_whitelist()); assert!(ig.matched("foo", false).is_whitelist());
} }
@ -844,7 +834,7 @@ mod tests {
// Tests that earlier custom ignore files have lower precedence than later. // Tests that earlier custom ignore files have lower precedence than later.
#[test] #[test]
fn custom_ignore_precedence() { fn custom_ignore_precedence() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
let custom_ignore1 = ".customignore1"; let custom_ignore1 = ".customignore1";
let custom_ignore2 = ".customignore2"; let custom_ignore2 = ".customignore2";
wfile(td.path().join(custom_ignore1), "foo"); wfile(td.path().join(custom_ignore1), "foo");
@ -853,7 +843,8 @@ mod tests {
let (ig, err) = IgnoreBuilder::new() let (ig, err) = IgnoreBuilder::new()
.add_custom_ignore_filename(custom_ignore1) .add_custom_ignore_filename(custom_ignore1)
.add_custom_ignore_filename(custom_ignore2) .add_custom_ignore_filename(custom_ignore2)
.build().add_child(td.path()); .build()
.add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
assert!(ig.matched("foo", false).is_whitelist()); assert!(ig.matched("foo", false).is_whitelist());
} }
@ -861,7 +852,7 @@ mod tests {
// Tests that an .ignore will override a .gitignore. // Tests that an .ignore will override a .gitignore.
#[test] #[test]
fn ignore_over_gitignore() { fn ignore_over_gitignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
wfile(td.path().join(".ignore"), "!foo"); wfile(td.path().join(".ignore"), "!foo");
@ -873,7 +864,7 @@ mod tests {
// Tests that exclude has lower precedent than both .ignore and .gitignore. // Tests that exclude has lower precedent than both .ignore and .gitignore.
#[test] #[test]
fn exclude_lowest() { fn exclude_lowest() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "!foo"); wfile(td.path().join(".gitignore"), "!foo");
wfile(td.path().join(".ignore"), "!bar"); wfile(td.path().join(".ignore"), "!bar");
mkdirp(td.path().join(".git/info")); mkdirp(td.path().join(".git/info"));
@ -888,7 +879,7 @@ mod tests {
#[test] #[test]
fn errored() { fn errored() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "{foo"); wfile(td.path().join(".gitignore"), "{foo");
let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
@ -897,7 +888,7 @@ mod tests {
#[test] #[test]
fn errored_both() { fn errored_both() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "{foo"); wfile(td.path().join(".gitignore"), "{foo");
wfile(td.path().join(".ignore"), "{bar"); wfile(td.path().join(".ignore"), "{bar");
@ -907,7 +898,7 @@ mod tests {
#[test] #[test]
fn errored_partial() { fn errored_partial() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
wfile(td.path().join(".gitignore"), "{foo\nbar"); wfile(td.path().join(".gitignore"), "{foo\nbar");
@ -918,7 +909,7 @@ mod tests {
#[test] #[test]
fn errored_partial_and_ignore() { fn errored_partial_and_ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "{foo\nbar"); wfile(td.path().join(".gitignore"), "{foo\nbar");
wfile(td.path().join(".ignore"), "!bar"); wfile(td.path().join(".ignore"), "!bar");
@ -929,7 +920,7 @@ mod tests {
#[test] #[test]
fn not_present_empty() { fn not_present_empty() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
@ -939,7 +930,7 @@ mod tests {
fn stops_at_git_dir() { fn stops_at_git_dir() {
// This tests that .gitignore files beyond a .git barrier aren't // This tests that .gitignore files beyond a .git barrier aren't
// matched, but .ignore files are. // matched, but .ignore files are.
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("foo/.git")); mkdirp(td.path().join("foo/.git"));
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
@ -960,7 +951,7 @@ mod tests {
#[test] #[test]
fn absolute_parent() { fn absolute_parent() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("foo")); mkdirp(td.path().join("foo"));
wfile(td.path().join(".gitignore"), "bar"); wfile(td.path().join(".gitignore"), "bar");
@ -983,7 +974,7 @@ mod tests {
#[test] #[test]
fn absolute_parent_anchored() { fn absolute_parent_anchored() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("src/llvm")); mkdirp(td.path().join("src/llvm"));
wfile(td.path().join(".gitignore"), "/llvm/\nfoo"); wfile(td.path().join(".gitignore"), "/llvm/\nfoo");

View File

@ -4,8 +4,8 @@ use std::fmt;
use std::fs::{self, FileType, Metadata}; use std::fs::{self, FileType, Metadata};
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use std::vec; use std::vec;
@ -182,14 +182,14 @@ impl DirEntryInner {
match *self { match *self {
Stdin => { Stdin => {
let err = Error::Io(io::Error::new( let err = Error::Io(io::Error::new(
io::ErrorKind::Other, "<stdin> has no metadata")); io::ErrorKind::Other,
"<stdin> has no metadata",
));
Err(err.with_path("<stdin>")) Err(err.with_path("<stdin>"))
} }
Walkdir(ref x) => { Walkdir(ref x) => x
x.metadata().map_err(|err| { .metadata()
Error::Io(io::Error::from(err)).with_path(x.path()) .map_err(|err| Error::Io(io::Error::from(err)).with_path(x.path())),
})
}
Raw(ref x) => x.metadata(), Raw(ref x) => x.metadata(),
} }
} }
@ -223,8 +223,8 @@ impl DirEntryInner {
#[cfg(unix)] #[cfg(unix)]
fn ino(&self) -> Option<u64> { fn ino(&self) -> Option<u64> {
use walkdir::DirEntryExt;
use self::DirEntryInner::*; use self::DirEntryInner::*;
use walkdir::DirEntryExt;
match *self { match *self {
Stdin => None, Stdin => None,
Walkdir(ref x) => Some(x.ino()), Walkdir(ref x) => Some(x.ino()),
@ -297,7 +297,8 @@ impl DirEntryRaw {
fs::metadata(&self.path) fs::metadata(&self.path)
} else { } else {
Ok(self.metadata.clone()) Ok(self.metadata.clone())
}.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path)) }
.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path))
} }
#[cfg(not(windows))] #[cfg(not(windows))]
@ -306,7 +307,8 @@ impl DirEntryRaw {
fs::metadata(&self.path) fs::metadata(&self.path)
} else { } else {
fs::symlink_metadata(&self.path) fs::symlink_metadata(&self.path)
}.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path)) }
.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path))
} }
fn file_type(&self) -> FileType { fn file_type(&self) -> FileType {
@ -314,7 +316,9 @@ impl DirEntryRaw {
} }
fn file_name(&self) -> &OsStr { fn file_name(&self) -> &OsStr {
self.path.file_name().unwrap_or_else(|| self.path.as_os_str()) self.path
.file_name()
.unwrap_or_else(|| self.path.as_os_str())
} }
fn depth(&self) -> usize { fn depth(&self) -> usize {
@ -326,10 +330,7 @@ impl DirEntryRaw {
self.ino self.ino
} }
fn from_entry( fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntryRaw, Error> {
depth: usize,
ent: &fs::DirEntry,
) -> Result<DirEntryRaw, Error> {
let ty = ent.file_type().map_err(|err| { let ty = ent.file_type().map_err(|err| {
let err = Error::Io(io::Error::from(err)).with_path(ent.path()); let err = Error::Io(io::Error::from(err)).with_path(ent.path());
Error::WithDepth { Error::WithDepth {
@ -387,18 +388,14 @@ impl DirEntryRaw {
ty: fs::FileType, ty: fs::FileType,
) -> Result<DirEntryRaw, Error> { ) -> Result<DirEntryRaw, Error> {
Err(Error::Io(io::Error::new( Err(Error::Io(io::Error::new(
io::ErrorKind::Other, "unsupported platform"))) io::ErrorKind::Other,
"unsupported platform",
)))
} }
#[cfg(windows)] #[cfg(windows)]
fn from_path( fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result<DirEntryRaw, Error> {
depth: usize, let md = fs::metadata(&pb).map_err(|err| Error::Io(err).with_path(&pb))?;
pb: PathBuf,
link: bool,
) -> Result<DirEntryRaw, Error> {
let md = fs::metadata(&pb).map_err(|err| {
Error::Io(err).with_path(&pb)
})?;
Ok(DirEntryRaw { Ok(DirEntryRaw {
path: pb, path: pb,
ty: md.file_type(), ty: md.file_type(),
@ -409,16 +406,10 @@ impl DirEntryRaw {
} }
#[cfg(unix)] #[cfg(unix)]
fn from_path( fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result<DirEntryRaw, Error> {
depth: usize,
pb: PathBuf,
link: bool,
) -> Result<DirEntryRaw, Error> {
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
let md = fs::metadata(&pb).map_err(|err| { let md = fs::metadata(&pb).map_err(|err| Error::Io(err).with_path(&pb))?;
Error::Io(err).with_path(&pb)
})?;
Ok(DirEntryRaw { Ok(DirEntryRaw {
path: pb, path: pb,
ty: md.file_type(), ty: md.file_type(),
@ -430,13 +421,11 @@ impl DirEntryRaw {
// Placeholder implementation to allow compiling on non-standard platforms (e.g. wasm32). // Placeholder implementation to allow compiling on non-standard platforms (e.g. wasm32).
#[cfg(not(any(windows, unix)))] #[cfg(not(any(windows, unix)))]
fn from_path( fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result<DirEntryRaw, Error> {
depth: usize,
pb: PathBuf,
link: bool,
) -> Result<DirEntryRaw, Error> {
Err(Error::Io(io::Error::new( Err(Error::Io(io::Error::new(
io::ErrorKind::Other, "unsupported platform"))) io::ErrorKind::Other,
"unsupported platform",
)))
} }
} }
@ -547,33 +536,34 @@ impl WalkBuilder {
let follow_links = self.follow_links; let follow_links = self.follow_links;
let max_depth = self.max_depth; let max_depth = self.max_depth;
let sorter = self.sorter.clone(); let sorter = self.sorter.clone();
let its = self.paths.iter().map(move |p| { let its = self
if p == Path::new("-") { .paths
(p.to_path_buf(), None) .iter()
} else { .map(move |p| {
let mut wd = WalkDir::new(p); if p == Path::new("-") {
wd = wd.follow_links(follow_links || p.is_file()); (p.to_path_buf(), None)
wd = wd.same_file_system(self.same_file_system); } else {
if let Some(max_depth) = max_depth { let mut wd = WalkDir::new(p);
wd = wd.max_depth(max_depth); wd = wd.follow_links(follow_links || p.is_file());
} wd = wd.same_file_system(self.same_file_system);
if let Some(ref sorter) = sorter { if let Some(max_depth) = max_depth {
match sorter.clone() { wd = wd.max_depth(max_depth);
Sorter::ByName(cmp) => { }
wd = wd.sort_by(move |a, b| { if let Some(ref sorter) = sorter {
cmp(a.file_name(), b.file_name()) match sorter.clone() {
}); Sorter::ByName(cmp) => {
} wd = wd.sort_by(move |a, b| cmp(a.file_name(), b.file_name()));
Sorter::ByPath(cmp) => { }
wd = wd.sort_by(move |a, b| { Sorter::ByPath(cmp) => {
cmp(a.path(), b.path()) wd = wd.sort_by(move |a, b| cmp(a.path(), b.path()));
}); }
} }
} }
(p.to_path_buf(), Some(WalkEventIter::from(wd)))
} }
(p.to_path_buf(), Some(WalkEventIter::from(wd))) })
} .collect::<Vec<_>>()
}).collect::<Vec<_>>().into_iter(); .into_iter();
let ig_root = self.ig_builder.build(); let ig_root = self.ig_builder.build();
Walk { Walk {
its: its, its: its,
@ -657,8 +647,12 @@ impl WalkBuilder {
let mut errs = PartialErrorBuilder::default(); let mut errs = PartialErrorBuilder::default();
errs.maybe_push(builder.add(path)); errs.maybe_push(builder.add(path));
match builder.build() { match builder.build() {
Ok(gi) => { self.ig_builder.add_ignore(gi); } Ok(gi) => {
Err(err) => { errs.push(err); } self.ig_builder.add_ignore(gi);
}
Err(err) => {
errs.push(err);
}
} }
errs.into_error_option() errs.into_error_option()
} }
@ -671,7 +665,7 @@ impl WalkBuilder {
/// later names. /// later names.
pub fn add_custom_ignore_filename<S: AsRef<OsStr>>( pub fn add_custom_ignore_filename<S: AsRef<OsStr>>(
&mut self, &mut self,
file_name: S file_name: S,
) -> &mut WalkBuilder { ) -> &mut WalkBuilder {
self.ig_builder.add_custom_ignore_filename(file_name); self.ig_builder.add_custom_ignore_filename(file_name);
self self
@ -808,11 +802,9 @@ impl WalkBuilder {
/// by `sort_by_file_name`. /// by `sort_by_file_name`.
/// ///
/// Note that this is not used in the parallel iterator. /// Note that this is not used in the parallel iterator.
pub fn sort_by_file_path<F>( pub fn sort_by_file_path<F>(&mut self, cmp: F) -> &mut WalkBuilder
&mut self, where
cmp: F, F: Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static,
) -> &mut WalkBuilder
where F: Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static
{ {
self.sorter = Some(Sorter::ByPath(Arc::new(cmp))); self.sorter = Some(Sorter::ByPath(Arc::new(cmp)));
self self
@ -830,7 +822,8 @@ impl WalkBuilder {
/// ///
/// Note that this is not used in the parallel iterator. /// Note that this is not used in the parallel iterator.
pub fn sort_by_file_name<F>(&mut self, cmp: F) -> &mut WalkBuilder pub fn sort_by_file_name<F>(&mut self, cmp: F) -> &mut WalkBuilder
where F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static where
F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static,
{ {
self.sorter = Some(Sorter::ByName(Arc::new(cmp))); self.sorter = Some(Sorter::ByName(Arc::new(cmp)));
self self
@ -1011,7 +1004,11 @@ enum WalkEvent {
impl From<WalkDir> for WalkEventIter { impl From<WalkDir> for WalkEventIter {
fn from(it: WalkDir) -> WalkEventIter { fn from(it: WalkDir) -> WalkEventIter {
WalkEventIter { depth: 0, it: it.into_iter(), next: None } WalkEventIter {
depth: 0,
it: it.into_iter(),
next: None,
}
} }
} }
@ -1094,10 +1091,10 @@ impl WalkParallel {
/// Execute the parallel recursive directory iterator. `mkf` is called /// Execute the parallel recursive directory iterator. `mkf` is called
/// for each thread used for iteration. The function produced by `mkf` /// for each thread used for iteration. The function produced by `mkf`
/// is then in turn called for each visited file path. /// is then in turn called for each visited file path.
pub fn run<F>( pub fn run<F>(self, mut mkf: F)
self, where
mut mkf: F, F: FnMut() -> Box<dyn FnMut(Result<DirEntry, Error>) -> WalkState + Send + 'static>,
) where F: FnMut() -> Box<dyn FnMut(Result<DirEntry, Error>) -> WalkState + Send + 'static> { {
let mut f = mkf(); let mut f = mkf();
let threads = self.threads(); let threads = self.threads();
// TODO: Figure out how to use a bounded channel here. With an // TODO: Figure out how to use a bounded channel here. With an
@ -1114,30 +1111,16 @@ impl WalkParallel {
// Note that we only send directories. For files, we send to them the // Note that we only send directories. For files, we send to them the
// callback directly. // callback directly.
for path in self.paths { for path in self.paths {
let (dent, root_device) = let (dent, root_device) = if path == Path::new("-") {
if path == Path::new("-") { (DirEntry::new_stdin(), None)
(DirEntry::new_stdin(), None) } else {
let root_device = if !self.same_file_system {
None
} else { } else {
let root_device = match device_num(&path) {
if !self.same_file_system { Ok(root_device) => Some(root_device),
None
} else {
match device_num(&path) {
Ok(root_device) => Some(root_device),
Err(err) => {
let err = Error::Io(err).with_path(path);
if f(Err(err)).is_quit() {
return;
}
continue;
}
}
};
match DirEntryRaw::from_path(0, path, false) {
Ok(dent) => {
(DirEntry::new_raw(dent, None), root_device)
}
Err(err) => { Err(err) => {
let err = Error::Io(err).with_path(path);
if f(Err(err)).is_quit() { if f(Err(err)).is_quit() {
return; return;
} }
@ -1145,11 +1128,22 @@ impl WalkParallel {
} }
} }
}; };
match DirEntryRaw::from_path(0, path, false) {
Ok(dent) => (DirEntry::new_raw(dent, None), root_device),
Err(err) => {
if f(Err(err)).is_quit() {
return;
}
continue;
}
}
};
tx.send(Message::Work(Work { tx.send(Message::Work(Work {
dent: dent, dent: dent,
ignore: self.ig_root.clone(), ignore: self.ig_root.clone(),
root_device: root_device, root_device: root_device,
})).unwrap(); }))
.unwrap();
any_work = true; any_work = true;
} }
// ... but there's no need to start workers if we don't need them. // ... but there's no need to start workers if we don't need them.
@ -1341,22 +1335,21 @@ impl Worker {
continue; continue;
} }
}; };
let descend = let descend = if let Some(root_device) = work.root_device {
if let Some(root_device) = work.root_device { match is_same_file_system(root_device, work.dent.path()) {
match is_same_file_system(root_device, work.dent.path()) { Ok(true) => true,
Ok(true) => true, Ok(false) => false,
Ok(false) => false, Err(err) => {
Err(err) => { if (self.f)(Err(err)).is_quit() {
if (self.f)(Err(err)).is_quit() { self.quit_now();
self.quit_now(); return;
return;
}
false
} }
false
} }
} else { }
true } else {
}; true
};
let depth = work.dent.depth(); let depth = work.dent.depth();
match (self.f)(Ok(work.dent)) { match (self.f)(Ok(work.dent)) {
@ -1374,12 +1367,7 @@ impl Worker {
continue; continue;
} }
for result in readdir { for result in readdir {
let state = self.run_one( let state = self.run_one(&work.ignore, depth + 1, work.root_device, result);
&work.ignore,
depth + 1,
work.root_device,
result,
);
if state.is_quit() { if state.is_quit() {
self.quit_now(); self.quit_now();
return; return;
@ -1444,23 +1432,24 @@ impl Worker {
} }
} }
let should_skip_path = should_skip_entry(ig, &dent); let should_skip_path = should_skip_entry(ig, &dent);
let should_skip_filesize = let should_skip_filesize = if self.max_filesize.is_some() && !dent.is_dir() {
if self.max_filesize.is_some() && !dent.is_dir() { skip_filesize(
skip_filesize( self.max_filesize.unwrap(),
self.max_filesize.unwrap(), dent.path(),
dent.path(), &dent.metadata().ok(),
&dent.metadata().ok(), )
) } else {
} else { false
false };
};
if !should_skip_path && !should_skip_filesize { if !should_skip_path && !should_skip_filesize {
self.tx.send(Message::Work(Work { self.tx
dent: dent, .send(Message::Work(Work {
ignore: ig.clone(), dent: dent,
root_device: root_device, ignore: ig.clone(),
})).unwrap(); root_device: root_device,
}))
.unwrap();
} }
WalkState::Continue WalkState::Continue
} }
@ -1590,17 +1579,25 @@ fn check_symlink_loop(
child_depth: usize, child_depth: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
let hchild = Handle::from_path(child_path).map_err(|err| { let hchild = Handle::from_path(child_path).map_err(|err| {
Error::from(err).with_path(child_path).with_depth(child_depth) Error::from(err)
.with_path(child_path)
.with_depth(child_depth)
})?; })?;
for ig in ig_parent.parents().take_while(|ig| !ig.is_absolute_parent()) { for ig in ig_parent
.parents()
.take_while(|ig| !ig.is_absolute_parent())
{
let h = Handle::from_path(ig.path()).map_err(|err| { let h = Handle::from_path(ig.path()).map_err(|err| {
Error::from(err).with_path(child_path).with_depth(child_depth) Error::from(err)
.with_path(child_path)
.with_depth(child_depth)
})?; })?;
if hchild == h { if hchild == h {
return Err(Error::Loop { return Err(Error::Loop {
ancestor: ig.path().to_path_buf(), ancestor: ig.path().to_path_buf(),
child: child_path.to_path_buf(), child: child_path.to_path_buf(),
}.with_depth(child_depth)); }
.with_depth(child_depth));
} }
} }
Ok(()) Ok(())
@ -1608,14 +1605,10 @@ fn check_symlink_loop(
// Before calling this function, make sure that you ensure that is really // Before calling this function, make sure that you ensure that is really
// necessary as the arguments imply a file stat. // necessary as the arguments imply a file stat.
fn skip_filesize( fn skip_filesize(max_filesize: u64, path: &Path, ent: &Option<Metadata>) -> bool {
max_filesize: u64,
path: &Path,
ent: &Option<Metadata>
) -> bool {
let filesize = match *ent { let filesize = match *ent {
Some(ref md) => Some(md.len()), Some(ref md) => Some(md.len()),
None => None None => None,
}; };
if let Some(fs) = filesize { if let Some(fs) = filesize {
@ -1630,10 +1623,7 @@ fn skip_filesize(
} }
} }
fn should_skip_entry( fn should_skip_entry(ig: &Ignore, dent: &DirEntry) -> bool {
ig: &Ignore,
dent: &DirEntry,
) -> bool {
let m = ig.matched_dir_entry(dent); let m = ig.matched_dir_entry(dent);
if m.is_ignore() { if m.is_ignore() {
debug!("ignoring {}: {:?}", dent.path().display(), m); debug!("ignoring {}: {:?}", dent.path().display(), m);
@ -1695,28 +1685,27 @@ fn path_equals(dent: &DirEntry, handle: &Handle) -> Result<bool, Error> {
/// Returns true if and only if the given path is on the same device as the /// Returns true if and only if the given path is on the same device as the
/// given root device. /// given root device.
fn is_same_file_system(root_device: u64, path: &Path) -> Result<bool, Error> { fn is_same_file_system(root_device: u64, path: &Path) -> Result<bool, Error> {
let dent_device = device_num(path) let dent_device = device_num(path).map_err(|err| Error::Io(err).with_path(path))?;
.map_err(|err| Error::Io(err).with_path(path))?;
Ok(root_device == dent_device) Ok(root_device == dent_device)
} }
#[cfg(unix)] #[cfg(unix)]
fn device_num<P: AsRef<Path>>(path: P)-> io::Result<u64> { fn device_num<P: AsRef<Path>>(path: P) -> io::Result<u64> {
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
path.as_ref().metadata().map(|md| md.dev()) path.as_ref().metadata().map(|md| md.dev())
} }
#[cfg(windows)] #[cfg(windows)]
fn device_num<P: AsRef<Path>>(path: P) -> io::Result<u64> { fn device_num<P: AsRef<Path>>(path: P) -> io::Result<u64> {
use winapi_util::{Handle, file}; use winapi_util::{file, Handle};
let h = Handle::from_path_any(path)?; let h = Handle::from_path_any(path)?;
file::information(h).map(|info| info.volume_serial_number()) file::information(h).map(|info| info.volume_serial_number())
} }
#[cfg(not(any(unix, windows)))] #[cfg(not(any(unix, windows)))]
fn device_num<P: AsRef<Path>>(_: P)-> io::Result<u64> { fn device_num<P: AsRef<Path>>(_: P) -> io::Result<u64> {
Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
"walkdir: same_file_system option not supported on this platform", "walkdir: same_file_system option not supported on this platform",
@ -1730,8 +1719,8 @@ mod tests {
use std::path::Path; use std::path::Path;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use tests::TempDir;
use super::{DirEntry, WalkBuilder, WalkState}; use super::{DirEntry, WalkBuilder, WalkState};
use tests::TempDir;
fn wfile<P: AsRef<Path>>(path: P, contents: &str) { fn wfile<P: AsRef<Path>>(path: P, contents: &str) {
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
@ -1778,10 +1767,7 @@ mod tests {
paths paths
} }
fn walk_collect_parallel( fn walk_collect_parallel(prefix: &Path, builder: &WalkBuilder) -> Vec<String> {
prefix: &Path,
builder: &WalkBuilder,
) -> Vec<String> {
let mut paths = vec![]; let mut paths = vec![];
for dent in walk_collect_entries_parallel(builder) { for dent in walk_collect_entries_parallel(builder) {
let path = dent.path().strip_prefix(prefix).unwrap(); let path = dent.path().strip_prefix(prefix).unwrap();
@ -1816,15 +1802,11 @@ mod tests {
paths paths
} }
fn tmpdir(prefix: &str) -> TempDir { fn tmpdir() -> TempDir {
TempDir::new().unwrap() TempDir::new().unwrap()
} }
fn assert_paths( fn assert_paths(prefix: &Path, builder: &WalkBuilder, expected: &[&str]) {
prefix: &Path,
builder: &WalkBuilder,
expected: &[&str],
) {
let got = walk_collect(prefix, builder); let got = walk_collect(prefix, builder);
assert_eq!(got, mkpaths(expected), "single threaded"); assert_eq!(got, mkpaths(expected), "single threaded");
let got = walk_collect_parallel(prefix, builder); let got = walk_collect_parallel(prefix, builder);
@ -1833,20 +1815,22 @@ mod tests {
#[test] #[test]
fn no_ignores() { fn no_ignores() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b/c")); mkdirp(td.path().join("a/b/c"));
mkdirp(td.path().join("x/y")); mkdirp(td.path().join("x/y"));
wfile(td.path().join("a/b/foo"), ""); wfile(td.path().join("a/b/foo"), "");
wfile(td.path().join("x/y/foo"), ""); wfile(td.path().join("x/y/foo"), "");
assert_paths(td.path(), &WalkBuilder::new(td.path()), &[ assert_paths(
"x", "x/y", "x/y/foo", "a", "a/b", "a/b/foo", "a/b/c", td.path(),
]); &WalkBuilder::new(td.path()),
&["x", "x/y", "x/y/foo", "a", "a/b", "a/b/foo", "a/b/c"],
);
} }
#[test] #[test]
fn custom_ignore() { fn custom_ignore() {
let td = tmpdir("walk-test-"); let td = tmpdir();
let custom_ignore = ".customignore"; let custom_ignore = ".customignore";
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(td.path().join(custom_ignore), "foo"); wfile(td.path().join(custom_ignore), "foo");
@ -1862,7 +1846,7 @@ mod tests {
#[test] #[test]
fn custom_ignore_exclusive_use() { fn custom_ignore_exclusive_use() {
let td = tmpdir("walk-test-"); let td = tmpdir();
let custom_ignore = ".customignore"; let custom_ignore = ".customignore";
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(td.path().join(custom_ignore), "foo"); wfile(td.path().join(custom_ignore), "foo");
@ -1882,7 +1866,7 @@ mod tests {
#[test] #[test]
fn gitignore() { fn gitignore() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
@ -1891,14 +1875,16 @@ mod tests {
wfile(td.path().join("bar"), ""); wfile(td.path().join("bar"), "");
wfile(td.path().join("a/bar"), ""); wfile(td.path().join("a/bar"), "");
assert_paths(td.path(), &WalkBuilder::new(td.path()), &[ assert_paths(
"bar", "a", "a/bar", td.path(),
]); &WalkBuilder::new(td.path()),
&["bar", "a", "a/bar"],
);
} }
#[test] #[test]
fn explicit_ignore() { fn explicit_ignore() {
let td = tmpdir("walk-test-"); let td = tmpdir();
let igpath = td.path().join(".not-an-ignore"); let igpath = td.path().join(".not-an-ignore");
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(&igpath, "foo"); wfile(&igpath, "foo");
@ -1914,7 +1900,7 @@ mod tests {
#[test] #[test]
fn explicit_ignore_exclusive_use() { fn explicit_ignore_exclusive_use() {
let td = tmpdir("walk-test-"); let td = tmpdir();
let igpath = td.path().join(".not-an-ignore"); let igpath = td.path().join(".not-an-ignore");
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(&igpath, "foo"); wfile(&igpath, "foo");
@ -1926,13 +1912,16 @@ mod tests {
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
builder.standard_filters(false); builder.standard_filters(false);
assert!(builder.add_ignore(&igpath).is_none()); assert!(builder.add_ignore(&igpath).is_none());
assert_paths(td.path(), &builder, assert_paths(
&[".not-an-ignore", "bar", "a", "a/bar"]); td.path(),
&builder,
&[".not-an-ignore", "bar", "a", "a/bar"],
);
} }
#[test] #[test]
fn gitignore_parent() { fn gitignore_parent() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
@ -1945,7 +1934,7 @@ mod tests {
#[test] #[test]
fn max_depth() { fn max_depth() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b/c")); mkdirp(td.path().join("a/b/c"));
wfile(td.path().join("foo"), ""); wfile(td.path().join("foo"), "");
wfile(td.path().join("a/foo"), ""); wfile(td.path().join("a/foo"), "");
@ -1953,19 +1942,23 @@ mod tests {
wfile(td.path().join("a/b/c/foo"), ""); wfile(td.path().join("a/b/c/foo"), "");
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
assert_paths(td.path(), &builder, &[ assert_paths(
"a", "a/b", "a/b/c", "foo", "a/foo", "a/b/foo", "a/b/c/foo", td.path(),
]); &builder,
&["a", "a/b", "a/b/c", "foo", "a/foo", "a/b/foo", "a/b/c/foo"],
);
assert_paths(td.path(), builder.max_depth(Some(0)), &[]); assert_paths(td.path(), builder.max_depth(Some(0)), &[]);
assert_paths(td.path(), builder.max_depth(Some(1)), &["a", "foo"]); assert_paths(td.path(), builder.max_depth(Some(1)), &["a", "foo"]);
assert_paths(td.path(), builder.max_depth(Some(2)), &[ assert_paths(
"a", "a/b", "foo", "a/foo", td.path(),
]); builder.max_depth(Some(2)),
&["a", "a/b", "foo", "a/foo"],
);
} }
#[test] #[test]
fn max_filesize() { fn max_filesize() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b")); mkdirp(td.path().join("a/b"));
wfile_size(td.path().join("foo"), 0); wfile_size(td.path().join("foo"), 0);
wfile_size(td.path().join("bar"), 400); wfile_size(td.path().join("bar"), 400);
@ -1975,41 +1968,49 @@ mod tests {
wfile_size(td.path().join("a/baz"), 200); wfile_size(td.path().join("a/baz"), 200);
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
assert_paths(td.path(), &builder, &[ assert_paths(
"a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz", td.path(),
]); &builder,
assert_paths(td.path(), builder.max_filesize(Some(0)), &[ &["a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz"],
"a", "a/b", "foo" );
]); assert_paths(
assert_paths(td.path(), builder.max_filesize(Some(500)), &[ td.path(),
"a", "a/b", "foo", "bar", "a/bar", "a/baz" builder.max_filesize(Some(0)),
]); &["a", "a/b", "foo"],
assert_paths(td.path(), builder.max_filesize(Some(50000)), &[ );
"a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz", assert_paths(
]); td.path(),
builder.max_filesize(Some(500)),
&["a", "a/b", "foo", "bar", "a/bar", "a/baz"],
);
assert_paths(
td.path(),
builder.max_filesize(Some(50000)),
&["a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz"],
);
} }
#[cfg(unix)] // because symlinks on windows are weird #[cfg(unix)] // because symlinks on windows are weird
#[test] #[test]
fn symlinks() { fn symlinks() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b")); mkdirp(td.path().join("a/b"));
symlink(td.path().join("a/b"), td.path().join("z")); symlink(td.path().join("a/b"), td.path().join("z"));
wfile(td.path().join("a/b/foo"), ""); wfile(td.path().join("a/b/foo"), "");
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
assert_paths(td.path(), &builder, &[ assert_paths(td.path(), &builder, &["a", "a/b", "a/b/foo", "z"]);
"a", "a/b", "a/b/foo", "z", assert_paths(
]); td.path(),
assert_paths(td.path(), &builder.follow_links(true), &[ &builder.follow_links(true),
"a", "a/b", "a/b/foo", "z", "z/foo", &["a", "a/b", "a/b/foo", "z", "z/foo"],
]); );
} }
#[cfg(unix)] // because symlinks on windows are weird #[cfg(unix)] // because symlinks on windows are weird
#[test] #[test]
fn first_path_not_symlink() { fn first_path_not_symlink() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("foo")); mkdirp(td.path().join("foo"));
let dents = WalkBuilder::new(td.path().join("foo")) let dents = WalkBuilder::new(td.path().join("foo"))
@ -2020,9 +2021,7 @@ mod tests {
assert_eq!(1, dents.len()); assert_eq!(1, dents.len());
assert!(!dents[0].path_is_symlink()); assert!(!dents[0].path_is_symlink());
let dents = walk_collect_entries_parallel( let dents = walk_collect_entries_parallel(&WalkBuilder::new(td.path().join("foo")));
&WalkBuilder::new(td.path().join("foo")),
);
assert_eq!(1, dents.len()); assert_eq!(1, dents.len());
assert!(!dents[0].path_is_symlink()); assert!(!dents[0].path_is_symlink());
} }
@ -2030,17 +2029,13 @@ mod tests {
#[cfg(unix)] // because symlinks on windows are weird #[cfg(unix)] // because symlinks on windows are weird
#[test] #[test]
fn symlink_loop() { fn symlink_loop() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b")); mkdirp(td.path().join("a/b"));
symlink(td.path().join("a"), td.path().join("a/b/c")); symlink(td.path().join("a"), td.path().join("a/b/c"));
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
assert_paths(td.path(), &builder, &[ assert_paths(td.path(), &builder, &["a", "a/b", "a/b/c"]);
"a", "a/b", "a/b/c", assert_paths(td.path(), &builder.follow_links(true), &["a", "a/b"]);
]);
assert_paths(td.path(), &builder.follow_links(true), &[
"a", "a/b",
]);
} }
// It's a little tricky to test the 'same_file_system' option since // It's a little tricky to test the 'same_file_system' option since
@ -2060,7 +2055,7 @@ mod tests {
// If our test directory actually isn't a different volume from /sys, // If our test directory actually isn't a different volume from /sys,
// then this test is meaningless and we shouldn't run it. // then this test is meaningless and we shouldn't run it.
let td = tmpdir("walk-test-"); let td = tmpdir();
if device_num(td.path()).unwrap() == device_num("/sys").unwrap() { if device_num(td.path()).unwrap() == device_num("/sys").unwrap() {
return; return;
} }
@ -2074,8 +2069,6 @@ mod tests {
// completely. // completely.
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
builder.follow_links(true).same_file_system(true); builder.follow_links(true).same_file_system(true);
assert_paths(td.path(), &builder, &[ assert_paths(td.path(), &builder, &["same_file", "same_file/alink"]);
"same_file", "same_file/alink",
]);
} }
} }