du: Add threshold argument support

- Add --threshold parameter and corresponding logic to skip listing
entires that don't adhere to the threshold
This commit is contained in:
Anup Mahindre 2021-06-05 23:35:15 +05:30
parent 440eba628c
commit d6181ce7d4

View file

@ -28,6 +28,7 @@ use std::os::windows::io::AsRawHandle;
#[cfg(windows)] #[cfg(windows)]
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr;
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::parse_size::{parse_size, ParseSizeError};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -56,6 +57,7 @@ mod options {
pub const BLOCK_SIZE_1M: &str = "m"; pub const BLOCK_SIZE_1M: &str = "m";
pub const SEPARATE_DIRS: &str = "S"; pub const SEPARATE_DIRS: &str = "S";
pub const SUMMARIZE: &str = "s"; pub const SUMMARIZE: &str = "s";
pub const THRESHOLD: &str = "threshold";
pub const SI: &str = "si"; pub const SI: &str = "si";
pub const TIME: &str = "time"; pub const TIME: &str = "time";
pub const TIME_STYLE: &str = "time-style"; pub const TIME_STYLE: &str = "time-style";
@ -510,6 +512,17 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.long(options::ONE_FILE_SYSTEM) .long(options::ONE_FILE_SYSTEM)
.help("skip directories on different file systems") .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(
// Arg::with_name("") // Arg::with_name("")
// .short("x") // .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 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) { let multiplier: u64 = if matches.is_present(options::SI) {
1000 1000
} else { } else {
@ -654,6 +673,10 @@ Try '{} --help' for more information.",
// See: http://linux.die.net/man/2/stat // See: http://linux.die.net/man/2/stat
stat.blocks * 512 stat.blocks * 512
}; };
if threshold.should_exclude(size) {
continue;
}
if matches.is_present(options::TIME) { if matches.is_present(options::TIME) {
let tm = { let tm = {
let secs = { let secs = {
@ -720,6 +743,35 @@ Try '{} --help' for more information.",
0 0
} }
struct Threshold(Option<u64>, bool);
impl FromStr for Threshold {
type Err = ParseSizeError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
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 { fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String {
// NOTE: // NOTE:
// GNU's du echos affected flag, -B or --block-size (-t or --threshold), depending user's selection // GNU's du echos affected flag, -B or --block-size (-t or --threshold), depending user's selection