summaryrefslogtreecommitdiffstats
path: root/src/common.rs
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2024-01-03 09:44:40 +0100
committerSebastian Thiel <sebastian.thiel@icloud.com>2024-01-03 10:26:45 +0100
commit93f0f61b3042b933f099714e3a6d336497eb18ba (patch)
tree8c689445d2b6af1155605676abee94df1f2aaa91 /src/common.rs
parent7905b48f2f9ca981a6c617ced3a151e79cab9739 (diff)
Use `gix-path` for more control and performance.
Also add more debugging information to the log, and allow `debug` logging to show up in there. While at it, assure that performance won't be affected too strongly when a lot of directories are used by using a set instead.
Diffstat (limited to 'src/common.rs')
-rw-r--r--src/common.rs36
1 files changed, 24 insertions, 12 deletions
diff --git a/src/common.rs b/src/common.rs
index 0723542..7f4f89e 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 std::fs;
+use std::collections::BTreeSet;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
@@ -171,7 +171,7 @@ pub struct WalkOptions {
pub apparent_size: bool,
pub sorting: TraversalSorting,
pub cross_filesystems: bool,
- pub ignore_dirs: Vec<PathBuf>,
+ pub ignore_dirs: BTreeSet<PathBuf>,
}
type WalkDir = jwalk::WalkDirGeneric<((), Option<Result<std::fs::Metadata, jwalk::Error>>)>;
@@ -179,6 +179,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 {
let ignore_dirs = self.ignore_dirs.clone();
+ let cwd = std::env::current_dir().unwrap_or_else(|_| root.to_owned());
WalkDir::new(root)
.follow_links(false)
.sort(match self.sorting {
@@ -199,7 +200,9 @@ impl WalkOptions {
.as_ref()
.map(|m| crossdev::is_same_device(root_device_id, m))
.unwrap_or(true);
- if !ok_for_fs || ignore_directory(&dir_entry.path(), &ignore_dirs) {
+ if !ok_for_fs
+ || ignore_directory(&dir_entry.path(), &ignore_dirs, &cwd)
+ {
dir_entry.read_children_path = None;
}
}
@@ -241,21 +244,29 @@ impl WalkResult {
}
}
-pub fn canonicalize_ignore_dirs(ignore_dirs: &[PathBuf]) -> Vec<PathBuf> {
- ignore_dirs
+pub fn canonicalize_ignore_dirs(ignore_dirs: &[PathBuf]) -> BTreeSet<PathBuf> {
+ let dirs = ignore_dirs
.iter()
- .map(fs::canonicalize)
+ .map(gix_path::realpath)
.filter_map(Result::ok)
- .collect()
+ .collect();
+ log::info!("Ignoring canonicalized {dirs:?}");
+ dirs
}
-fn ignore_directory(path: &Path, ignore_dirs: &[PathBuf]) -> bool {
+fn ignore_directory(path: &Path, ignore_dirs: &BTreeSet<PathBuf>, cwd: &Path) -> bool {
if ignore_dirs.is_empty() {
return false;
}
- let path = fs::canonicalize(path);
- path.map(|path| ignore_dirs.contains(&path))
- .unwrap_or(false)
+ let path = gix_path::realpath_opts(path, cwd, 32);
+ path.map(|path| {
+ let ignored = ignore_dirs.contains(&path);
+ if ignored {
+ log::debug!("Ignored {path:?}");
+ }
+ ignored
+ })
+ .unwrap_or(false)
}
#[cfg(test)]
@@ -264,6 +275,7 @@ mod tests {
#[test]
fn test_ignore_directories() {
+ let cwd = std::env::current_dir().unwrap();
#[cfg(unix)]
let mut parameters = vec![
("/usr", vec!["/usr"], true),
@@ -303,7 +315,7 @@ mod tests {
&ignore_dirs.into_iter().map(Into::into).collect::<Vec<_>>(),
);
assert_eq!(
- ignore_directory(path.as_ref(), &ignore_dirs),
+ ignore_directory(path.as_ref(), &ignore_dirs, &cwd),
expected_result,
"result='{expected_result}' for path='{path}' and ignore_dir='{ignore_dirs:?}' "
);