1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

df: implement the --output command-line argument

Implement the `--output` command-line argument, which allows
specifying an exact sequence of columns to display in the output
table. For example,

    $ df --output=source,fstype | head -n3
    Filesystem       Type
    udev             devtmpfs
    tmpfs            tmpfs

(The spacing does not exactly match the spacing of GNU `df` yet.)

Fixes #3057.
This commit is contained in:
Jeffrey Finkelstein 2022-02-21 19:54:12 -05:00
parent 0b07ecdad2
commit ec048b3857
2 changed files with 91 additions and 5 deletions

View file

@ -3,7 +3,7 @@
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
// spell-checker:ignore itotal iused iavail ipcent pcent squashfs
use crate::{OPT_INODES, OPT_PRINT_TYPE};
use crate::{OPT_INODES, OPT_OUTPUT, OPT_PRINT_TYPE};
use clap::ArgMatches;
/// The columns in the output table produced by `df`.
@ -65,8 +65,9 @@ impl Column {
match (
matches.is_present(OPT_PRINT_TYPE),
matches.is_present(OPT_INODES),
matches.occurrences_of(OPT_OUTPUT) > 0,
) {
(false, false) => vec![
(false, false, false) => vec![
Self::Source,
Self::Size,
Self::Used,
@ -76,7 +77,20 @@ impl Column {
Self::Pcent,
Self::Target,
],
(false, true) => vec![
(false, false, true) => {
matches
.values_of(OPT_OUTPUT)
.unwrap()
.map(|s| {
// Unwrapping here should not panic because the
// command-line argument parsing library should be
// responsible for ensuring each comma-separated
// string is a valid column label.
Self::parse(s).unwrap()
})
.collect()
}
(false, true, false) => vec![
Self::Source,
Self::Itotal,
Self::Iused,
@ -84,7 +98,7 @@ impl Column {
Self::Ipcent,
Self::Target,
],
(true, false) => vec![
(true, false, false) => vec![
Self::Source,
Self::Fstype,
Self::Size,
@ -95,7 +109,7 @@ impl Column {
Self::Pcent,
Self::Target,
],
(true, true) => vec![
(true, true, false) => vec![
Self::Source,
Self::Fstype,
Self::Itotal,
@ -104,6 +118,49 @@ impl Column {
Self::Ipcent,
Self::Target,
],
// The command-line arguments -T and -i are each mutually
// exclusive with --output, so the command-line argument
// parser should reject those combinations before we get
// to this point in the code.
_ => unreachable!(),
}
}
/// Convert a column name to the corresponding enumeration variant.
///
/// There are twelve valid column names, one for each variant:
///
/// - "source"
/// - "fstype"
/// - "itotal"
/// - "iused"
/// - "iavail"
/// - "ipcent"
/// - "size"
/// - "used"
/// - "avail"
/// - "pcent"
/// - "file"
/// - "target"
///
/// # Errors
///
/// If the string `s` is not one of the valid column names.
fn parse(s: &str) -> Result<Self, ()> {
match s {
"source" => Ok(Self::Source),
"fstype" => Ok(Self::Fstype),
"itotal" => Ok(Self::Itotal),
"iused" => Ok(Self::Iused),
"iavail" => Ok(Self::Iavail),
"ipcent" => Ok(Self::Ipcent),
"size" => Ok(Self::Size),
"used" => Ok(Self::Used),
"avail" => Ok(Self::Avail),
"pcent" => Ok(Self::Pcent),
"file" => Ok(Self::File),
"target" => Ok(Self::Target),
_ => Err(()),
}
}
}

View file

@ -183,4 +183,33 @@ fn test_block_size_1024() {
assert_eq!(get_header(34 * 1024 * 1024 * 1024), "34G-blocks");
}
// TODO The spacing does not match GNU df. Also we need to remove
// trailing spaces from the heading row.
#[test]
fn test_output_selects_columns() {
let output = new_ucmd!()
.args(&["--output=source"])
.succeeds()
.stdout_move_str();
assert_eq!(output.lines().next().unwrap(), "Filesystem ");
let output = new_ucmd!()
.args(&["--output=source,target"])
.succeeds()
.stdout_move_str();
assert_eq!(
output.lines().next().unwrap(),
"Filesystem Mounted on "
);
let output = new_ucmd!()
.args(&["--output=source,target,used"])
.succeeds()
.stdout_move_str();
assert_eq!(
output.lines().next().unwrap(),
"Filesystem Mounted on Used "
);
}
// ToDO: more tests...