mirror of
https://github.com/uutils/coreutils
synced 2025-01-07 10:49:09 +00:00
du: remove ArgMatches from StatPrinter
This commit is contained in:
parent
09999427cc
commit
6cae191569
1 changed files with 84 additions and 81 deletions
|
@ -87,6 +87,18 @@ struct Options {
|
||||||
count_links: bool,
|
count_links: bool,
|
||||||
inodes: bool,
|
inodes: bool,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
|
threshold: Option<Threshold>,
|
||||||
|
apparent_size: bool,
|
||||||
|
// TODO: the size conversion fields should be unified
|
||||||
|
si: bool,
|
||||||
|
bytes: bool,
|
||||||
|
human_readable: bool,
|
||||||
|
block_size_1k: bool,
|
||||||
|
block_size_1m: bool,
|
||||||
|
block_size: u64,
|
||||||
|
time: Option<Time>,
|
||||||
|
time_format: String,
|
||||||
|
line_ending: LineEnding,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
|
@ -96,6 +108,13 @@ enum Deref {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum Time {
|
||||||
|
Accessed,
|
||||||
|
Modified,
|
||||||
|
Created,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
file_id: u128,
|
file_id: u128,
|
||||||
|
@ -273,10 +292,10 @@ fn read_block_size(s: Option<&str>) -> UResult<u64> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn choose_size(matches: &ArgMatches, stat: &Stat) -> u64 {
|
fn choose_size(options: &Options, stat: &Stat) -> u64 {
|
||||||
if matches.get_flag(options::INODES) {
|
if options.inodes {
|
||||||
stat.inodes
|
stat.inodes
|
||||||
} else if matches.get_flag(options::APPARENT_SIZE) || matches.get_flag(options::BYTES) {
|
} else if options.apparent_size || options.bytes {
|
||||||
stat.size
|
stat.size
|
||||||
} else {
|
} else {
|
||||||
// The st_blocks field indicates the number of blocks allocated to the file, 512-byte units.
|
// The st_blocks field indicates the number of blocks allocated to the file, 512-byte units.
|
||||||
|
@ -423,14 +442,14 @@ fn convert_size_other(size: u64, _multiplier: u64, block_size: u64) -> String {
|
||||||
format!("{}", ((size as f64) / (block_size as f64)).ceil())
|
format!("{}", ((size as f64) / (block_size as f64)).ceil())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_convert_size_fn(matches: &ArgMatches) -> Box<dyn Fn(u64, u64, u64) -> String + Send> {
|
fn get_convert_size_fn(options: &Options) -> Box<dyn Fn(u64, u64, u64) -> String + Send> {
|
||||||
if matches.get_flag(options::HUMAN_READABLE) || matches.get_flag(options::SI) {
|
if options.human_readable || options.si {
|
||||||
Box::new(convert_size_human)
|
Box::new(convert_size_human)
|
||||||
} else if matches.get_flag(options::BYTES) {
|
} else if options.bytes {
|
||||||
Box::new(convert_size_b)
|
Box::new(convert_size_b)
|
||||||
} else if matches.get_flag(options::BLOCK_SIZE_1K) {
|
} else if options.block_size_1k {
|
||||||
Box::new(convert_size_k)
|
Box::new(convert_size_k)
|
||||||
} else if matches.get_flag(options::BLOCK_SIZE_1M) {
|
} else if options.block_size_1m {
|
||||||
Box::new(convert_size_m)
|
Box::new(convert_size_m)
|
||||||
} else {
|
} else {
|
||||||
Box::new(convert_size_other)
|
Box::new(convert_size_other)
|
||||||
|
@ -442,7 +461,7 @@ enum DuError {
|
||||||
InvalidMaxDepthArg(String),
|
InvalidMaxDepthArg(String),
|
||||||
SummarizeDepthConflict(String),
|
SummarizeDepthConflict(String),
|
||||||
InvalidTimeStyleArg(String),
|
InvalidTimeStyleArg(String),
|
||||||
InvalidTimeArg(String),
|
InvalidTimeArg,
|
||||||
InvalidGlob(String),
|
InvalidGlob(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,11 +487,9 @@ Try '{} --help' for more information.",
|
||||||
s.quote(),
|
s.quote(),
|
||||||
uucore::execution_phrase()
|
uucore::execution_phrase()
|
||||||
),
|
),
|
||||||
Self::InvalidTimeArg(s) => write!(
|
Self::InvalidTimeArg => write!(
|
||||||
f,
|
f,
|
||||||
"Invalid argument {} for --time.
|
"'birth' and 'creation' arguments for --time are not supported on this platform.",
|
||||||
'birth' and 'creation' arguments are not supported on this platform.",
|
|
||||||
s.quote()
|
|
||||||
),
|
),
|
||||||
Self::InvalidGlob(s) => write!(f, "Invalid exclude syntax: {s}"),
|
Self::InvalidGlob(s) => write!(f, "Invalid exclude syntax: {s}"),
|
||||||
}
|
}
|
||||||
|
@ -487,7 +504,7 @@ impl UError for DuError {
|
||||||
Self::InvalidMaxDepthArg(_)
|
Self::InvalidMaxDepthArg(_)
|
||||||
| Self::SummarizeDepthConflict(_)
|
| Self::SummarizeDepthConflict(_)
|
||||||
| Self::InvalidTimeStyleArg(_)
|
| Self::InvalidTimeStyleArg(_)
|
||||||
| Self::InvalidTimeArg(_)
|
| Self::InvalidTimeArg
|
||||||
| Self::InvalidGlob(_) => 1,
|
| Self::InvalidGlob(_) => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -535,62 +552,25 @@ struct StatPrintInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StatPrinter {
|
struct StatPrinter {
|
||||||
matches: ArgMatches,
|
|
||||||
threshold: Option<Threshold>,
|
|
||||||
summarize: bool,
|
summarize: bool,
|
||||||
time_format_str: String,
|
|
||||||
line_ending: LineEnding,
|
|
||||||
options: Options,
|
options: Options,
|
||||||
convert_size: Box<dyn Fn(u64) -> String + Send>,
|
convert_size: Box<dyn Fn(u64) -> String + Send>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatPrinter {
|
impl StatPrinter {
|
||||||
fn new(matches: ArgMatches, options: Options, summarize: bool) -> UResult<Self> {
|
fn new(options: Options, summarize: bool) -> UResult<Self> {
|
||||||
let block_size = read_block_size(
|
let multiplier: u64 = if options.si { 1000 } else { 1024 };
|
||||||
matches
|
|
||||||
.get_one::<String>(options::BLOCK_SIZE)
|
|
||||||
.map(|s| s.as_str()),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let multiplier: u64 = if matches.get_flag(options::SI) {
|
let convert_size_fn = get_convert_size_fn(&options);
|
||||||
1000
|
|
||||||
} else {
|
|
||||||
1024
|
|
||||||
};
|
|
||||||
|
|
||||||
let convert_size_fn = get_convert_size_fn(&matches);
|
|
||||||
|
|
||||||
let convert_size: Box<dyn Fn(u64) -> String + Send> = if options.inodes {
|
let convert_size: Box<dyn Fn(u64) -> String + Send> = if options.inodes {
|
||||||
Box::new(|size: u64| size.to_string())
|
Box::new(|size: u64| size.to_string())
|
||||||
} else {
|
} else {
|
||||||
Box::new(move |size: u64| convert_size_fn(size, multiplier, block_size))
|
Box::new(move |size: u64| convert_size_fn(size, multiplier, options.block_size))
|
||||||
};
|
};
|
||||||
|
|
||||||
let threshold = match matches.get_one::<String>(options::THRESHOLD) {
|
|
||||||
Some(s) => match Threshold::from_str(s) {
|
|
||||||
Ok(t) => Some(t),
|
|
||||||
Err(e) => {
|
|
||||||
return Err(USimpleError::new(
|
|
||||||
1,
|
|
||||||
format_error_message(&e, s, options::THRESHOLD),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let time_format_str =
|
|
||||||
parse_time_style(matches.get_one::<String>("time-style").map(|s| s.as_str()))?
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let line_ending = LineEnding::from_zero_flag(matches.get_flag(options::NULL));
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
matches,
|
|
||||||
threshold,
|
|
||||||
summarize,
|
summarize,
|
||||||
time_format_str,
|
|
||||||
line_ending,
|
|
||||||
options,
|
options,
|
||||||
convert_size,
|
convert_size,
|
||||||
})
|
})
|
||||||
|
@ -604,13 +584,14 @@ impl StatPrinter {
|
||||||
match received {
|
match received {
|
||||||
Ok(message) => match message {
|
Ok(message) => match message {
|
||||||
Ok(stat_info) => {
|
Ok(stat_info) => {
|
||||||
let size = choose_size(&self.matches, &stat_info.stat);
|
let size = choose_size(&self.options, &stat_info.stat);
|
||||||
|
|
||||||
if stat_info.depth == 0 {
|
if stat_info.depth == 0 {
|
||||||
grand_total += size;
|
grand_total += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self
|
if !self
|
||||||
|
.options
|
||||||
.threshold
|
.threshold
|
||||||
.map_or(false, |threshold| threshold.should_exclude(size))
|
.map_or(false, |threshold| threshold.should_exclude(size))
|
||||||
&& self
|
&& self
|
||||||
|
@ -630,31 +611,24 @@ impl StatPrinter {
|
||||||
|
|
||||||
if self.options.total {
|
if self.options.total {
|
||||||
print!("{}\ttotal", (self.convert_size)(grand_total));
|
print!("{}\ttotal", (self.convert_size)(grand_total));
|
||||||
print!("{}", self.line_ending);
|
print!("{}", self.options.line_ending);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_stat(&self, stat: &Stat, size: u64) -> UResult<()> {
|
fn print_stat(&self, stat: &Stat, size: u64) -> UResult<()> {
|
||||||
if self.matches.contains_id(options::TIME) {
|
if let Some(time) = self.options.time {
|
||||||
let tm = {
|
let secs = get_time_secs(time, stat)?;
|
||||||
let secs = self
|
let tm = DateTime::<Local>::from(UNIX_EPOCH + Duration::from_secs(secs));
|
||||||
.matches
|
let time_str = tm.format(&self.options.time_format).to_string();
|
||||||
.get_one::<String>(options::TIME)
|
|
||||||
.map(|s| get_time_secs(s, stat))
|
|
||||||
.transpose()?
|
|
||||||
.unwrap_or(stat.modified);
|
|
||||||
DateTime::<Local>::from(UNIX_EPOCH + Duration::from_secs(secs))
|
|
||||||
};
|
|
||||||
let time_str = tm.format(&self.time_format_str).to_string();
|
|
||||||
print!("{}\t{}\t", (self.convert_size)(size), time_str);
|
print!("{}\t{}\t", (self.convert_size)(size), time_str);
|
||||||
} else {
|
} else {
|
||||||
print!("{}\t", (self.convert_size)(size));
|
print!("{}\t", (self.convert_size)(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
print_verbatim(&stat.path).unwrap();
|
print_verbatim(&stat.path).unwrap();
|
||||||
print!("{}", self.line_ending);
|
print!("{}", self.options.line_ending);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -685,6 +659,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
None => vec![PathBuf::from(".")],
|
None => vec![PathBuf::from(".")],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let time = matches.contains_id(options::TIME).then(|| {
|
||||||
|
match matches.get_one::<String>(options::TIME).map(AsRef::as_ref) {
|
||||||
|
None | Some("ctime" | "status") => Time::Modified,
|
||||||
|
Some("access" | "atime" | "use") => Time::Accessed,
|
||||||
|
Some("birth" | "creation") => Time::Created,
|
||||||
|
_ => unreachable!("should be caught by clap"),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let block_size = read_block_size(
|
||||||
|
matches
|
||||||
|
.get_one::<String>(options::BLOCK_SIZE)
|
||||||
|
.map(|s| s.as_str()),
|
||||||
|
)?;
|
||||||
|
|
||||||
let options = Options {
|
let options = Options {
|
||||||
all: matches.get_flag(options::ALL),
|
all: matches.get_flag(options::ALL),
|
||||||
max_depth,
|
max_depth,
|
||||||
|
@ -702,6 +691,25 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
count_links: matches.get_flag(options::COUNT_LINKS),
|
count_links: matches.get_flag(options::COUNT_LINKS),
|
||||||
inodes: matches.get_flag(options::INODES),
|
inodes: matches.get_flag(options::INODES),
|
||||||
verbose: matches.get_flag(options::VERBOSE),
|
verbose: matches.get_flag(options::VERBOSE),
|
||||||
|
si: matches.get_flag(options::SI),
|
||||||
|
threshold: matches
|
||||||
|
.get_one::<String>(options::THRESHOLD)
|
||||||
|
.map(|s| {
|
||||||
|
Threshold::from_str(s).map_err(|e| {
|
||||||
|
USimpleError::new(1, format_error_message(&e, s, options::THRESHOLD))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.transpose()?,
|
||||||
|
apparent_size: matches.get_flag(options::APPARENT_SIZE),
|
||||||
|
bytes: matches.get_flag(options::BYTES),
|
||||||
|
time,
|
||||||
|
block_size,
|
||||||
|
human_readable: matches.get_flag(options::HUMAN_READABLE),
|
||||||
|
block_size_1k: matches.get_flag(options::BLOCK_SIZE_1K),
|
||||||
|
block_size_1m: matches.get_flag(options::BLOCK_SIZE_1M),
|
||||||
|
time_format: parse_time_style(matches.get_one::<String>("time-style").map(|s| s.as_str()))?
|
||||||
|
.to_string(),
|
||||||
|
line_ending: LineEnding::from_zero_flag(matches.get_flag(options::NULL)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if options.inodes
|
if options.inodes
|
||||||
|
@ -711,7 +719,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use separate thread to print output, so we can print finished results while computation is still running
|
// Use separate thread to print output, so we can print finished results while computation is still running
|
||||||
let stat_printer = StatPrinter::new(matches.clone(), options.clone(), summarize)?;
|
let stat_printer = StatPrinter::new(options.clone(), summarize)?;
|
||||||
let (print_tx, rx) = mpsc::channel::<UResult<StatPrintInfo>>();
|
let (print_tx, rx) = mpsc::channel::<UResult<StatPrintInfo>>();
|
||||||
let printing_thread = thread::spawn(move || stat_printer.print_stats(&rx));
|
let printing_thread = thread::spawn(move || stat_printer.print_stats(&rx));
|
||||||
|
|
||||||
|
@ -767,17 +775,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_time_secs(s: &str, stat: &Stat) -> Result<u64, DuError> {
|
fn get_time_secs(time: Time, stat: &Stat) -> Result<u64, DuError> {
|
||||||
let secs = match s {
|
match time {
|
||||||
"ctime" | "status" => stat.modified,
|
Time::Modified => Ok(stat.modified),
|
||||||
"access" | "atime" | "use" => stat.accessed,
|
Time::Accessed => Ok(stat.accessed),
|
||||||
"birth" | "creation" => stat
|
Time::Created => stat.created.ok_or_else(|| DuError::InvalidTimeArg),
|
||||||
.created
|
}
|
||||||
.ok_or_else(|| DuError::InvalidTimeArg(s.into()))?,
|
|
||||||
// below should never happen as clap already restricts the values.
|
|
||||||
_ => unreachable!("Invalid field for --time"),
|
|
||||||
};
|
|
||||||
Ok(secs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_time_style(s: Option<&str>) -> UResult<&str> {
|
fn parse_time_style(s: Option<&str>) -> UResult<&str> {
|
||||||
|
|
Loading…
Reference in a new issue