summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2021-12-27 11:04:51 +0800
committerSebastian Thiel <sebastian.thiel@icloud.com>2021-12-27 11:14:32 +0800
commit26d65145650cc3aac4ad540fdf04e95e139812e3 (patch)
tree988efe04d255c6a8c14f3edcfd6675928ce6b528
parentc27da8b9bf3d2ea091ff9267d2e96df05a17bf05 (diff)
feat: Add `--ignore-dirs` option, with useful default on linux (#116)
On linux there are a few directories which shouldn't be traversed by default as they may cause hangs and blocking. With the new argument it's possible to specify absolute directories to not enter during traversal, with a default set to avoid problematic directories on linux right away.
-rw-r--r--src/common.rs24
-rw-r--r--src/interactive/app/tests/journeys_readonly.rs4
-rw-r--r--src/interactive/app/tests/utils.rs1
-rw-r--r--src/main.rs1
-rw-r--r--src/options.rs7
5 files changed, 28 insertions, 9 deletions
diff --git a/src/common.rs b/src/common.rs
index 88c27f5..4db888e 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -1,5 +1,6 @@
use crate::traverse::{EntryData, Tree, TreeIndex};
use byte_unit::{n_gb_bytes, n_gib_bytes, n_mb_bytes, n_mib_bytes, ByteUnit};
+use std::path::PathBuf;
use std::{fmt, path::Path};
pub fn get_entry_or_panic(tree: &Tree, node_idx: TreeIndex) -> &EntryData {
@@ -123,6 +124,7 @@ pub struct WalkOptions {
pub apparent_size: bool,
pub sorting: TraversalSorting,
pub cross_filesystems: bool,
+ pub ignore_dirs: Vec<PathBuf>,
}
type WalkDir = jwalk::WalkDirGeneric<((), Option<Result<std::fs::Metadata, jwalk::Error>>)>;
@@ -136,14 +138,22 @@ impl WalkOptions {
TraversalSorting::AlphabeticalByFileName => true,
})
.skip_hidden(false)
- .process_read_dir(|_, _, _, dir_entry_results| {
- dir_entry_results.iter_mut().for_each(|dir_entry_result| {
- if let Ok(dir_entry) = dir_entry_result {
- if dir_entry.file_type.is_file() || dir_entry.file_type().is_symlink() {
- dir_entry.client_state = Some(dir_entry.metadata());
+ .process_read_dir({
+ let ignore_dirs = self.ignore_dirs.clone();
+ move |_, _, _, dir_entry_results| {
+ dir_entry_results.iter_mut().for_each(|dir_entry_result| {
+ if let Ok(dir_entry) = dir_entry_result {
+ if dir_entry.file_type.is_file() || dir_entry.file_type().is_symlink() {
+ dir_entry.client_state = Some(dir_entry.metadata());
+ }
+ if dir_entry.file_type.is_dir()
+ && ignore_dirs.contains(&dir_entry.path())
+ {
+ dir_entry.read_children_path = None;
+ }
}
- }
- })
+ })
+ }
})
.parallelism(match self.threads {
0 => jwalk::Parallelism::RayonDefaultPool,
diff --git a/src/interactive/app/tests/journeys_readonly.rs b/src/interactive/app/tests/journeys_readonly.rs
index 4633c1e..76e824e 100644
--- a/src/interactive/app/tests/journeys_readonly.rs
+++ b/src/interactive/app/tests/journeys_readonly.rs
@@ -37,8 +37,8 @@ fn simple_user_journey_read_only() -> Result<()> {
"it will sort entries in descending order by size"
);
- assert_eq!(
- app.state.is_scanning, false,
+ assert!(
+ !app.state.is_scanning,
"it will not think it is still scanning"
);
diff --git a/src/interactive/app/tests/utils.rs b/src/interactive/app/tests/utils.rs
index 017ade3..0e1a8f0 100644
--- a/src/interactive/app/tests/utils.rs
+++ b/src/interactive/app/tests/utils.rs
@@ -178,6 +178,7 @@ pub fn initialized_app_and_terminal_with_closure(
count_hard_links: false,
sorting: TraversalSorting::AlphabeticalByFileName,
cross_filesystems: false,
+ ignore_dirs: Vec::new(),
},
input_paths,
Interaction::None,
diff --git a/src/main.rs b/src/main.rs
index d116bbd..d8720a3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -64,6 +64,7 @@ fn main() -> Result<()> {
count_hard_links: opt.count_hard_links,
sorting: TraversalSorting::None,
cross_filesystems: !opt.stay_on_filesystem,
+ ignore_dirs: opt.ignore_dirs,
};
let res = match opt.command {
#[cfg(any(feature = "tui-unix", feature = "tui-crossplatform"))]
diff --git a/src/options.rs b/src/options.rs
index 8c7c35e..8302d69 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -89,6 +89,13 @@ pub struct Args {
#[clap(short = 'x', long)]
pub stay_on_filesystem: bool,
+ /// One or more absolute directories to ignore. Note that these are not ignored if they are passed as input path.
+ ///
+ /// Hence, they will only be ignored if they are eventually reached as part of the traversal.
+ #[clap(long = "ignore-dirs", short = 'i', parse(from_os_str))]
+ #[cfg_attr(target_os = "linux", clap(default_values = &["/proc", "/dev", "/sys", "/run"]))]
+ pub ignore_dirs: Vec<PathBuf>,
+
/// One or more input files or directories. If unset, we will use all entries in the current working directory.
#[clap(parse(from_os_str))]
pub input: Vec<PathBuf>,