diff options
author | Piotr Wach <pwach@bloomberg.net> | 2023-12-27 20:36:23 +0100 |
---|---|---|
committer | Piotr Wach <pwach@bloomberg.net> | 2023-12-27 21:30:01 +0100 |
commit | e2d5a34b5b6d8212b53d60ceea20324eba08cb2a (patch) | |
tree | 1cd3b8a19bc2a22312b35d8486490f02da85c489 /src/common.rs | |
parent | 196f0d62f32aacc2d393ef2929305a831a150520 (diff) |
fix ignore dirs wip
Diffstat (limited to 'src/common.rs')
-rw-r--r-- | src/common.rs | 83 |
1 files changed, 79 insertions, 4 deletions
diff --git a/src/common.rs b/src/common.rs index 66e2277..f3c98b2 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,7 +1,7 @@ use crate::crossdev; use crate::traverse::{EntryData, Tree, TreeIndex}; use byte_unit::{n_gb_bytes, n_gib_bytes, n_mb_bytes, n_mib_bytes, ByteUnit}; -use log::info; +use std::fs; use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -178,7 +178,7 @@ type WalkDir = jwalk::WalkDirGeneric<((), Option<Result<std::fs::Metadata, jwalk impl WalkOptions { pub(crate) fn iter_from_path(&self, root: &Path, root_device_id: u64) -> WalkDir { - info!("root path={:?}", root); + let ignore_dirs = self.ignore_dirs.clone(); WalkDir::new(root) .follow_links(false) .sort(match self.sorting { @@ -187,7 +187,6 @@ impl WalkOptions { }) .skip_hidden(false) .process_read_dir({ - let ignore_dirs = self.ignore_dirs.clone(); let cross_filesystems = self.cross_filesystems; move |_, _, _, dir_entry_results| { dir_entry_results.iter_mut().for_each(|dir_entry_result| { @@ -200,7 +199,7 @@ impl WalkOptions { .as_ref() .map(|m| crossdev::is_same_device(root_device_id, m)) .unwrap_or(true); - if !ok_for_fs || ignore_dirs.contains(&dir_entry.path()) { + if !ok_for_fs || ignore_directory(&dir_entry.path(), &ignore_dirs) { dir_entry.read_children_path = None; } } @@ -241,3 +240,79 @@ impl WalkResult { i32::from(self.num_errors > 0) } } + +pub fn canonicalize_ignore_dirs(ignore_dirs: &[PathBuf]) -> Vec<PathBuf> { + ignore_dirs + .iter() + .map(fs::canonicalize) + .filter_map(Result::ok) + .collect() +} + +fn ignore_directory(path: &Path, ignore_dirs: &[PathBuf]) -> bool { + if ignore_dirs.is_empty() { + return false; + } + let path = fs::canonicalize(path); + path.map(|path| ignore_dirs.contains(&path)) + .unwrap_or(false) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ignore_directories() { + #[cfg(unix)] + let mut parameters = vec![ + ("/usr", vec!["/usr"], true), + ("/usr/local", vec!["/usr"], false), + ("/smth", vec!["/usr"], false), + ("/usr/local/..", vec!["/usr/local/.."], true), + ("/usr", vec!["/usr/local/.."], true), + ("/usr/local/share/../..", vec!["/usr"], true), + ]; + + #[cfg(windows)] + let mut parameters = vec![ + ("C:\\Windows", vec!["C:\\Windows"], true), + ("C:\\Windows\\System", vec!["C:\\Windows"], false), + ("C:\\Smth", vec!["C:\\Windows"], false), + ( + "C:\\Windows\\System\\..", + vec!["C:\\Windows\\System\\.."], + true, + ), + ("C:\\Windows", vec!["C:\\Windows\\System\\.."], true), + ( + "C:\\Windows\\System\\Speech\\..\\..", + vec!["C:\\Windows"], + true, + ), + ]; + + parameters.append(&mut vec![ + ("src", vec!["src"], true), + ("src/interactive", vec!["src"], false), + ("src/interactive/..", vec!["src"], true), + ]); + + for (path, ignore_dirs, expected_result) in parameters { + let ignore_dirs = canonicalize_ignore_dirs( + &ignore_dirs + .into_iter() + .map(|p| PathBuf::from(p)) + .collect::<Vec<PathBuf>>(), + ); + assert_eq!( + ignore_directory(&PathBuf::from(path), &ignore_dirs), + expected_result, + "result='{}' for path='{}' and ignore_dir='{:?}' ", + expected_result, + path, + ignore_dirs + ); + } + } +} |