mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 03:57:44 +00:00
df: implement the File column
Implement the "File" column in the `df` output table. Before this commit, a blank entry appeared in the "File" column for each row. After this commit, a "-" entry appears when `df` is run with no positional arguments and the filename appears when run with positional arguments. For example: $ touch a b c && df --output=target,file a b c Mounted on File / a / b / c
This commit is contained in:
parent
e1f8893289
commit
ab717ce370
4 changed files with 76 additions and 7 deletions
|
@ -243,7 +243,10 @@ fn get_all_filesystems(opt: &Options) -> Vec<Filesystem> {
|
||||||
|
|
||||||
// Convert each `MountInfo` into a `Filesystem`, which contains
|
// Convert each `MountInfo` into a `Filesystem`, which contains
|
||||||
// both the mount information and usage information.
|
// both the mount information and usage information.
|
||||||
mounts.into_iter().filter_map(Filesystem::new).collect()
|
mounts
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|m| Filesystem::new(m, None))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For each path, get the filesystem that contains that path.
|
/// For each path, get the filesystem that contains that path.
|
||||||
|
|
|
@ -23,6 +23,13 @@ use uucore::fsext::{FsUsage, MountInfo};
|
||||||
/// space available on the filesystem and the amount of space used.
|
/// space available on the filesystem and the amount of space used.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct Filesystem {
|
pub(crate) struct Filesystem {
|
||||||
|
/// The file given on the command line if any.
|
||||||
|
///
|
||||||
|
/// When invoking `df` with a positional argument, it displays
|
||||||
|
/// usage information for the filesystem that contains the given
|
||||||
|
/// file. If given, this field contains that filename.
|
||||||
|
pub file: Option<String>,
|
||||||
|
|
||||||
/// Information about the mounted device, mount directory, and related options.
|
/// Information about the mounted device, mount directory, and related options.
|
||||||
pub mount_info: MountInfo,
|
pub mount_info: MountInfo,
|
||||||
|
|
||||||
|
@ -66,7 +73,7 @@ where
|
||||||
|
|
||||||
impl Filesystem {
|
impl Filesystem {
|
||||||
// TODO: resolve uuid in `mount_info.dev_name` if exists
|
// TODO: resolve uuid in `mount_info.dev_name` if exists
|
||||||
pub(crate) fn new(mount_info: MountInfo) -> Option<Self> {
|
pub(crate) fn new(mount_info: MountInfo, file: Option<String>) -> Option<Self> {
|
||||||
let _stat_path = if !mount_info.mount_dir.is_empty() {
|
let _stat_path = if !mount_info.mount_dir.is_empty() {
|
||||||
mount_info.mount_dir.clone()
|
mount_info.mount_dir.clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -84,7 +91,11 @@ impl Filesystem {
|
||||||
let usage = FsUsage::new(statfs(_stat_path).ok()?);
|
let usage = FsUsage::new(statfs(_stat_path).ok()?);
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let usage = FsUsage::new(Path::new(&_stat_path));
|
let usage = FsUsage::new(Path::new(&_stat_path));
|
||||||
Some(Self { mount_info, usage })
|
Some(Self {
|
||||||
|
mount_info,
|
||||||
|
usage,
|
||||||
|
file,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find and create the filesystem that best matches a given path.
|
/// Find and create the filesystem that best matches a given path.
|
||||||
|
@ -107,11 +118,12 @@ impl Filesystem {
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
{
|
{
|
||||||
|
let file = path.as_ref().display().to_string();
|
||||||
let canonicalize = true;
|
let canonicalize = true;
|
||||||
let mount_info = mount_info_from_path(mounts, path, canonicalize)?;
|
let mount_info = mount_info_from_path(mounts, path, canonicalize)?;
|
||||||
// TODO Make it so that we do not need to clone the `mount_info`.
|
// TODO Make it so that we do not need to clone the `mount_info`.
|
||||||
let mount_info = (*mount_info).clone();
|
let mount_info = (*mount_info).clone();
|
||||||
Self::new(mount_info)
|
Self::new(mount_info, Some(file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,9 @@ use std::ops::AddAssign;
|
||||||
/// A row comprises several pieces of information, including the
|
/// A row comprises several pieces of information, including the
|
||||||
/// filesystem device, the mountpoint, the number of bytes used, etc.
|
/// filesystem device, the mountpoint, the number of bytes used, etc.
|
||||||
pub(crate) struct Row {
|
pub(crate) struct Row {
|
||||||
|
/// The filename given on the command-line, if given.
|
||||||
|
file: Option<String>,
|
||||||
|
|
||||||
/// Name of the device on which the filesystem lives.
|
/// Name of the device on which the filesystem lives.
|
||||||
fs_device: String,
|
fs_device: String,
|
||||||
|
|
||||||
|
@ -73,6 +76,7 @@ pub(crate) struct Row {
|
||||||
impl Row {
|
impl Row {
|
||||||
pub(crate) fn new(source: &str) -> Self {
|
pub(crate) fn new(source: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
file: None,
|
||||||
fs_device: source.into(),
|
fs_device: source.into(),
|
||||||
fs_type: "-".into(),
|
fs_type: "-".into(),
|
||||||
fs_mount: "-".into(),
|
fs_mount: "-".into(),
|
||||||
|
@ -101,6 +105,7 @@ impl AddAssign for Row {
|
||||||
let inodes = self.inodes + rhs.inodes;
|
let inodes = self.inodes + rhs.inodes;
|
||||||
let inodes_used = self.inodes_used + rhs.inodes_used;
|
let inodes_used = self.inodes_used + rhs.inodes_used;
|
||||||
*self = Self {
|
*self = Self {
|
||||||
|
file: None,
|
||||||
fs_device: "total".into(),
|
fs_device: "total".into(),
|
||||||
fs_type: "-".into(),
|
fs_type: "-".into(),
|
||||||
fs_mount: "-".into(),
|
fs_mount: "-".into(),
|
||||||
|
@ -145,6 +150,7 @@ impl From<Filesystem> for Row {
|
||||||
..
|
..
|
||||||
} = fs.usage;
|
} = fs.usage;
|
||||||
Self {
|
Self {
|
||||||
|
file: fs.file,
|
||||||
fs_device: dev_name,
|
fs_device: dev_name,
|
||||||
fs_type,
|
fs_type,
|
||||||
fs_mount: mount_dir,
|
fs_mount: mount_dir,
|
||||||
|
@ -246,8 +252,9 @@ impl fmt::Display for DisplayRow<'_> {
|
||||||
Column::Ipcent => {
|
Column::Ipcent => {
|
||||||
write!(f, "{0: >5} ", DisplayRow::percentage(self.row.inodes_usage))?;
|
write!(f, "{0: >5} ", DisplayRow::percentage(self.row.inodes_usage))?;
|
||||||
}
|
}
|
||||||
// TODO Implement this.
|
Column::File => {
|
||||||
Column::File => {}
|
write!(f, "{0: <16}", self.row.file.as_ref().unwrap_or(&"-".into()))?;
|
||||||
|
}
|
||||||
Column::Fstype => write!(f, "{0: <5} ", self.row.fs_type)?,
|
Column::Fstype => write!(f, "{0: <5} ", self.row.fs_type)?,
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Column::Capacity => write!(
|
Column::Capacity => write!(
|
||||||
|
@ -406,6 +413,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
file: Some("/path/to/file".to_string()),
|
||||||
fs_device: "my_device".to_string(),
|
fs_device: "my_device".to_string(),
|
||||||
fs_type: "my_type".to_string(),
|
fs_type: "my_type".to_string(),
|
||||||
fs_mount: "my_mount".to_string(),
|
fs_mount: "my_mount".to_string(),
|
||||||
|
@ -437,6 +445,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
file: Some("/path/to/file".to_string()),
|
||||||
fs_device: "my_device".to_string(),
|
fs_device: "my_device".to_string(),
|
||||||
fs_type: "my_type".to_string(),
|
fs_type: "my_type".to_string(),
|
||||||
fs_mount: "my_mount".to_string(),
|
fs_mount: "my_mount".to_string(),
|
||||||
|
@ -468,6 +477,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
file: Some("/path/to/file".to_string()),
|
||||||
fs_device: "my_device".to_string(),
|
fs_device: "my_device".to_string(),
|
||||||
fs_type: "my_type".to_string(),
|
fs_type: "my_type".to_string(),
|
||||||
fs_mount: "my_mount".to_string(),
|
fs_mount: "my_mount".to_string(),
|
||||||
|
@ -499,6 +509,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
file: Some("/path/to/file".to_string()),
|
||||||
fs_device: "my_device".to_string(),
|
fs_device: "my_device".to_string(),
|
||||||
fs_type: "my_type".to_string(),
|
fs_type: "my_type".to_string(),
|
||||||
fs_mount: "my_mount".to_string(),
|
fs_mount: "my_mount".to_string(),
|
||||||
|
@ -530,6 +541,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
file: Some("/path/to/file".to_string()),
|
||||||
fs_device: "my_device".to_string(),
|
fs_device: "my_device".to_string(),
|
||||||
fs_type: "my_type".to_string(),
|
fs_type: "my_type".to_string(),
|
||||||
fs_mount: "my_mount".to_string(),
|
fs_mount: "my_mount".to_string(),
|
||||||
|
@ -560,6 +572,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
file: Some("/path/to/file".to_string()),
|
||||||
fs_device: "my_device".to_string(),
|
fs_device: "my_device".to_string(),
|
||||||
fs_type: "my_type".to_string(),
|
fs_type: "my_type".to_string(),
|
||||||
fs_mount: "my_mount".to_string(),
|
fs_mount: "my_mount".to_string(),
|
||||||
|
|
|
@ -222,4 +222,45 @@ fn test_output_selects_columns() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDO: more tests...
|
// TODO Fix the spacing.
|
||||||
|
#[test]
|
||||||
|
fn test_output_file_all_filesystems() {
|
||||||
|
// When run with no positional arguments, `df` lets "-" represent
|
||||||
|
// the "File" entry for each row.
|
||||||
|
let output = new_ucmd!()
|
||||||
|
.arg("--output=file")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_move_str();
|
||||||
|
let mut lines = output.lines();
|
||||||
|
assert_eq!(lines.next().unwrap(), "File ");
|
||||||
|
for line in lines {
|
||||||
|
assert_eq!(line, "- ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Fix the spacing.
|
||||||
|
#[test]
|
||||||
|
fn test_output_file_specific_files() {
|
||||||
|
// Create three files.
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
at.touch("a");
|
||||||
|
at.touch("b");
|
||||||
|
at.touch("c");
|
||||||
|
|
||||||
|
// When run with positional arguments, the filesystems should
|
||||||
|
// appear in the "File" column.
|
||||||
|
let output = ucmd
|
||||||
|
.args(&["--output=file", "a", "b", "c"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_move_str();
|
||||||
|
let actual: Vec<&str> = output.lines().collect();
|
||||||
|
assert_eq!(
|
||||||
|
actual,
|
||||||
|
vec![
|
||||||
|
"File ",
|
||||||
|
"a ",
|
||||||
|
"b ",
|
||||||
|
"c "
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue