mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
Merge branch 'main' into mktemp-set-dir-mode
This commit is contained in:
@@ -9,3 +9,12 @@ rustflags = [
|
||||
"-Wclippy::single_char_pattern",
|
||||
"-Wclippy::explicit_iter_loop",
|
||||
]
|
||||
|
||||
[build]
|
||||
# See https://github.com/time-rs/time/issues/293#issuecomment-1005002386. The
|
||||
# unsoundness here is not in the `time` library, but in the Rust stdlib, and as
|
||||
# such it needs to be fixed there.
|
||||
rustflags = "--cfg unsound_local_offset"
|
||||
|
||||
[target.'cfg(target_os = "linux")']
|
||||
rustflags = ["--cfg", "unsound_local_offset"]
|
||||
|
||||
@@ -5,3 +5,8 @@ updates:
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 5
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 5
|
||||
|
||||
@@ -384,9 +384,9 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -p uucore -p coreutils
|
||||
args: -v ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -p uucore -p coreutils
|
||||
env:
|
||||
RUSTFLAGS: "-Awarnings"
|
||||
RUSTFLAGS: "-Awarnings --cfg unsound_local_offset"
|
||||
|
||||
deps:
|
||||
name: Dependencies
|
||||
|
||||
@@ -8,6 +8,10 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
gnu:
|
||||
permissions:
|
||||
actions: read # for dawidd6/action-download-artifact to query and download artifacts
|
||||
contents: read # for actions/checkout to fetch code
|
||||
pull-requests: read # for dawidd6/action-download-artifact to query commit hash
|
||||
name: Run GNU tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -170,6 +174,8 @@ jobs:
|
||||
REPO_DEFAULT_BRANCH='${{ steps.vars.outputs.repo_default_branch }}'
|
||||
if test -f "${REF_LOG_FILE}"; then
|
||||
echo "Reference SHA1/ID: $(sha1sum -- "${REF_SUMMARY_FILE}")"
|
||||
REF_ERROR=$(sed -n "s/^ERROR: \([[:print:]]\+\).*/\1/p" "${REF_LOG_FILE}" | sort)
|
||||
NEW_ERROR=$(sed -n "s/^ERROR: \([[:print:]]\+\).*/\1/p" '${{ steps.vars.outputs.path_GNU_tests }}/test-suite.log' | sort)
|
||||
REF_FAILING=$(sed -n "s/^FAIL: \([[:print:]]\+\).*/\1/p" "${REF_LOG_FILE}" | sort)
|
||||
NEW_FAILING=$(sed -n "s/^FAIL: \([[:print:]]\+\).*/\1/p" '${{ steps.vars.outputs.path_GNU_tests }}/test-suite.log' | sort)
|
||||
for LINE in ${REF_FAILING}
|
||||
@@ -186,6 +192,21 @@ jobs:
|
||||
have_new_failures="true"
|
||||
fi
|
||||
done
|
||||
for LINE in ${REF_ERROR}
|
||||
do
|
||||
if ! grep -Fxq ${LINE}<<<"${NEW_ERROR}"; then
|
||||
echo "::warning ::Congrats! The gnu test ${LINE} is no longer ERROR!"
|
||||
fi
|
||||
done
|
||||
for LINE in ${NEW_ERROR}
|
||||
do
|
||||
if ! grep -Fxq ${LINE}<<<"${REF_ERROR}"
|
||||
then
|
||||
echo "::error ::GNU test error: ${LINE}. ${LINE} is passing on '${{ steps.vars.outputs.repo_default_branch }}'. Maybe you have to rebase?"
|
||||
have_new_failures="true"
|
||||
fi
|
||||
done
|
||||
|
||||
else
|
||||
echo "::warning ::Skipping test failure comparison; no prior reference test logs are available."
|
||||
fi
|
||||
|
||||
Generated
+177
-142
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -391,7 +391,7 @@ rand = "0.8"
|
||||
regex = "1.5"
|
||||
sha1 = { version="0.10", features=["std"] }
|
||||
tempfile = "3"
|
||||
time = "0.1"
|
||||
time = {version="0.3", features=["local-offset"]}
|
||||
unindent = "0.1"
|
||||
uucore = { version=">=0.0.11", package="uucore", path="src/uucore", features=["entries", "process"] }
|
||||
walkdir = "2.2"
|
||||
|
||||
@@ -11,6 +11,8 @@ unmaintained = "warn"
|
||||
yanked = "warn"
|
||||
notice = "warn"
|
||||
ignore = [
|
||||
"RUSTSEC-2020-0159",
|
||||
"RUSTSEC-2020-0071",
|
||||
#"RUSTSEC-0000-0000",
|
||||
]
|
||||
|
||||
@@ -62,7 +64,7 @@ highlight = "all"
|
||||
# spell-checker: disable
|
||||
skip = [
|
||||
# getrandom
|
||||
{ name = "wasi", version="0.10.2+wasi-snapshot-preview1" },
|
||||
{ name = "wasi", version="0.10.0+wasi-snapshot-preview1" },
|
||||
# blake2d_simd
|
||||
{ name = "arrayvec", version = "=0.7.2" },
|
||||
# flimit/unix_socket
|
||||
@@ -84,6 +86,8 @@ skip = [
|
||||
{ name = "memchr", version = "=1.0.2" },
|
||||
{ name = "quote", version = "=0.3.15" },
|
||||
{ name = "unicode-xid", version = "=0.0.4" },
|
||||
# chrono
|
||||
{ name = "time", version = "=0.1.44" },
|
||||
]
|
||||
# spell-checker: enable
|
||||
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ utilities in [Rust](https://www.rust-lang.org). It is available for
|
||||
Linux, Windows, Mac and other platforms.
|
||||
|
||||
The API reference for `uucore`, the library of functions shared between
|
||||
various utils, is hosted at at
|
||||
various utils, is hosted at
|
||||
[docs.rs](https://docs.rs/uucore/latest/uucore/).
|
||||
|
||||
uutils is licensed under the [MIT License](https://github.com/uutils/coreutils/blob/main/LICENSE).
|
||||
@@ -17,4 +17,4 @@ uutils is licensed under the [MIT License](https://github.com/uutils/coreutils/b
|
||||
* [Discord](https://discord.gg/wQVJbvJ)
|
||||
|
||||
> Note: This manual is automatically generated from the source code and is
|
||||
> a work in progress.
|
||||
> a work in progress.
|
||||
|
||||
@@ -90,7 +90,7 @@ pub fn parse_base_cmd_args(args: impl uucore::Args, about: &str, usage: &str) ->
|
||||
let arg_list = args
|
||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||
.accept_any();
|
||||
Config::from(&command.get_matches_from(arg_list))
|
||||
Config::from(&command.try_get_matches_from(arg_list)?)
|
||||
}
|
||||
|
||||
pub fn base_app<'a>(about: &'a str, usage: &'a str) -> Command<'a> {
|
||||
|
||||
@@ -188,7 +188,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
.collect_str(InvalidEncodingHandling::Ignore)
|
||||
.accept_any();
|
||||
|
||||
let matches = uu_app().get_matches_from(args);
|
||||
let matches = uu_app().try_get_matches_from(args)?;
|
||||
|
||||
let number_mode = if matches.is_present(options::NUMBER_NONBLANK) {
|
||||
NumberingMode::NonEmpty
|
||||
|
||||
@@ -16,7 +16,7 @@ path = "src/chmod.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||
libc = "0.2.124"
|
||||
libc = "0.2.125"
|
||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["fs", "mode"] }
|
||||
|
||||
[[bin]]
|
||||
|
||||
@@ -21,7 +21,7 @@ path = "src/cp.rs"
|
||||
[dependencies]
|
||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||
filetime = "0.2"
|
||||
libc = "0.2.124"
|
||||
libc = "0.2.125"
|
||||
quick-error = "2.0.1"
|
||||
selinux = { version="0.2", optional=true }
|
||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["entries", "fs", "perms", "mode"] }
|
||||
@@ -34,7 +34,7 @@ ioctl-sys = "0.8"
|
||||
winapi = { version="0.3", features=["fileapi"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
xattr="0.2.1"
|
||||
xattr="0.2.3"
|
||||
exacl= { version = "0.8.0", optional=true }
|
||||
|
||||
[[bin]]
|
||||
|
||||
+9
-6
@@ -57,7 +57,7 @@ use std::path::{Path, PathBuf, StripPrefixError};
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use uucore::backup_control::{self, BackupMode};
|
||||
use uucore::error::{set_exit_code, ExitCode, UError, UResult};
|
||||
use uucore::error::{set_exit_code, ExitCode, UClapError, UError, UResult};
|
||||
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
@@ -485,7 +485,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
app.print_help()?;
|
||||
}
|
||||
clap::ErrorKind::DisplayVersion => println!("{}", app.render_version()),
|
||||
_ => return Err(Box::new(e)),
|
||||
_ => return Err(Box::new(e.with_exit_code(1))),
|
||||
};
|
||||
} else if let Ok(matches) = matches {
|
||||
let options = Options::from_matches(&matches)?;
|
||||
@@ -992,7 +992,9 @@ fn copy_directory(
|
||||
}
|
||||
|
||||
// if no-dereference is enabled and this is a symlink, copy it as a file
|
||||
if !options.dereference && fs::symlink_metadata(root).unwrap().file_type().is_symlink() {
|
||||
if !options.dereference && fs::symlink_metadata(root).unwrap().file_type().is_symlink()
|
||||
// replace by is_symlink in rust>=1.58
|
||||
{
|
||||
return copy_file(root, target, options, symlinked_files);
|
||||
}
|
||||
|
||||
@@ -1036,6 +1038,7 @@ fn copy_directory(
|
||||
{
|
||||
let p = or_continue!(path);
|
||||
let is_symlink = fs::symlink_metadata(p.path())?.file_type().is_symlink();
|
||||
// replace by is_symlink in rust >=1.58
|
||||
let path = current_dir.join(&p.path());
|
||||
|
||||
let local_to_root_parent = match root_parent {
|
||||
@@ -1288,7 +1291,7 @@ fn copy_file(
|
||||
|
||||
// Fail if dest is a dangling symlink or a symlink this program created previously
|
||||
if fs::symlink_metadata(dest)
|
||||
.map(|m| m.file_type().is_symlink())
|
||||
.map(|m| m.file_type().is_symlink()) // replace by is_symlink in rust>=1.58
|
||||
.unwrap_or(false)
|
||||
{
|
||||
if FileInformation::from_path(dest, false)
|
||||
@@ -1301,7 +1304,7 @@ fn copy_file(
|
||||
dest.display()
|
||||
)));
|
||||
}
|
||||
if !dest.exists() {
|
||||
if options.dereference && !dest.exists() {
|
||||
return Err(Error::Error(format!(
|
||||
"not writing through dangling symlink '{}'",
|
||||
dest.display()
|
||||
@@ -1535,7 +1538,7 @@ fn copy_link(
|
||||
} else {
|
||||
// we always need to remove the file to be able to create a symlink,
|
||||
// even if it is writeable.
|
||||
if dest.exists() {
|
||||
if dest.is_file() {
|
||||
fs::remove_file(dest)?;
|
||||
}
|
||||
dest.into()
|
||||
|
||||
+139
-67
@@ -3,9 +3,9 @@
|
||||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
//! Types for representing and displaying block sizes.
|
||||
use crate::{OPT_BLOCKSIZE, OPT_HUMAN_READABLE_BINARY, OPT_HUMAN_READABLE_DECIMAL};
|
||||
use crate::OPT_BLOCKSIZE;
|
||||
use clap::ArgMatches;
|
||||
use std::fmt;
|
||||
use std::{env, fmt};
|
||||
|
||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||
|
||||
@@ -26,6 +26,22 @@ const IEC_BASES: [u128; 10] = [
|
||||
/// Suffixes for the first nine multi-byte unit suffixes.
|
||||
const SUFFIXES: [char; 9] = ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
|
||||
|
||||
const SI_BASES: [u128; 10] = [
|
||||
1,
|
||||
1_000,
|
||||
1_000_000,
|
||||
1_000_000_000,
|
||||
1_000_000_000_000,
|
||||
1_000_000_000_000_000,
|
||||
1_000_000_000_000_000_000,
|
||||
1_000_000_000_000_000_000_000,
|
||||
1_000_000_000_000_000_000_000_000,
|
||||
1_000_000_000_000_000_000_000_000_000,
|
||||
];
|
||||
|
||||
// we use "kB" instead of "KB" because of GNU df
|
||||
const SI_SUFFIXES: [&str; 9] = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
|
||||
/// Convert a multiple of 1024 into a string like "12K" or "34M".
|
||||
///
|
||||
/// # Examples
|
||||
@@ -57,63 +73,112 @@ fn to_magnitude_and_suffix_1024(n: u128) -> Result<String, ()> {
|
||||
Err(())
|
||||
}
|
||||
|
||||
/// Convert a number into a string like "12kB" or "34MB".
|
||||
///
|
||||
/// Powers of 1000 become "1kB", "1MB", "1GB", etc.
|
||||
///
|
||||
/// The returned string has a maximum length of 5 chars, for example: "1.1kB", "999kB", "1MB".
|
||||
fn to_magnitude_and_suffix_not_powers_of_1024(n: u128) -> Result<String, ()> {
|
||||
let mut i = 0;
|
||||
|
||||
while SI_BASES[i + 1] - SI_BASES[i] < n && i < SI_SUFFIXES.len() {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let quot = n / SI_BASES[i];
|
||||
let rem = n % SI_BASES[i];
|
||||
let suffix = SI_SUFFIXES[i];
|
||||
|
||||
if rem == 0 {
|
||||
Ok(format!("{}{}", quot, suffix))
|
||||
} else {
|
||||
let tenths_place = rem / (SI_BASES[i] / 10);
|
||||
|
||||
if rem % (SI_BASES[i] / 10) == 0 {
|
||||
Ok(format!("{}.{}{}", quot, tenths_place, suffix))
|
||||
} else if tenths_place + 1 == 10 {
|
||||
Ok(format!("{}{}", quot + 1, suffix))
|
||||
} else {
|
||||
Ok(format!("{}.{}{}", quot, tenths_place + 1, suffix))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a number into a magnitude and a multi-byte unit suffix.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the number is too large to represent.
|
||||
fn to_magnitude_and_suffix(n: u128) -> Result<String, ()> {
|
||||
if n % 1024 == 0 {
|
||||
if n % 1024 == 0 && n % 1000 != 0 {
|
||||
to_magnitude_and_suffix_1024(n)
|
||||
} else {
|
||||
// TODO Implement this, probably using code from `numfmt`.
|
||||
Ok("1kB".into())
|
||||
to_magnitude_and_suffix_not_powers_of_1024(n)
|
||||
}
|
||||
}
|
||||
|
||||
/// A mode to use in condensing the display of a large number of bytes.
|
||||
pub(crate) enum SizeFormat {
|
||||
HumanReadable(HumanReadable),
|
||||
StaticBlockSize,
|
||||
}
|
||||
|
||||
impl Default for SizeFormat {
|
||||
fn default() -> Self {
|
||||
Self::StaticBlockSize
|
||||
}
|
||||
}
|
||||
|
||||
/// A mode to use in condensing the human readable display of a large number
|
||||
/// of bytes.
|
||||
///
|
||||
/// The [`HumanReadable::Decimal`] and[`HumanReadable::Binary`] 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 [`HumanReadable::Decimal`]).
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum HumanReadable {
|
||||
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||
///
|
||||
/// This variant represents powers of 1,000. Contrast with
|
||||
/// [`HumanReadable::Binary`], which represents powers of
|
||||
/// 1,024.
|
||||
Decimal,
|
||||
|
||||
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||
///
|
||||
/// This variant represents powers of 1,024. Contrast with
|
||||
/// [`HumanReadable::Decimal`], which represents powers
|
||||
/// of 1,000.
|
||||
Binary,
|
||||
}
|
||||
|
||||
/// A block size to use in condensing the display of a large number of bytes.
|
||||
///
|
||||
/// The [`BlockSize::Bytes`] variant represents a static block
|
||||
/// size. The [`BlockSize::HumanReadableDecimal`] and
|
||||
/// [`BlockSize::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 [`BlockSize::HumanReadableDecimal`]).
|
||||
/// size.
|
||||
///
|
||||
/// The default variant is `Bytes(1024)`.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) 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
|
||||
/// [`BlockSize::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,024. Contrast with
|
||||
/// [`BlockSize::HumanReadableDecimal`], which represents powers
|
||||
/// of 1,000.
|
||||
HumanReadableBinary,
|
||||
}
|
||||
|
||||
impl Default for BlockSize {
|
||||
fn default() -> Self {
|
||||
Self::Bytes(1024)
|
||||
if env::var("POSIXLY_CORRECT").is_ok() {
|
||||
Self::Bytes(512)
|
||||
} else {
|
||||
Self::Bytes(1024)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn block_size_from_matches(matches: &ArgMatches) -> Result<BlockSize, ParseSizeError> {
|
||||
if matches.is_present(OPT_HUMAN_READABLE_BINARY) {
|
||||
Ok(BlockSize::HumanReadableBinary)
|
||||
} else if matches.is_present(OPT_HUMAN_READABLE_DECIMAL) {
|
||||
Ok(BlockSize::HumanReadableDecimal)
|
||||
} else if matches.is_present(OPT_BLOCKSIZE) {
|
||||
if matches.is_present(OPT_BLOCKSIZE) {
|
||||
let s = matches.value_of(OPT_BLOCKSIZE).unwrap();
|
||||
Ok(BlockSize::Bytes(parse_size(s)?))
|
||||
} else {
|
||||
@@ -124,10 +189,8 @@ pub(crate) fn block_size_from_matches(matches: &ArgMatches) -> Result<BlockSize,
|
||||
impl fmt::Display for BlockSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::HumanReadableBinary => write!(f, "Size"),
|
||||
Self::HumanReadableDecimal => write!(f, "Size"),
|
||||
Self::Bytes(n) => match to_magnitude_and_suffix(*n as u128) {
|
||||
Ok(s) => write!(f, "{}-blocks", s),
|
||||
Ok(s) => write!(f, "{}", s),
|
||||
Err(_) => Err(fmt::Error),
|
||||
},
|
||||
}
|
||||
@@ -137,6 +200,8 @@ impl fmt::Display for BlockSize {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::env;
|
||||
|
||||
use crate::blocks::{to_magnitude_and_suffix, BlockSize};
|
||||
|
||||
#[test]
|
||||
@@ -153,46 +218,53 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO We have not yet implemented this behavior, but when we do,
|
||||
// uncomment this test.
|
||||
#[test]
|
||||
fn test_to_magnitude_and_suffix_not_powers_of_1024() {
|
||||
assert_eq!(to_magnitude_and_suffix(1).unwrap(), "1B");
|
||||
assert_eq!(to_magnitude_and_suffix(999).unwrap(), "999B");
|
||||
|
||||
// #[test]
|
||||
// fn test_to_magnitude_and_suffix_not_powers_of_1024() {
|
||||
// assert_eq!(to_magnitude_and_suffix(1).unwrap(), "1B");
|
||||
// assert_eq!(to_magnitude_and_suffix(999).unwrap(), "999B");
|
||||
assert_eq!(to_magnitude_and_suffix(1000).unwrap(), "1kB");
|
||||
assert_eq!(to_magnitude_and_suffix(1001).unwrap(), "1.1kB");
|
||||
assert_eq!(to_magnitude_and_suffix(1023).unwrap(), "1.1kB");
|
||||
assert_eq!(to_magnitude_and_suffix(1025).unwrap(), "1.1kB");
|
||||
assert_eq!(to_magnitude_and_suffix(999_000).unwrap(), "999kB");
|
||||
|
||||
// assert_eq!(to_magnitude_and_suffix(1000).unwrap(), "1kB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1001).unwrap(), "1.1kB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1023).unwrap(), "1.1kB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1025).unwrap(), "1.1kB");
|
||||
// assert_eq!(to_magnitude_and_suffix(999_000).unwrap(), "999kB");
|
||||
assert_eq!(to_magnitude_and_suffix(999_001).unwrap(), "1MB");
|
||||
assert_eq!(to_magnitude_and_suffix(999_999).unwrap(), "1MB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_000_000).unwrap(), "1MB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_000_001).unwrap(), "1.1MB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_100_000).unwrap(), "1.1MB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_100_001).unwrap(), "1.2MB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_900_000).unwrap(), "1.9MB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_900_001).unwrap(), "2MB");
|
||||
assert_eq!(to_magnitude_and_suffix(9_900_000).unwrap(), "9.9MB");
|
||||
assert_eq!(to_magnitude_and_suffix(9_900_001).unwrap(), "10MB");
|
||||
assert_eq!(to_magnitude_and_suffix(999_000_000).unwrap(), "999MB");
|
||||
|
||||
// assert_eq!(to_magnitude_and_suffix(999_001).unwrap(), "1MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(999_999).unwrap(), "1MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1_000_000).unwrap(), "1MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1_000_001).unwrap(), "1.1MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1_100_000).unwrap(), "1.1MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1_100_001).unwrap(), "1.2MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1_900_000).unwrap(), "1.9MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1_900_001).unwrap(), "2MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(9_900_000).unwrap(), "9.9MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(9_900_001).unwrap(), "10MB");
|
||||
// assert_eq!(to_magnitude_and_suffix(999_000_000).unwrap(), "999MB");
|
||||
assert_eq!(to_magnitude_and_suffix(999_000_001).unwrap(), "1GB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_000_000_000).unwrap(), "1GB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_000_000_001).unwrap(), "1.1GB");
|
||||
}
|
||||
|
||||
// assert_eq!(to_magnitude_and_suffix(999_000_001).unwrap(), "1GB");
|
||||
// assert_eq!(to_magnitude_and_suffix(1_000_000_000).unwrap(), "1GB");
|
||||
// // etc.
|
||||
// }
|
||||
#[test]
|
||||
fn test_to_magnitude_and_suffix_multiples_of_1000_and_1024() {
|
||||
assert_eq!(to_magnitude_and_suffix(128_000).unwrap(), "128kB");
|
||||
assert_eq!(to_magnitude_and_suffix(1000 * 1024).unwrap(), "1.1MB");
|
||||
assert_eq!(to_magnitude_and_suffix(1_000_000_000_000).unwrap(), "1TB");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_size_display() {
|
||||
assert_eq!(format!("{}", BlockSize::HumanReadableBinary), "Size");
|
||||
assert_eq!(format!("{}", BlockSize::HumanReadableDecimal), "Size");
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(1024)), "1K-blocks");
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(2 * 1024)), "2K-blocks");
|
||||
assert_eq!(
|
||||
format!("{}", BlockSize::Bytes(3 * 1024 * 1024)),
|
||||
"3M-blocks"
|
||||
);
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(1024)), "1K");
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(2 * 1024)), "2K");
|
||||
assert_eq!(format!("{}", BlockSize::Bytes(3 * 1024 * 1024)), "3M");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_block_size() {
|
||||
assert_eq!(BlockSize::Bytes(1024), BlockSize::default());
|
||||
env::set_var("POSIXLY_CORRECT", "1");
|
||||
assert_eq!(BlockSize::Bytes(512), BlockSize::default());
|
||||
env::remove_var("POSIXLY_CORRECT");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ impl Column {
|
||||
match column {
|
||||
// 14 = length of "Filesystem" plus 4 spaces
|
||||
Self::Source => 14,
|
||||
Self::Used => 5,
|
||||
// the shortest headers have a length of 4 chars so we use that as the minimum width
|
||||
_ => 4,
|
||||
}
|
||||
|
||||
+40
-7
@@ -11,9 +11,11 @@ mod columns;
|
||||
mod filesystem;
|
||||
mod table;
|
||||
|
||||
use blocks::{HumanReadable, SizeFormat};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{UError, UResult, USimpleError};
|
||||
use uucore::fsext::{read_fs_list, MountInfo};
|
||||
use uucore::parse_size::ParseSizeError;
|
||||
use uucore::{format_usage, show};
|
||||
|
||||
use clap::{crate_version, Arg, ArgMatches, Command};
|
||||
@@ -30,6 +32,13 @@ use crate::table::Table;
|
||||
static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
|
||||
or all file systems by default.";
|
||||
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||
const LONG_HELP: &str = "Display values are in units of the first available SIZE from --block-size,
|
||||
and the DF_BLOCK_SIZE, BLOCK_SIZE and BLOCKSIZE environment variables.
|
||||
Otherwise, units default to 1024 bytes (or 512 if POSIXLY_CORRECT is set).
|
||||
|
||||
SIZE is an integer and optional unit (example: 10M is 10*1024*1024).
|
||||
Units are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB,... (powers
|
||||
of 1000).";
|
||||
|
||||
static OPT_HELP: &str = "help";
|
||||
static OPT_ALL: &str = "all";
|
||||
@@ -61,6 +70,7 @@ static OUTPUT_FIELD_LIST: [&str; 12] = [
|
||||
struct Options {
|
||||
show_local_fs: bool,
|
||||
show_all_fs: bool,
|
||||
size_format: SizeFormat,
|
||||
block_size: BlockSize,
|
||||
|
||||
/// Optional list of filesystem types to include in the output table.
|
||||
@@ -88,6 +98,7 @@ impl Default for Options {
|
||||
show_local_fs: Default::default(),
|
||||
show_all_fs: Default::default(),
|
||||
block_size: Default::default(),
|
||||
size_format: Default::default(),
|
||||
include: Default::default(),
|
||||
exclude: Default::default(),
|
||||
show_total: Default::default(),
|
||||
@@ -105,7 +116,8 @@ impl Default for Options {
|
||||
|
||||
#[derive(Debug)]
|
||||
enum OptionsError {
|
||||
InvalidBlockSize,
|
||||
BlockSizeTooLarge(String),
|
||||
InvalidBlockSize(String),
|
||||
|
||||
/// An error getting the columns to display in the output table.
|
||||
ColumnError(ColumnError),
|
||||
@@ -116,11 +128,14 @@ enum OptionsError {
|
||||
impl fmt::Display for OptionsError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
// TODO This should include the raw string provided as the argument.
|
||||
//
|
||||
// TODO This needs to vary based on whether `--block-size`
|
||||
// or `-B` were provided.
|
||||
Self::InvalidBlockSize => write!(f, "invalid --block-size argument"),
|
||||
Self::BlockSizeTooLarge(s) => {
|
||||
write!(f, "--block-size argument {} too large", s.quote())
|
||||
}
|
||||
// TODO This needs to vary based on whether `--block-size`
|
||||
// or `-B` were provided.
|
||||
Self::InvalidBlockSize(s) => write!(f, "invalid --block-size argument {}", s),
|
||||
Self::ColumnError(ColumnError::MultipleColumns(s)) => write!(
|
||||
f,
|
||||
"option --output: field {} used more than once",
|
||||
@@ -155,8 +170,21 @@ impl Options {
|
||||
Ok(Self {
|
||||
show_local_fs: matches.is_present(OPT_LOCAL),
|
||||
show_all_fs: matches.is_present(OPT_ALL),
|
||||
block_size: block_size_from_matches(matches)
|
||||
.map_err(|_| OptionsError::InvalidBlockSize)?,
|
||||
block_size: block_size_from_matches(matches).map_err(|e| match e {
|
||||
ParseSizeError::SizeTooBig(_) => OptionsError::BlockSizeTooLarge(
|
||||
matches.value_of(OPT_BLOCKSIZE).unwrap().to_string(),
|
||||
),
|
||||
ParseSizeError::ParseFailure(s) => OptionsError::InvalidBlockSize(s),
|
||||
})?,
|
||||
size_format: {
|
||||
if matches.is_present(OPT_HUMAN_READABLE_BINARY) {
|
||||
SizeFormat::HumanReadable(HumanReadable::Binary)
|
||||
} else if matches.is_present(OPT_HUMAN_READABLE_DECIMAL) {
|
||||
SizeFormat::HumanReadable(HumanReadable::Decimal)
|
||||
} else {
|
||||
SizeFormat::StaticBlockSize
|
||||
}
|
||||
},
|
||||
include,
|
||||
exclude,
|
||||
show_total: matches.is_present(OPT_TOTAL),
|
||||
@@ -406,6 +434,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.after_help(LONG_HELP)
|
||||
.infer_long_args(true)
|
||||
.arg(
|
||||
Arg::new(OPT_HELP)
|
||||
@@ -424,6 +453,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||
.short('B')
|
||||
.long("block-size")
|
||||
.takes_value(true)
|
||||
.value_name("SIZE")
|
||||
.overrides_with_all(&[OPT_KILO, OPT_BLOCKSIZE])
|
||||
.help(
|
||||
"scale sizes by SIZE before printing them; e.g.\
|
||||
@@ -480,6 +510,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||
Arg::new(OPT_OUTPUT)
|
||||
.long("output")
|
||||
.takes_value(true)
|
||||
.value_name("FIELD_LIST")
|
||||
.min_values(0)
|
||||
.require_equals(true)
|
||||
.use_value_delimiter(true)
|
||||
@@ -489,7 +520,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||
.default_values(&["source", "size", "used", "avail", "pcent", "target"])
|
||||
.conflicts_with_all(&[OPT_INODES, OPT_PORTABILITY, OPT_PRINT_TYPE])
|
||||
.help(
|
||||
"use the output format defined by FIELD_LIST,\
|
||||
"use the output format defined by FIELD_LIST, \
|
||||
or print all fields if FIELD_LIST is omitted.",
|
||||
),
|
||||
)
|
||||
@@ -512,6 +543,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||
.long("type")
|
||||
.allow_invalid_utf8(true)
|
||||
.takes_value(true)
|
||||
.value_name("TYPE")
|
||||
.multiple_occurrences(true)
|
||||
.help("limit listing to file systems of type TYPE"),
|
||||
)
|
||||
@@ -528,6 +560,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||
.long("exclude-type")
|
||||
.allow_invalid_utf8(true)
|
||||
.takes_value(true)
|
||||
.value_name("TYPE")
|
||||
.use_value_delimiter(true)
|
||||
.multiple_occurrences(true)
|
||||
.help("limit listing to file systems not of type TYPE"),
|
||||
|
||||
+59
-101
@@ -10,6 +10,7 @@
|
||||
use number_prefix::NumberPrefix;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::blocks::{HumanReadable, SizeFormat};
|
||||
use crate::columns::{Alignment, Column};
|
||||
use crate::filesystem::Filesystem;
|
||||
use crate::{BlockSize, Options};
|
||||
@@ -213,15 +214,10 @@ impl<'a> RowFormatter<'a> {
|
||||
}
|
||||
|
||||
/// Get a human readable string giving the scaled version of the input number.
|
||||
///
|
||||
/// The scaling factor is defined in the `options` field.
|
||||
///
|
||||
/// This function is supposed to be used by `scaled_bytes()` and `scaled_inodes()` only.
|
||||
fn scaled_human_readable(&self, size: u64) -> String {
|
||||
let number_prefix = match self.options.block_size {
|
||||
BlockSize::HumanReadableDecimal => NumberPrefix::decimal(size as f64),
|
||||
BlockSize::HumanReadableBinary => NumberPrefix::binary(size as f64),
|
||||
_ => unreachable!(),
|
||||
fn scaled_human_readable(&self, size: u64, human_readable: HumanReadable) -> String {
|
||||
let number_prefix = match human_readable {
|
||||
HumanReadable::Decimal => NumberPrefix::decimal(size as f64),
|
||||
HumanReadable::Binary => NumberPrefix::binary(size as f64),
|
||||
};
|
||||
match number_prefix {
|
||||
NumberPrefix::Standalone(bytes) => bytes.to_string(),
|
||||
@@ -233,10 +229,12 @@ impl<'a> RowFormatter<'a> {
|
||||
///
|
||||
/// The scaling factor is defined in the `options` field.
|
||||
fn scaled_bytes(&self, size: u64) -> String {
|
||||
if let BlockSize::Bytes(d) = self.options.block_size {
|
||||
(size / d).to_string()
|
||||
} else {
|
||||
self.scaled_human_readable(size)
|
||||
match self.options.size_format {
|
||||
SizeFormat::HumanReadable(h) => self.scaled_human_readable(size, h),
|
||||
SizeFormat::StaticBlockSize => {
|
||||
let BlockSize::Bytes(d) = self.options.block_size;
|
||||
(size / d).to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,10 +242,9 @@ impl<'a> RowFormatter<'a> {
|
||||
///
|
||||
/// The scaling factor is defined in the `options` field.
|
||||
fn scaled_inodes(&self, size: u64) -> String {
|
||||
if let BlockSize::Bytes(_) = self.options.block_size {
|
||||
size.to_string()
|
||||
} else {
|
||||
self.scaled_human_readable(size)
|
||||
match self.options.size_format {
|
||||
SizeFormat::HumanReadable(h) => self.scaled_human_readable(size, h),
|
||||
SizeFormat::StaticBlockSize => size.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +302,12 @@ impl Header {
|
||||
for column in &options.columns {
|
||||
let header = match column {
|
||||
Column::Source => String::from("Filesystem"),
|
||||
Column::Size => options.block_size.to_string(),
|
||||
Column::Size => match options.size_format {
|
||||
SizeFormat::HumanReadable(_) => String::from("Size"),
|
||||
SizeFormat::StaticBlockSize => {
|
||||
format!("{}-blocks", options.block_size)
|
||||
}
|
||||
},
|
||||
Column::Used => String::from("Used"),
|
||||
Column::Avail => String::from("Available"),
|
||||
Column::Pcent => String::from("Use%"),
|
||||
@@ -424,6 +426,7 @@ impl fmt::Display for Table {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::blocks::{HumanReadable, SizeFormat};
|
||||
use crate::columns::Column;
|
||||
use crate::table::{Header, Row, RowFormatter};
|
||||
use crate::{BlockSize, Options};
|
||||
@@ -446,6 +449,30 @@ mod tests {
|
||||
Column::Target,
|
||||
];
|
||||
|
||||
impl Default for Row {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
file: Some("/path/to/file".to_string()),
|
||||
fs_device: "my_device".to_string(),
|
||||
fs_type: "my_type".to_string(),
|
||||
fs_mount: "my_mount".to_string(),
|
||||
|
||||
bytes: 100,
|
||||
bytes_used: 25,
|
||||
bytes_avail: 75,
|
||||
bytes_usage: Some(0.25),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: Some(0.5),
|
||||
|
||||
inodes: 10,
|
||||
inodes_used: 2,
|
||||
inodes_free: 8,
|
||||
inodes_usage: Some(0.2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_header() {
|
||||
let options = Default::default();
|
||||
@@ -523,7 +550,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_header_with_human_readable_binary() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::HumanReadableBinary,
|
||||
size_format: SizeFormat::HumanReadable(HumanReadable::Binary),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
@@ -542,7 +569,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_header_with_human_readable_si() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::HumanReadableDecimal,
|
||||
size_format: SizeFormat::HumanReadable(HumanReadable::Decimal),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
@@ -565,9 +592,7 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
let row = Row {
|
||||
file: Some("/path/to/file".to_string()),
|
||||
fs_device: "my_device".to_string(),
|
||||
fs_type: "my_type".to_string(),
|
||||
fs_mount: "my_mount".to_string(),
|
||||
|
||||
bytes: 100,
|
||||
@@ -575,13 +600,7 @@ mod tests {
|
||||
bytes_avail: 75,
|
||||
bytes_usage: Some(0.25),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: Some(0.5),
|
||||
|
||||
inodes: 10,
|
||||
inodes_used: 2,
|
||||
inodes_free: 8,
|
||||
inodes_usage: Some(0.2),
|
||||
..Default::default()
|
||||
};
|
||||
let fmt = RowFormatter::new(&row, &options);
|
||||
assert_eq!(
|
||||
@@ -598,7 +617,6 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
let row = Row {
|
||||
file: Some("/path/to/file".to_string()),
|
||||
fs_device: "my_device".to_string(),
|
||||
fs_type: "my_type".to_string(),
|
||||
fs_mount: "my_mount".to_string(),
|
||||
@@ -608,13 +626,7 @@ mod tests {
|
||||
bytes_avail: 75,
|
||||
bytes_usage: Some(0.25),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: Some(0.5),
|
||||
|
||||
inodes: 10,
|
||||
inodes_used: 2,
|
||||
inodes_free: 8,
|
||||
inodes_usage: Some(0.2),
|
||||
..Default::default()
|
||||
};
|
||||
let fmt = RowFormatter::new(&row, &options);
|
||||
assert_eq!(
|
||||
@@ -631,23 +643,15 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
let row = Row {
|
||||
file: Some("/path/to/file".to_string()),
|
||||
fs_device: "my_device".to_string(),
|
||||
fs_type: "my_type".to_string(),
|
||||
fs_mount: "my_mount".to_string(),
|
||||
|
||||
bytes: 100,
|
||||
bytes_used: 25,
|
||||
bytes_avail: 75,
|
||||
bytes_usage: Some(0.25),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: Some(0.5),
|
||||
|
||||
inodes: 10,
|
||||
inodes_used: 2,
|
||||
inodes_free: 8,
|
||||
inodes_usage: Some(0.2),
|
||||
|
||||
..Default::default()
|
||||
};
|
||||
let fmt = RowFormatter::new(&row, &options);
|
||||
assert_eq!(
|
||||
@@ -664,23 +668,9 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
let row = Row {
|
||||
file: Some("/path/to/file".to_string()),
|
||||
fs_device: "my_device".to_string(),
|
||||
fs_type: "my_type".to_string(),
|
||||
fs_mount: "my_mount".to_string(),
|
||||
|
||||
bytes: 100,
|
||||
bytes_used: 25,
|
||||
bytes_avail: 75,
|
||||
bytes_usage: Some(0.25),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: Some(0.5),
|
||||
|
||||
inodes: 10,
|
||||
inodes_used: 2,
|
||||
inodes_free: 8,
|
||||
inodes_usage: Some(0.2),
|
||||
..Default::default()
|
||||
};
|
||||
let fmt = RowFormatter::new(&row, &options);
|
||||
assert_eq!(fmt.get_values(), vec!("1", "10"));
|
||||
@@ -689,12 +679,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_row_formatter_with_human_readable_si() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::HumanReadableDecimal,
|
||||
size_format: SizeFormat::HumanReadable(HumanReadable::Decimal),
|
||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||
..Default::default()
|
||||
};
|
||||
let row = Row {
|
||||
file: Some("/path/to/file".to_string()),
|
||||
fs_device: "my_device".to_string(),
|
||||
fs_type: "my_type".to_string(),
|
||||
fs_mount: "my_mount".to_string(),
|
||||
@@ -704,13 +693,7 @@ mod tests {
|
||||
bytes_avail: 3000,
|
||||
bytes_usage: Some(0.25),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: Some(0.5),
|
||||
|
||||
inodes: 10,
|
||||
inodes_used: 2,
|
||||
inodes_free: 8,
|
||||
inodes_usage: Some(0.2),
|
||||
..Default::default()
|
||||
};
|
||||
let fmt = RowFormatter::new(&row, &options);
|
||||
assert_eq!(
|
||||
@@ -730,12 +713,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_row_formatter_with_human_readable_binary() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::HumanReadableBinary,
|
||||
size_format: SizeFormat::HumanReadable(HumanReadable::Binary),
|
||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||
..Default::default()
|
||||
};
|
||||
let row = Row {
|
||||
file: Some("/path/to/file".to_string()),
|
||||
fs_device: "my_device".to_string(),
|
||||
fs_type: "my_type".to_string(),
|
||||
fs_mount: "my_mount".to_string(),
|
||||
@@ -745,13 +727,7 @@ mod tests {
|
||||
bytes_avail: 3072,
|
||||
bytes_usage: Some(0.25),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: Some(0.5),
|
||||
|
||||
inodes: 10,
|
||||
inodes_used: 2,
|
||||
inodes_free: 8,
|
||||
inodes_usage: Some(0.2),
|
||||
..Default::default()
|
||||
};
|
||||
let fmt = RowFormatter::new(&row, &options);
|
||||
assert_eq!(
|
||||
@@ -771,32 +747,14 @@ mod tests {
|
||||
#[test]
|
||||
fn test_row_formatter_with_round_up_usage() {
|
||||
let options = Options {
|
||||
block_size: BlockSize::Bytes(1),
|
||||
columns: vec![Column::Pcent],
|
||||
..Default::default()
|
||||
};
|
||||
let row = Row {
|
||||
file: Some("/path/to/file".to_string()),
|
||||
fs_device: "my_device".to_string(),
|
||||
fs_type: "my_type".to_string(),
|
||||
fs_mount: "my_mount".to_string(),
|
||||
|
||||
bytes: 100,
|
||||
bytes_used: 25,
|
||||
bytes_avail: 75,
|
||||
bytes_usage: Some(0.251),
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
bytes_capacity: Some(0.5),
|
||||
|
||||
inodes: 10,
|
||||
inodes_used: 2,
|
||||
inodes_free: 8,
|
||||
inodes_usage: Some(0.2),
|
||||
..Default::default()
|
||||
};
|
||||
let fmt = RowFormatter::new(&row, &options);
|
||||
assert_eq!(
|
||||
fmt.get_values(),
|
||||
vec!("my_device", "100", "25", "75", "26%", "my_mount")
|
||||
);
|
||||
assert_eq!(fmt.get_values(), vec!("26%"));
|
||||
}
|
||||
}
|
||||
|
||||
+8
-22
@@ -20,7 +20,7 @@ use std::fs::File;
|
||||
use std::fs::Metadata;
|
||||
use std::io::BufRead;
|
||||
use std::io::BufReader;
|
||||
use std::io::{ErrorKind, Result};
|
||||
use std::io::Result;
|
||||
use std::iter;
|
||||
#[cfg(not(windows))]
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
@@ -34,7 +34,8 @@ use std::str::FromStr;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
use std::{error::Error, fmt::Display};
|
||||
use uucore::display::{print_verbatim, Quotable};
|
||||
use uucore::error::{set_exit_code, UError, UResult};
|
||||
use uucore::error::FromIo;
|
||||
use uucore::error::{UError, UResult};
|
||||
use uucore::format_usage;
|
||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||
use uucore::InvalidEncodingHandling;
|
||||
@@ -102,7 +103,6 @@ const UNITS: [(char, u32); 6] = [('E', 6), ('P', 5), ('T', 4), ('G', 3), ('M', 2
|
||||
|
||||
struct Options {
|
||||
all: bool,
|
||||
util_name: String,
|
||||
max_depth: Option<usize>,
|
||||
total: bool,
|
||||
separate_dirs: bool,
|
||||
@@ -309,13 +309,9 @@ fn du(
|
||||
let read = match fs::read_dir(&my_stat.path) {
|
||||
Ok(read) => read,
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"{}: cannot read directory {}: {}",
|
||||
options.util_name,
|
||||
my_stat.path.quote(),
|
||||
e
|
||||
show!(
|
||||
e.map_err_context(|| format!("cannot read directory {}", my_stat.path.quote()))
|
||||
);
|
||||
set_exit_code(1);
|
||||
return Box::new(iter::once(my_stat));
|
||||
}
|
||||
};
|
||||
@@ -368,18 +364,9 @@ fn du(
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(error) => match error.kind() {
|
||||
ErrorKind::PermissionDenied => {
|
||||
let description = format!("cannot access {}", entry.path().quote());
|
||||
let error_message = "Permission denied";
|
||||
show_error_custom_description!(description, "{}", error_message);
|
||||
set_exit_code(1);
|
||||
}
|
||||
_ => {
|
||||
set_exit_code(1);
|
||||
show_error!("cannot access {}: {}", entry.path().quote(), error);
|
||||
}
|
||||
},
|
||||
Err(e) => show!(
|
||||
e.map_err_context(|| format!("cannot access {}", entry.path().quote()))
|
||||
),
|
||||
}
|
||||
}
|
||||
Err(error) => show_error!("{}", error),
|
||||
@@ -567,7 +554,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
|
||||
let options = Options {
|
||||
all: matches.is_present(options::ALL),
|
||||
util_name: uucore::util_name().to_owned(),
|
||||
max_depth,
|
||||
total: matches.is_present(options::TOTAL),
|
||||
separate_dirs: matches.is_present(options::SEPARATE_DIRS),
|
||||
|
||||
@@ -17,7 +17,7 @@ path = "src/expr.rs"
|
||||
[dependencies]
|
||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||
num-bigint = "0.4.0"
|
||||
num-traits = "0.2.14"
|
||||
num-traits = "0.2.15"
|
||||
onig = { version = "~6.3", default-features = false }
|
||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ categories = ["command-line-utilities"]
|
||||
edition = "2021"
|
||||
|
||||
[build-dependencies]
|
||||
num-traits = "0.2.13" # used in src/numerics.rs, which is included by build.rs
|
||||
num-traits = "0.2.15" # used in src/numerics.rs, which is included by build.rs
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||
coz = { version = "0.1.3", optional = true }
|
||||
num-traits = "0.2.13" # Needs at least version 0.2.13 for "OverflowingAdd"
|
||||
num-traits = "0.2.15" # Needs at least version 0.2.15 for "OverflowingAdd"
|
||||
rand = { version = "0.8", features = ["small_rng"] }
|
||||
smallvec = "1.7" # TODO(nicoo): Use `union` feature, requires Rust 1.49 or later.
|
||||
uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore" }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user