From d6181ce7d44e523c8400f4081bb1b16d3d97b0aa Mon Sep 17 00:00:00 2001 From: Anup Mahindre Date: Sat, 5 Jun 2021 23:35:15 +0530 Subject: [PATCH 1/3] du: Add threshold argument support - Add --threshold parameter and corresponding logic to skip listing entires that don't adhere to the threshold --- src/uu/du/src/du.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index b7c53eb72..39af3d7e1 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -28,6 +28,7 @@ use std::os::windows::io::AsRawHandle; #[cfg(windows)] use std::path::Path; use std::path::PathBuf; +use std::str::FromStr; use std::time::{Duration, UNIX_EPOCH}; use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::InvalidEncodingHandling; @@ -56,6 +57,7 @@ mod options { pub const BLOCK_SIZE_1M: &str = "m"; pub const SEPARATE_DIRS: &str = "S"; pub const SUMMARIZE: &str = "s"; + pub const THRESHOLD: &str = "threshold"; pub const SI: &str = "si"; pub const TIME: &str = "time"; pub const TIME_STYLE: &str = "time-style"; @@ -510,6 +512,17 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .long(options::ONE_FILE_SYSTEM) .help("skip directories on different file systems") ) + .arg( + Arg::with_name(options::THRESHOLD) + .short("t") + .long(options::THRESHOLD) + .alias("th") + .value_name("SIZE") + .number_of_values(1) + .allow_hyphen_values(true) + .help("exclude entries smaller than SIZE if positive, \ + or entries greater than SIZE if negative") + ) // .arg( // Arg::with_name("") // .short("x") @@ -586,6 +599,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let block_size = u64::try_from(read_block_size(matches.value_of(options::BLOCK_SIZE))).unwrap(); + let threshold = match matches.value_of(options::THRESHOLD) { + Some(s) => Threshold::from_str(s) + .unwrap_or_else(|e| crash!(1, "{}", format_error_message(e, s, options::THRESHOLD))), + None => Threshold(None, false), + }; + let multiplier: u64 = if matches.is_present(options::SI) { 1000 } else { @@ -654,6 +673,10 @@ Try '{} --help' for more information.", // See: http://linux.die.net/man/2/stat stat.blocks * 512 }; + if threshold.should_exclude(size) { + continue; + } + if matches.is_present(options::TIME) { let tm = { let secs = { @@ -720,6 +743,35 @@ Try '{} --help' for more information.", 0 } +struct Threshold(Option, bool); + +impl FromStr for Threshold { + type Err = ParseSizeError; + + fn from_str(s: &str) -> std::result::Result { + let offset = if s.starts_with('-') || s.starts_with('+') { + 1 + } else { + 0 + }; + let sz = parse_size(&s[offset..])?; + + Ok(Threshold( + Some(u64::try_from(sz).unwrap()), + s.starts_with('-'), + )) + } +} + +impl Threshold { + fn should_exclude(&self, sz: u64) -> bool { + match *self { + Threshold(Some(th), is_upper) => (is_upper && sz > th) || (!is_upper && sz < th), + Threshold(None, _) => false, + } + } +} + fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String { // NOTE: // GNU's du echos affected flag, -B or --block-size (-t or --threshold), depending user's selection From fa12b46c51268dd4c4f2db6fcaf93421c3330015 Mon Sep 17 00:00:00 2001 From: Anup Mahindre Date: Sat, 12 Jun 2021 19:30:48 +0530 Subject: [PATCH 2/3] tests: Add test for du threshold feature --- tests/by-util/test_du.rs | 50 +++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 8d1267423..93875ae51 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -80,19 +80,22 @@ fn _du_basics_subdir(s: &str) { #[test] fn test_du_invalid_size() { - new_ucmd!() - .arg("--block-size=1fb4t") - .arg("/tmp") - .fails() - .code_is(1) - .stderr_only("du: invalid --block-size argument '1fb4t'"); - #[cfg(not(target_pointer_width = "128"))] - new_ucmd!() - .arg("--block-size=1Y") - .arg("/tmp") - .fails() - .code_is(1) - .stderr_only("du: --block-size argument '1Y' too large"); + let args = &["block-size", "threshold"]; + for s in args { + new_ucmd!() + .arg(format!("--{}=1fb4t", s)) + .arg("/tmp") + .fails() + .code_is(1) + .stderr_only(format!("du: invalid --{} argument '1fb4t'", s)); + #[cfg(not(target_pointer_width = "128"))] + new_ucmd!() + .arg(format!("--{}=1Y", s)) + .arg("/tmp") + .fails() + .code_is(1) + .stderr_only(format!("du: --{} argument '1Y' too large", s)); + } } #[test] @@ -351,3 +354,24 @@ fn test_du_one_file_system() { } _du_basics_subdir(result.stdout_str()); } + +#[test] +fn test_du_threshold() { + let scene = TestScenario::new(util_name!()); + + let threshold = if cfg!(windows) { "7K" } else { "10K" }; + + scene + .ucmd() + .arg(format!("--threshold={}", threshold)) + .succeeds() + .stdout_contains("links") + .stdout_does_not_contain("deeper"); + + scene + .ucmd() + .arg(format!("--threshold=-{}", threshold)) + .succeeds() + .stdout_does_not_contain("links") + .stdout_contains("deeper"); +} From da7b02cf9d8b64d35de957124807f3a3b80c02ac Mon Sep 17 00:00:00 2001 From: Anup Mahindre Date: Sat, 12 Jun 2021 21:31:56 +0530 Subject: [PATCH 3/3] du: Refactor threshold handling --- src/uu/du/src/du.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index 39af3d7e1..e466b8afe 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -599,11 +599,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let block_size = u64::try_from(read_block_size(matches.value_of(options::BLOCK_SIZE))).unwrap(); - let threshold = match matches.value_of(options::THRESHOLD) { - Some(s) => Threshold::from_str(s) - .unwrap_or_else(|e| crash!(1, "{}", format_error_message(e, s, options::THRESHOLD))), - None => Threshold(None, false), - }; + let threshold = matches.value_of(options::THRESHOLD).map(|s| { + Threshold::from_str(s) + .unwrap_or_else(|e| crash!(1, "{}", format_error_message(e, s, options::THRESHOLD))) + }); let multiplier: u64 = if matches.is_present(options::SI) { 1000 @@ -673,7 +672,8 @@ Try '{} --help' for more information.", // See: http://linux.die.net/man/2/stat stat.blocks * 512 }; - if threshold.should_exclude(size) { + + if threshold.map_or(false, |threshold| threshold.should_exclude(size)) { continue; } @@ -743,31 +743,33 @@ Try '{} --help' for more information.", 0 } -struct Threshold(Option, bool); +#[derive(Clone, Copy)] +enum Threshold { + Lower(u64), + Upper(u64), +} impl FromStr for Threshold { type Err = ParseSizeError; fn from_str(s: &str) -> std::result::Result { - let offset = if s.starts_with('-') || s.starts_with('+') { - 1 - } else { - 0 - }; - let sz = parse_size(&s[offset..])?; + let offset = if s.starts_with(&['-', '+'][..]) { 1 } else { 0 }; - Ok(Threshold( - Some(u64::try_from(sz).unwrap()), - s.starts_with('-'), - )) + let size = u64::try_from(parse_size(&s[offset..])?).unwrap(); + + if s.starts_with('-') { + Ok(Threshold::Upper(size)) + } else { + Ok(Threshold::Lower(size)) + } } } impl Threshold { - fn should_exclude(&self, sz: u64) -> bool { + fn should_exclude(&self, size: u64) -> bool { match *self { - Threshold(Some(th), is_upper) => (is_upper && sz > th) || (!is_upper && sz < th), - Threshold(None, _) => false, + Threshold::Upper(threshold) => size > threshold, + Threshold::Lower(threshold) => size < threshold, } } }