mirror of
https://github.com/uutils/coreutils
synced 2024-12-13 23:02:38 +00:00
df: add support for --total option
Add support for the `--total` option to `df`, which displays the total of each numeric column. For example, $ df --total Filesystem 1K-blocks Used Available Use% Mounted on udev 3858016 0 3858016 0% /dev ... /dev/loop14 63488 63488 0 100% /snap/core20/1361 total 258775268 98099712 148220200 40% -
This commit is contained in:
parent
41acdb5471
commit
d0ebd1c9d0
3 changed files with 117 additions and 0 deletions
|
@ -106,6 +106,11 @@ impl From<&ArgMatches> for BlockSize {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parameters that control the behavior of `df`.
|
||||
///
|
||||
/// Most of these parameters control which rows and which columns are
|
||||
/// displayed. The `block_size` determines the units to use when
|
||||
/// displaying numbers of bytes or inodes.
|
||||
#[derive(Default)]
|
||||
struct Options {
|
||||
show_local_fs: bool,
|
||||
|
@ -115,6 +120,9 @@ struct Options {
|
|||
show_inode_instead: bool,
|
||||
block_size: BlockSize,
|
||||
fs_selector: FsSelector,
|
||||
|
||||
/// Whether to show a final row comprising the totals for each column.
|
||||
show_total: bool,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
|
@ -128,6 +136,7 @@ impl Options {
|
|||
show_inode_instead: matches.is_present(OPT_INODES),
|
||||
block_size: BlockSize::from(matches),
|
||||
fs_selector: FsSelector::from(matches),
|
||||
show_total: matches.is_present(OPT_TOTAL),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -307,9 +316,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
.filter(|fs| fs.usage.blocks != 0 || opt.show_all_fs || opt.show_listed_fs)
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
|
||||
println!("{}", Header::new(&opt));
|
||||
let mut total = Row::new("total");
|
||||
for row in data {
|
||||
println!("{}", DisplayRow::new(&row, &opt));
|
||||
total += row;
|
||||
}
|
||||
if opt.show_total {
|
||||
println!("{}", DisplayRow::new(&total, &opt));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -15,6 +15,7 @@ use crate::{BlockSize, Filesystem, Options};
|
|||
use uucore::fsext::{FsUsage, MountInfo};
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::AddAssign;
|
||||
|
||||
/// A row in the filesystem usage data table.
|
||||
///
|
||||
|
@ -67,6 +68,63 @@ pub(crate) struct Row {
|
|||
inodes_usage: Option<f64>,
|
||||
}
|
||||
|
||||
impl Row {
|
||||
pub(crate) fn new(source: &str) -> Self {
|
||||
Self {
|
||||
fs_device: source.into(),
|
||||
fs_type: "-".into(),
|
||||
fs_mount: "-".into(),
|
||||
bytes: 0,
|
||||
bytes_used: 0,
|
||||
bytes_free: 0,
|
||||
bytes_usage: None,
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: None,
|
||||
inodes: 0,
|
||||
inodes_used: 0,
|
||||
inodes_free: 0,
|
||||
inodes_usage: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Row {
|
||||
/// Sum the numeric values of two rows.
|
||||
///
|
||||
/// The `Row::fs_device` field is set to `"total"` and the
|
||||
/// remaining `String` fields are set to `"-"`.
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
let bytes = self.bytes + rhs.bytes;
|
||||
let bytes_used = self.bytes_used + rhs.bytes_used;
|
||||
let inodes = self.inodes + rhs.inodes;
|
||||
let inodes_used = self.inodes_used + rhs.inodes_used;
|
||||
*self = Self {
|
||||
fs_device: "total".into(),
|
||||
fs_type: "-".into(),
|
||||
fs_mount: "-".into(),
|
||||
bytes,
|
||||
bytes_used,
|
||||
bytes_free: self.bytes_free + rhs.bytes_free,
|
||||
bytes_usage: if bytes == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(bytes_used as f64 / bytes as f64)
|
||||
},
|
||||
// TODO Figure out how to compute this.
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: None,
|
||||
inodes,
|
||||
inodes_used,
|
||||
inodes_free: self.inodes_free + rhs.inodes_free,
|
||||
inodes_usage: if inodes == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(inodes_used as f64 / inodes as f64)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Filesystem> for Row {
|
||||
fn from(fs: Filesystem) -> Self {
|
||||
let MountInfo {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// spell-checker:ignore udev
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
|
@ -77,4 +78,47 @@ fn test_type_option() {
|
|||
new_ucmd!().args(&["-t", "ext4", "-t", "ext3"]).succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_total() {
|
||||
// Example output:
|
||||
//
|
||||
// Filesystem 1K-blocks Used Available Use% Mounted on
|
||||
// udev 3858016 0 3858016 0% /dev
|
||||
// ...
|
||||
// /dev/loop14 63488 63488 0 100% /snap/core20/1361
|
||||
// total 258775268 98099712 148220200 40% -
|
||||
let output = new_ucmd!().arg("--total").succeeds().stdout_move_str();
|
||||
|
||||
// Skip the header line.
|
||||
let lines: Vec<&str> = output.lines().skip(1).collect();
|
||||
|
||||
// Parse the values from the last row.
|
||||
let last_line = lines.last().unwrap();
|
||||
let mut iter = last_line.split_whitespace();
|
||||
assert_eq!(iter.next().unwrap(), "total");
|
||||
let reported_total_size = iter.next().unwrap().parse().unwrap();
|
||||
let reported_total_used = iter.next().unwrap().parse().unwrap();
|
||||
let reported_total_avail = iter.next().unwrap().parse().unwrap();
|
||||
|
||||
// Loop over each row except the last, computing the sum of each column.
|
||||
let mut computed_total_size = 0;
|
||||
let mut computed_total_used = 0;
|
||||
let mut computed_total_avail = 0;
|
||||
let n = lines.len();
|
||||
for line in &lines[..n - 1] {
|
||||
let mut iter = line.split_whitespace();
|
||||
iter.next().unwrap();
|
||||
computed_total_size += iter.next().unwrap().parse::<u64>().unwrap();
|
||||
computed_total_used += iter.next().unwrap().parse::<u64>().unwrap();
|
||||
computed_total_avail += iter.next().unwrap().parse::<u64>().unwrap();
|
||||
}
|
||||
|
||||
// Check that the sum of each column matches the reported value in
|
||||
// the last row.
|
||||
assert_eq!(computed_total_size, reported_total_size);
|
||||
assert_eq!(computed_total_used, reported_total_used);
|
||||
assert_eq!(computed_total_avail, reported_total_avail);
|
||||
// TODO We could also check here that the use percentage matches.
|
||||
}
|
||||
|
||||
// ToDO: more tests...
|
||||
|
|
Loading…
Reference in a new issue