mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
Merge pull request #3182 from jfinkels/df-scale-by-block-size
df: correctly scale bytes by block size
This commit is contained in:
commit
6224a08978
2 changed files with 65 additions and 42 deletions
|
@ -61,6 +61,52 @@ struct FsSelector {
|
|||
exclude: HashSet<String>,
|
||||
}
|
||||
|
||||
/// A block size to use in condensing the display of a large number of bytes.
|
||||
///
|
||||
/// The [`Bytes`] variant represents a static block size. The
|
||||
/// [`HumanReadableDecimal`] and [`HumanReadableBinary`] variants
|
||||
/// represent dynamic block sizes: as the number of bytes increases,
|
||||
/// the divisor increases as well (for example, from 1 to 1,000 to
|
||||
/// 1,000,000 and so on in the case of [`HumanReadableDecimal`]).
|
||||
///
|
||||
/// The default variant is `Bytes(1024)`.
|
||||
enum BlockSize {
|
||||
/// A fixed number of bytes.
|
||||
///
|
||||
/// The number must be positive.
|
||||
Bytes(u64),
|
||||
|
||||
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||
///
|
||||
/// This variant represents powers of 1,000. Contrast with
|
||||
/// [`HumanReadableBinary`], which represents powers of 1,024.
|
||||
HumanReadableDecimal,
|
||||
|
||||
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||
///
|
||||
/// This variant represents powers of 1,000. Contrast with
|
||||
/// [`HumanReadableBinary`], which represents powers of 1,024.
|
||||
HumanReadableBinary,
|
||||
}
|
||||
|
||||
impl Default for BlockSize {
|
||||
fn default() -> Self {
|
||||
Self::Bytes(1024)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ArgMatches> for BlockSize {
|
||||
fn from(matches: &ArgMatches) -> Self {
|
||||
if matches.is_present(OPT_HUMAN_READABLE) {
|
||||
Self::HumanReadableBinary
|
||||
} else if matches.is_present(OPT_HUMAN_READABLE_2) {
|
||||
Self::HumanReadableDecimal
|
||||
} else {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Options {
|
||||
show_local_fs: bool,
|
||||
|
@ -68,8 +114,7 @@ struct Options {
|
|||
show_listed_fs: bool,
|
||||
show_fs_type: bool,
|
||||
show_inode_instead: bool,
|
||||
// block_size: usize,
|
||||
human_readable_base: i64,
|
||||
block_size: BlockSize,
|
||||
fs_selector: FsSelector,
|
||||
}
|
||||
|
||||
|
@ -82,13 +127,7 @@ impl Options {
|
|||
show_listed_fs: false,
|
||||
show_fs_type: matches.is_present(OPT_PRINT_TYPE),
|
||||
show_inode_instead: matches.is_present(OPT_INODES),
|
||||
human_readable_base: if matches.is_present(OPT_HUMAN_READABLE) {
|
||||
1024
|
||||
} else if matches.is_present(OPT_HUMAN_READABLE_2) {
|
||||
1000
|
||||
} else {
|
||||
-1
|
||||
},
|
||||
block_size: BlockSize::from(matches),
|
||||
fs_selector: FsSelector::from(matches),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//! [`DisplayRow`] implements [`std::fmt::Display`].
|
||||
use number_prefix::NumberPrefix;
|
||||
|
||||
use crate::{Filesystem, Options};
|
||||
use crate::{BlockSize, Filesystem, Options};
|
||||
use uucore::fsext::{FsUsage, MountInfo};
|
||||
|
||||
use std::fmt;
|
||||
|
@ -147,23 +147,10 @@ impl<'a> DisplayRow<'a> {
|
|||
///
|
||||
/// If the scaling factor is not 1000, 1024, or a negative number.
|
||||
fn scaled(&self, size: u64) -> Result<String, fmt::Error> {
|
||||
// TODO The argument-parsing code should be responsible for
|
||||
// ensuring that the `human_readable_base` number is
|
||||
// positive. Then we could remove the `Err` case from this
|
||||
// function.
|
||||
//
|
||||
// TODO We should not be using a negative number to indicate
|
||||
// default behavior. The default behavior for `df` is to show
|
||||
// sizes in blocks of 1K bytes each, so we should just do
|
||||
// that.
|
||||
//
|
||||
// TODO Support arbitrary positive scaling factors (from the
|
||||
// `--block-size` command-line argument).
|
||||
let number_prefix = match self.options.human_readable_base {
|
||||
1000 => NumberPrefix::decimal(size as f64),
|
||||
1024 => NumberPrefix::binary(size as f64),
|
||||
d if d < 0 => return Ok(size.to_string()),
|
||||
_ => return Err(fmt::Error {}),
|
||||
let number_prefix = match self.options.block_size {
|
||||
BlockSize::HumanReadableDecimal => NumberPrefix::decimal(size as f64),
|
||||
BlockSize::HumanReadableBinary => NumberPrefix::binary(size as f64),
|
||||
BlockSize::Bytes(d) => return Ok((size / d).to_string()),
|
||||
};
|
||||
match number_prefix {
|
||||
NumberPrefix::Standalone(bytes) => Ok(bytes.to_string()),
|
||||
|
@ -261,7 +248,9 @@ impl fmt::Display for Header<'_> {
|
|||
write!(f, "{0: >12} ", "IFree")?;
|
||||
write!(f, "{0: >5} ", "IUse%")?;
|
||||
} else {
|
||||
if self.options.human_readable_base == -1 {
|
||||
// TODO Support arbitrary positive scaling factors (from
|
||||
// the `--block-size` command-line argument).
|
||||
if let BlockSize::Bytes(_) = self.options.block_size {
|
||||
write!(f, "{0: >12} ", "1k-blocks")?;
|
||||
} else {
|
||||
write!(f, "{0: >12} ", "Size")?;
|
||||
|
@ -281,14 +270,11 @@ impl fmt::Display for Header<'_> {
|
|||
mod tests {
|
||||
|
||||
use crate::table::{DisplayRow, Header, Row};
|
||||
use crate::Options;
|
||||
use crate::{BlockSize, Options};
|
||||
|
||||
#[test]
|
||||
fn test_header_display() {
|
||||
let options = Options {
|
||||
human_readable_base: -1,
|
||||
..Default::default()
|
||||
};
|
||||
let options = Default::default();
|
||||
assert_eq!(
|
||||
Header::new(&options).to_string(),
|
||||
"Filesystem 1k-blocks Used Available Use% Mounted on "
|
||||
|
@ -298,7 +284,6 @@ mod tests {
|
|||
#[test]
|
||||
fn test_header_display_fs_type() {
|
||||
let options = Options {
|
||||
human_readable_base: -1,
|
||||
show_fs_type: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -311,7 +296,6 @@ mod tests {
|
|||
#[test]
|
||||
fn test_header_display_inode() {
|
||||
let options = Options {
|
||||
human_readable_base: -1,
|
||||
show_inode_instead: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -324,7 +308,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_header_display_human_readable_binary() {
|
||||
let options = Options {
|
||||
human_readable_base: 1024,
|
||||
block_size: BlockSize::HumanReadableBinary,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
|
@ -336,7 +320,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_header_display_human_readable_si() {
|
||||
let options = Options {
|
||||
human_readable_base: 1000,
|
||||
block_size: BlockSize::HumanReadableDecimal,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
|
@ -348,7 +332,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_row_display() {
|
||||
let options = Options {
|
||||
human_readable_base: -1,
|
||||
block_size: BlockSize::Bytes(1),
|
||||
..Default::default()
|
||||
};
|
||||
let row = Row {
|
||||
|
@ -378,7 +362,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_row_display_fs_type() {
|
||||
let options = Options {
|
||||
human_readable_base: -1,
|
||||
block_size: BlockSize::Bytes(1),
|
||||
show_fs_type: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -409,7 +393,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_row_display_inodes() {
|
||||
let options = Options {
|
||||
human_readable_base: -1,
|
||||
block_size: BlockSize::Bytes(1),
|
||||
show_inode_instead: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -440,7 +424,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_row_display_human_readable_si() {
|
||||
let options = Options {
|
||||
human_readable_base: 1000,
|
||||
block_size: BlockSize::HumanReadableDecimal,
|
||||
show_fs_type: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -471,7 +455,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_row_display_human_readable_binary() {
|
||||
let options = Options {
|
||||
human_readable_base: 1024,
|
||||
block_size: BlockSize::HumanReadableBinary,
|
||||
show_fs_type: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue