Initial version of parallel directory traversal

see #32
This commit is contained in:
sharkdp 2017-06-11 22:43:30 +02:00 committed by David Peter
parent 2d1d24c38c
commit e06189e654
1 changed files with 42 additions and 28 deletions

View File

@ -17,6 +17,7 @@ use std::ops::Deref;
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
use std::path::{Path, Component}; use std::path::{Path, Component};
use std::process; use std::process;
use std::sync::Arc;
use clap::{App, AppSettings, Arg}; use clap::{App, AppSettings, Arg};
use atty::Stream; use atty::Stream;
@ -93,6 +94,9 @@ fn print_entry(base: &Path, entry: &Path, config: &FdOptions) {
#[cfg(not(target_family = "unix"))] #[cfg(not(target_family = "unix"))]
let is_executable = |p: &std::path::PathBuf| {false}; let is_executable = |p: &std::path::PathBuf| {false};
let stdout = std::io::stdout();
let mut handle = stdout.lock();
if let Some(ref ls_colors) = config.ls_colors { if let Some(ref ls_colors) = config.ls_colors {
let default_style = ansi_term::Style::default(); let default_style = ansi_term::Style::default();
@ -139,17 +143,17 @@ fn print_entry(base: &Path, entry: &Path, config: &FdOptions) {
} }
}; };
print!("{}", style.paint(comp_str)); write!(handle, "{}", style.paint(comp_str));
if component_path.is_dir() && component_path != path_full { if component_path.is_dir() && component_path != path_full {
let sep = std::path::MAIN_SEPARATOR.to_string(); let sep = std::path::MAIN_SEPARATOR.to_string();
print!("{}", style.paint(sep)); write!(handle, "{}", style.paint(sep));
} }
} }
if config.null_separator { if config.null_separator {
print!("{}", '\0'); writeln!(handle, "{}", '\0');
} else { } else {
println!(); writeln!(handle);
} }
} else { } else {
// Uncolorized output // Uncolorized output
@ -157,7 +161,7 @@ fn print_entry(base: &Path, entry: &Path, config: &FdOptions) {
let prefix = if config.path_display == PathDisplay::Absolute { ROOT_DIR } else { "" }; let prefix = if config.path_display == PathDisplay::Absolute { ROOT_DIR } else { "" };
let separator = if config.null_separator { "\0" } else { "\n" }; let separator = if config.null_separator { "\0" } else { "\n" };
let r = write!(&mut std::io::stdout(), "{}{}{}", prefix, path_str, separator); let r = writeln!(&mut std::io::stdout(), "{}{}{}", prefix, path_str, separator);
if r.is_err() { if r.is_err() {
// Probably a broken pipe. Exit gracefully. // Probably a broken pipe. Exit gracefully.
@ -167,7 +171,7 @@ fn print_entry(base: &Path, entry: &Path, config: &FdOptions) {
} }
/// Recursively scan the given search path and search for files / pathnames matching the pattern. /// Recursively scan the given search path and search for files / pathnames matching the pattern.
fn scan(root: &Path, pattern: &Regex, base: &Path, config: &FdOptions) { fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions>) {
let walker = WalkBuilder::new(root) let walker = WalkBuilder::new(root)
.hidden(config.ignore_hidden) .hidden(config.ignore_hidden)
.ignore(config.read_ignore) .ignore(config.read_ignore)
@ -177,31 +181,41 @@ fn scan(root: &Path, pattern: &Regex, base: &Path, config: &FdOptions) {
.git_exclude(config.read_ignore) .git_exclude(config.read_ignore)
.follow_links(config.follow_links) .follow_links(config.follow_links)
.max_depth(config.max_depth) .max_depth(config.max_depth)
.build() .build_parallel();
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.path() != root);
for entry in walker { walker.run(|| {
let path_rel_buf = match fshelper::path_relative_from(entry.path(), base) { let base = base.to_owned();
Some(p) => p, let config = config.clone();
None => error("Error: could not get relative path for directory entry.") let pattern = pattern.clone();
};
let path_rel = path_rel_buf.as_path();
let search_str_o = Box::new(move |entry_o| {
if config.search_full_path { let entry = match entry_o {
Some(path_rel.to_string_lossy()) Ok(e) => e,
} else { Err(_) => return ignore::WalkState::Continue
path_rel.file_name()
.map(|f| f.to_string_lossy())
}; };
if let Some(search_str) = search_str_o { let path_rel_buf = match fshelper::path_relative_from(entry.path(), &*base) {
pattern.find(&*search_str) Some(p) => p,
.map(|_| print_entry(base, path_rel, config)); None => error("Error: could not get relative path for directory entry.")
} };
} let path_rel = path_rel_buf.as_path();
let search_str_o =
if config.search_full_path {
Some(path_rel.to_string_lossy())
} else {
path_rel.file_name()
.map(|f| f.to_string_lossy())
};
if let Some(search_str) = search_str_o {
pattern.find(&*search_str)
.map(|_| print_entry(&base, path_rel, &config));
}
ignore::WalkState::Continue
})
});
} }
/// Print error message to stderr and exit with status `1`. /// Print error message to stderr and exit with status `1`.
@ -338,7 +352,7 @@ fn main() {
match RegexBuilder::new(pattern) match RegexBuilder::new(pattern)
.case_insensitive(!config.case_sensitive) .case_insensitive(!config.case_sensitive)
.build() { .build() {
Ok(re) => scan(root_dir, &re, base, &config), Ok(re) => scan(root_dir, Arc::new(re), base, Arc::new(config)),
Err(err) => error(err.description()) Err(err) => error(err.description())
} }
} }