From da198dbb197c436e65d3c108ff9b9a53a2031338 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sun, 19 Sep 2021 22:24:11 +0200 Subject: [PATCH 01/62] tests/util: add a convenience wrapper to run a ucmd with root permissions --- tests/common/util.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/common/util.rs b/tests/common/util.rs index f3cdec010..a7c6e464d 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1237,6 +1237,58 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< )) } +/// This is a convenience wrapper to run a ucmd with root permissions. +/// This runs 'sudo -E --non-interactive target/debug/coreutils util_name args` +/// This is primarily designed to run in the CICD environment where whoami is in $path +/// and where non-interactive sudo is possible. +/// To check if i) non-interactive sudo is possible and ii) if sudo works, this runs: +/// 'sudo -E --non-interactive whoami' first. +/// +/// Example: +/// +/// ```no_run +/// use crate::common::util::*; +/// #[test] +/// fn test_xyz() { +/// let ts = TestScenario::new("whoami"); +/// let expected = "root\n".to_string(); +/// if let Ok(result) = run_ucmd_as_root(&ts, &[]) { +/// result.stdout_is(expected); +/// } else { +/// print!("TEST SKIPPED"); +/// } +/// } +///``` +#[cfg(unix)] +pub fn run_ucmd_as_root( + ts: &TestScenario, + args: &[&str], +) -> std::result::Result { + if ts + .cmd_keepenv("sudo") + .env("LC_ALL", "C") + .arg("-E") + .arg("--non-interactive") + .arg("whoami") + .run() + .stdout_str() + .trim() + != "root" + { + Err("\"sudo whoami\" didn't return \"root\"".to_string()) + } else { + Ok(ts + .cmd_keepenv("sudo") + .env("LC_ALL", "C") + .arg("-E") + .arg("--non-interactive") + .arg(&ts.bin_path) + .arg(&ts.util_name) + .args(args) + .run()) + } +} + /// Sanity checks for test utils #[cfg(test)] mod tests { @@ -1523,4 +1575,20 @@ mod tests { std::assert_eq!(host_name_for("gwho"), "gwho"); } } + + #[test] + #[cfg(unix)] + fn test_run_ucmd_as_root() { + // We need non-interactive `sudo. + // CICD environment should allow non-interactive `sudo`. + // Return early if we can't guarantee non-interactive `sudo` + if !is_ci() { + return; + } + let ts = TestScenario::new("whoami"); + std::assert_eq!( + run_ucmd_as_root(&ts, &[]).unwrap().stdout_str().trim(), + "root" + ); + } } From 4ef77232486f0c7e9a6b8e0ad88a966f96b79f6d Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Mon, 20 Sep 2021 00:20:06 +0200 Subject: [PATCH 02/62] Update util.rs add feature for `whoami` --- tests/common/util.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/common/util.rs b/tests/common/util.rs index a7c6e464d..f056f3510 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1578,6 +1578,7 @@ mod tests { #[test] #[cfg(unix)] + #[cfg(feature = "whoami")] fn test_run_ucmd_as_root() { // We need non-interactive `sudo. // CICD environment should allow non-interactive `sudo`. From 1ccf55a3dc611c5de46b9fe8a479dc6d42c67d6d Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Tue, 21 Sep 2021 00:23:23 +0200 Subject: [PATCH 03/62] Update util.rs --- tests/common/util.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/common/util.rs b/tests/common/util.rs index f056f3510..928bc84f3 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1239,7 +1239,7 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< /// This is a convenience wrapper to run a ucmd with root permissions. /// This runs 'sudo -E --non-interactive target/debug/coreutils util_name args` -/// This is primarily designed to run in the CICD environment where whoami is in $path +/// This is primarily designed to run in an environment where whoami is in $path /// and where non-interactive sudo is possible. /// To check if i) non-interactive sudo is possible and ii) if sudo works, this runs: /// 'sudo -E --non-interactive whoami' first. @@ -1264,6 +1264,7 @@ pub fn run_ucmd_as_root( ts: &TestScenario, args: &[&str], ) -> std::result::Result { + // Apparently CICD environment has no `sudo`? if ts .cmd_keepenv("sudo") .env("LC_ALL", "C") @@ -1580,16 +1581,18 @@ mod tests { #[cfg(unix)] #[cfg(feature = "whoami")] fn test_run_ucmd_as_root() { - // We need non-interactive `sudo. - // CICD environment should allow non-interactive `sudo`. - // Return early if we can't guarantee non-interactive `sudo` - if !is_ci() { - return; + // Skip test if we can't guarantee non-interactive `sudo`. + if let Ok(_status) = Command::new("sudo") + .args(&["-E", "-v", "--non-interactive"]) + .status() + { + let ts = TestScenario::new("whoami"); + std::assert_eq!( + run_ucmd_as_root(&ts, &[]).unwrap().stdout_str().trim(), + "root" + ); + } else { + print!("TEST SKIPPED"); } - let ts = TestScenario::new("whoami"); - std::assert_eq!( - run_ucmd_as_root(&ts, &[]).unwrap().stdout_str().trim(), - "root" - ); } } From adfe4b22893609c4478a9bf30b4846d57249deac Mon Sep 17 00:00:00 2001 From: naveen <172697+naveensrinivasan@users.noreply.github.com> Date: Fri, 29 Apr 2022 01:01:27 +0000 Subject: [PATCH 04/62] chore: Set permissions for GitHub actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much. - Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> --- .github/workflows/GnuTests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index d306092c6..7bc0f26d4 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -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: From 023fc96aab29a1df3b79ebd8de27afbe0850cf5f Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 28 Apr 2022 09:10:20 +0200 Subject: [PATCH 05/62] df: fix "Size" column header Fixes #3193 --- src/uu/df/src/blocks.rs | 101 ++++++++++++++++++++++++++++----------- tests/by-util/test_df.rs | 7 ++- 2 files changed, 75 insertions(+), 33 deletions(-) diff --git a/src/uu/df/src/blocks.rs b/src/uu/df/src/blocks.rs index 7783e5636..efeae2a70 100644 --- a/src/uu/df/src/blocks.rs +++ b/src/uu/df/src/blocks.rs @@ -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,6 +73,37 @@ fn to_magnitude_and_suffix_1024(n: u128) -> Result { Err(()) } +/// Convert a number, except multiples of 1024, 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 { + 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 @@ -66,8 +113,7 @@ fn to_magnitude_and_suffix(n: u128) -> Result { if n % 1024 == 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) } } @@ -153,36 +199,33 @@ 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"); - // // etc. - // } + 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"); + } #[test] fn test_block_size_display() { diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index 61ddcec5d..ce820bb92 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -413,10 +413,9 @@ fn test_block_size_with_suffix() { assert_eq!(get_header("1KiB"), "1K-blocks"); assert_eq!(get_header("1MiB"), "1M-blocks"); assert_eq!(get_header("1GiB"), "1G-blocks"); - // TODO enable the following asserts when #3193 is resolved - //assert_eq!(get_header("1KB"), "1kB-blocks"); - //assert_eq!(get_header("1MB"), "1MB-blocks"); - //assert_eq!(get_header("1GB"), "1GB-blocks"); + assert_eq!(get_header("1KB"), "1kB-blocks"); + assert_eq!(get_header("1MB"), "1MB-blocks"); + assert_eq!(get_header("1GB"), "1GB-blocks"); } #[test] From ca670148f2bf1a247e784f732f241b8278d81291 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 27 Apr 2022 08:43:03 +0200 Subject: [PATCH 06/62] build(deps): bump time from 0.1.43 to 0.3.9 Bumps [time](https://github.com/time-rs/time) from 0.1.43 to 0.3.9. - [Release notes](https://github.com/time-rs/time/releases) - [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md) - [Commits](https://github.com/time-rs/time/compare/v0.1.43...v0.3.9) --- updated-dependencies: - dependency-name: time dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 29 +++-- Cargo.toml | 2 +- deny.toml | 3 + src/uu/install/Cargo.toml | 3 + src/uu/pinky/src/pinky.rs | 10 +- src/uu/touch/Cargo.toml | 2 +- src/uu/touch/src/touch.rs | 154 ++++++++++++++++++--------- src/uu/uptime/src/uptime.rs | 6 +- src/uu/who/src/who.rs | 10 +- src/uucore/Cargo.toml | 4 +- src/uucore/src/lib/features/fsext.rs | 12 ++- src/uucore/src/lib/features/utmpx.rs | 14 +-- tests/by-util/test_mv.rs | 6 +- tests/by-util/test_touch.rs | 86 ++++++++------- 14 files changed, 218 insertions(+), 123 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 191ad8923..497d7ab42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,7 +224,7 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time", + "time 0.1.44", "winapi 0.3.9", ] @@ -335,7 +335,7 @@ dependencies = [ "sha1", "tempfile", "textwrap 0.15.0", - "time", + "time 0.3.9", "unindent", "unix_socket", "users", @@ -1213,6 +1213,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +dependencies = [ + "libc", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -1944,16 +1953,17 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi", "winapi 0.3.9", ] [[package]] -name = "typenum" +< String { thread_local! { - static NOW: time::Tm = time::now() + static NOW: time::OffsetDateTime = time::OffsetDateTime::now_local().unwrap(); } NOW.with(|n| { - let duration = n.to_timespec().sec - when; + let duration = n.unix_timestamp() - when; if duration < 60 { // less than 1min " ".to_owned() @@ -242,7 +242,11 @@ fn idle_string(when: i64) -> String { } fn time_string(ut: &Utmpx) -> String { - time::strftime("%b %e %H:%M", &ut.login_time()).unwrap() // LC_ALL=C + // "%b %e %H:%M" + let time_format: Vec = + time::format_description::parse("[month repr:short] [day padding:space] [hour]:[minute]") + .unwrap(); + ut.login_time().format(&time_format).unwrap() // LC_ALL=C } fn gecos_to_fullname(pw: &Passwd) -> Option { diff --git a/src/uu/touch/Cargo.toml b/src/uu/touch/Cargo.toml index 646b65f50..aa747ae78 100644 --- a/src/uu/touch/Cargo.toml +++ b/src/uu/touch/Cargo.toml @@ -17,7 +17,7 @@ path = "src/touch.rs" [dependencies] filetime = "0.2.1" clap = { version = "3.1", features = ["wrap_help", "cargo"] } -time = "0.1.40" +time = { version = "0.3", features = ["parsing", "formatting", "local-offset", "macros"] } uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["libc"] } [target.'cfg(target_os = "windows")'.dependencies] diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index ff08a1b59..75cd38a7a 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -17,6 +17,7 @@ use clap::{crate_version, Arg, ArgGroup, Command}; use filetime::*; use std::fs::{self, File}; use std::path::{Path, PathBuf}; +use time::macros::{format_description, time}; use uucore::display::Quotable; use uucore::error::{FromIo, UError, UResult, USimpleError}; use uucore::format_usage; @@ -41,14 +42,13 @@ pub mod options { static ARG_FILES: &str = "files"; -fn to_local(mut tm: time::Tm) -> time::Tm { - tm.tm_utcoff = time::now().tm_utcoff; - tm +fn to_local(tm: time::PrimitiveDateTime) -> time::OffsetDateTime { + // TODO: handle error getting now + tm.assume_offset(time::OffsetDateTime::now_local().unwrap().offset()) } -fn local_tm_to_filetime(tm: time::Tm) -> FileTime { - let ts = tm.to_timespec(); - FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32) +fn local_dt_to_filetime(dt: time::OffsetDateTime) -> FileTime { + FileTime::from_unix_time(dt.unix_timestamp(), dt.nanosecond()) } #[uucore::main] @@ -62,7 +62,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Try 'touch --help' for more information."##, ) })?; - let (mut atime, mut mtime) = if let Some(reference) = matches.value_of_os(options::sources::REFERENCE) { stat(Path::new(reference), !matches.is_present(options::NO_DEREF))? @@ -72,7 +71,7 @@ Try 'touch --help' for more information."##, } else if let Some(current) = matches.value_of(options::sources::CURRENT) { parse_timestamp(current)? } else { - local_tm_to_filetime(time::now()) + local_dt_to_filetime(time::OffsetDateTime::now_local().unwrap()) }; (timestamp, timestamp) }; @@ -248,38 +247,80 @@ fn stat(path: &Path, follow: bool) -> UResult<(FileTime, FileTime)> { )) } -fn parse_date(str: &str) -> UResult { +const POSIX_LOCALE_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[weekday repr:short] [month repr:short] [day padding:space] [hour]:[minute]:[second] [year]" +); + +const ISO_8601_FORMAT: &[time::format_description::FormatItem] = + format_description!("[year]-[month]-[day]"); + +fn parse_date(s: &str) -> UResult { // This isn't actually compatible with GNU touch, but there doesn't seem to // be any simple specification for what format this parameter allows and I'm // not about to implement GNU parse_datetime. // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y - let formats = vec!["%c", "%F"]; - for f in formats { - if let Ok(tm) = time::strptime(str, f) { - return Ok(local_tm_to_filetime(to_local(tm))); + + // TODO: match on char count? + + // "The preferred date and time representation for the current locale." + // "(In the POSIX locale this is equivalent to %a %b %e %H:%M:%S %Y.)" + // time 0.1.43 parsed this as 'a b e T Y' + // which is equivalent to the POSIX locale: %a %b %e %H:%M:%S %Y + // Tue Dec 3 ... + // ("%c", POSIX_LOCALE_FORMAT), + if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &POSIX_LOCALE_FORMAT) { + return Ok(local_dt_to_filetime(to_local(parsed))); + } + + // "Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99)" + // ("%F", ISO_8601_FORMAT), + if let Ok(parsed) = time::Date::parse(s, &ISO_8601_FORMAT) { + return Ok(local_dt_to_filetime(to_local( + time::PrimitiveDateTime::new(parsed, time!(00:00)), + ))); + } + + // "@%s" is "The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). (TZ) (Calculated from mktime(tm).)" + if s.bytes().next() == Some(b'@') { + if let Ok(ts) = &s[1..].parse::() { + // Don't convert to local time in this case - seconds since epoch are not time-zone dependent + return Ok(local_dt_to_filetime( + time::OffsetDateTime::from_unix_timestamp(*ts).unwrap(), + )); } } - if let Ok(tm) = time::strptime(str, "@%s") { - // Don't convert to local time in this case - seconds since epoch are not time-zone dependent - return Ok(local_tm_to_filetime(tm)); - } - - Err(USimpleError::new( - 1, - format!("Unable to parse date: {}", str), - )) + Err(USimpleError::new(1, format!("Unable to parse date: {}", s))) } +// "%Y%m%d%H%M.%S" 15 chars +const YYYYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full][month repr:numerical padding:zero][day][hour][minute].[second]" +); + +// "%Y%m%d%H%M" 12 chars +const YYYYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = + format_description!("[year repr:full][month repr:numerical padding:zero][day][hour][minute]"); + +// "%y%m%d%H%M.%S" 13 chars +const YYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = + format_description!("[year repr:last_two padding:none][month][day][hour][minute].[second]"); + +// "%y%m%d%H%M" 10 chars +const YYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = + format_description!("[year repr:last_two padding:none][month padding:zero][day padding:zero][hour repr:24 padding:zero][minute padding:zero]"); + fn parse_timestamp(s: &str) -> UResult { - let now = time::now(); - let (format, ts) = match s.chars().count() { - 15 => ("%Y%m%d%H%M.%S", s.to_owned()), - 12 => ("%Y%m%d%H%M", s.to_owned()), - 13 => ("%y%m%d%H%M.%S", s.to_owned()), - 10 => ("%y%m%d%H%M", s.to_owned()), - 11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)), - 8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)), + // TODO: handle error + let now = time::OffsetDateTime::now_utc(); + + let (mut format, mut ts) = match s.chars().count() { + 15 => (YYYYMMDDHHMM_DOT_SS_FORMAT, s.to_owned()), + 12 => (YYYYMMDDHHMM_FORMAT, s.to_owned()), + 13 => (YYMMDDHHMM_DOT_SS_FORMAT, s.to_owned()), + 10 => (YYMMDDHHMM_FORMAT, s.to_owned()), + 11 => (YYYYMMDDHHMM_DOT_SS_FORMAT, format!("{}{}", now.year(), s)), + 8 => (YYYYMMDDHHMM_FORMAT, format!("{}{}", now.year(), s)), _ => { return Err(USimpleError::new( 1, @@ -287,30 +328,39 @@ fn parse_timestamp(s: &str) -> UResult { )) } }; - - let tm = time::strptime(&ts, format) - .map_err(|_| USimpleError::new(1, format!("invalid date format {}", s.quote())))?; - - let mut local = to_local(tm); - local.tm_isdst = -1; - let ft = local_tm_to_filetime(local); - - // We have to check that ft is valid time. Due to daylight saving - // time switch, local time can jump from 1:59 AM to 3:00 AM, - // in which case any time between 2:00 AM and 2:59 AM is not valid. - // Convert back to local time and see if we got the same value back. - let ts = time::Timespec { - sec: ft.unix_seconds(), - nsec: 0, - }; - let tm2 = time::at(ts); - if tm.tm_hour != tm2.tm_hour { - return Err(USimpleError::new( - 1, - format!("invalid date format {}", s.quote()), - )); + // workaround time returning Err(TryFromParsed(InsufficientInformation)) for year w/ + // repr:last_two + // https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1ccfac7c07c5d1c7887a11decf0e1996 + if s.chars().count() == 10 { + format = YYYYMMDDHHMM_FORMAT; + ts = "20".to_owned() + &ts; + } else if s.chars().count() == 13 { + format = YYYYMMDDHHMM_DOT_SS_FORMAT; + ts = "20".to_owned() + &ts; } + let tm = time::PrimitiveDateTime::parse(&ts, &format) + .map_err(|_| USimpleError::new(1, format!("invalid date ts format {}", ts.quote())))?; + + let local = to_local(tm); + let ft = local_dt_to_filetime(local); + + // // We have to check that ft is valid time. Due to daylight saving + // // time switch, local time can jump from 1:59 AM to 3:00 AM, + // // in which case any time between 2:00 AM and 2:59 AM is not valid. + // // Convert back to local time and see if we got the same value back. + // let ts = time::Timespec { + // sec: ft.unix_seconds(), + // nsec: 0, + // }; + // let tm2 = time::at(ts); + // if tm.tm_hour != tm2.tm_hour { + // return Err(USimpleError::new( + // 1, + // format!("invalid date format {}", s.quote()), + // )); + // } + Ok(ft) } diff --git a/src/uu/uptime/src/uptime.rs b/src/uu/uptime/src/uptime.rs index a93344dbc..5c64cb5af 100644 --- a/src/uu/uptime/src/uptime.rs +++ b/src/uu/uptime/src/uptime.rs @@ -111,9 +111,9 @@ fn process_utmpx() -> (Option, usize) { match line.record_type() { USER_PROCESS => nusers += 1, BOOT_TIME => { - let t = line.login_time().to_timespec(); - if t.sec > 0 { - boot_time = Some(t.sec as time_t); + let dt = line.login_time(); + if dt.second() > 0 { + boot_time = Some(dt.second() as time_t); } } _ => continue, diff --git a/src/uu/who/src/who.rs b/src/uu/who/src/who.rs index 6e21ac912..47d96a381 100644 --- a/src/uu/who/src/who.rs +++ b/src/uu/who/src/who.rs @@ -275,10 +275,10 @@ struct Who { fn idle_string<'a>(when: i64, boottime: i64) -> Cow<'a, str> { thread_local! { - static NOW: time::Tm = time::now() + static NOW: time::OffsetDateTime = time::OffsetDateTime::now_local().unwrap(); } NOW.with(|n| { - let now = n.to_timespec().sec; + let now = n.unix_timestamp(); if boottime < when && now - 24 * 3600 < when && when <= now { let seconds_idle = now - when; if seconds_idle < 60 { @@ -298,7 +298,11 @@ fn idle_string<'a>(when: i64, boottime: i64) -> Cow<'a, str> { } fn time_string(ut: &Utmpx) -> String { - time::strftime("%b %e %H:%M", &ut.login_time()).unwrap() // LC_ALL=C + // "%b %e %H:%M" + let time_format: Vec = + time::format_description::parse("[month repr:short] [day padding:space] [hour]:[minute]") + .unwrap(); + ut.login_time().format(&time_format).unwrap() // LC_ALL=C } #[inline] diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 6f74b238a..5b363376d 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -26,7 +26,7 @@ wild = "2.0" # * optional itertools = { version="0.10.0", optional=true } thiserror = { version="1.0", optional=true } -time = { version="<= 0.1.43", optional=true } +time = { version="<= 0.3.10", optional=true, features = ["formatting", "local-offset", "macros"] } # * "problem" dependencies (pinned) data-encoding = { version="2.1", optional=true } data-encoding-macro = { version="0.1.12", optional=true } @@ -62,6 +62,6 @@ process = ["libc"] ringbuffer = [] signals = [] utf8 = [] -utmpx = ["time", "libc", "dns-lookup"] +utmpx = ["time", "time/macros", "libc", "dns-lookup"] wide = [] pipes = ["nix"] diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index eeaf54061..838bfd4b5 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -12,6 +12,7 @@ // spell-checker:ignore (arch) bitrig ; (fs) cifs smbfs extern crate time; +use time::macros::format_description; pub use crate::*; // import macros from `../../macros.rs` @@ -63,7 +64,6 @@ fn LPWSTR2String(buf: &[u16]) -> String { String::from_utf16(&buf[..len]).unwrap() } -use self::time::Timespec; #[cfg(unix)] use libc::{ mode_t, strerror, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, @@ -732,11 +732,17 @@ where } } +// match strftime "%Y-%m-%d %H:%M:%S.%f %z" +const PRETTY_DATETIME_FORMAT: &[time::format_description::FormatItem] = format_description!("[year]-[month]-[day padding:zero] [hour]:[minute]:[second].[subsecond] [offset_hour][offset_minute]"); + pub fn pretty_time(sec: i64, nsec: i64) -> String { // sec == seconds since UNIX_EPOCH // nsec == nanoseconds since (UNIX_EPOCH + sec) - let tm = time::at(Timespec::new(sec, nsec as i32)); - let res = time::strftime("%Y-%m-%d %H:%M:%S.%f %z", &tm).unwrap(); + let ts_nanos: i128 = (sec * 1_000_000_000 + nsec).into(); + // TODO: return errors to caller + let tm = time::OffsetDateTime::from_unix_timestamp_nanos(ts_nanos).unwrap(); + + let res = tm.format(&PRETTY_DATETIME_FORMAT).unwrap(); if res.ends_with(" -0000") { res.replace(" -0000", " +0000") } else { diff --git a/src/uucore/src/lib/features/utmpx.rs b/src/uucore/src/lib/features/utmpx.rs index 302d03d71..dc66eae09 100644 --- a/src/uucore/src/lib/features/utmpx.rs +++ b/src/uucore/src/lib/features/utmpx.rs @@ -32,7 +32,6 @@ //! ``` pub extern crate time; -use self::time::{Timespec, Tm}; use std::ffi::CString; use std::io::Result as IOResult; @@ -189,11 +188,14 @@ impl Utmpx { chars2string!(self.inner.ut_line) } /// A.K.A. ut.ut_tv - pub fn login_time(&self) -> Tm { - time::at(Timespec::new( - self.inner.ut_tv.tv_sec as i64, - self.inner.ut_tv.tv_usec as i32, - )) + pub fn login_time(&self) -> time::OffsetDateTime { + let ts_nanos: i128 = (self.inner.ut_tv.tv_sec as i64 * 1_000_000_000 as i64 + + self.inner.ut_tv.tv_usec as i64 * 1_000 as i64) + .into(); + let local_offset = time::OffsetDateTime::now_local().unwrap().offset(); + time::OffsetDateTime::from_unix_timestamp_nanos(ts_nanos) + .unwrap() + .to_offset(local_offset) } /// A.K.A. ut.ut_exit /// diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index c4ec03d95..06f4d5259 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -595,9 +595,9 @@ fn test_mv_update_option() { at.touch(file_a); at.touch(file_b); - let ts = time::now().to_timespec(); - let now = FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32); - let later = FileTime::from_unix_time(ts.sec as i64 + 3600, ts.nsec as u32); + let ts = time::OffsetDateTime::now_local().unwrap(); + let now = FileTime::from_unix_time(ts.unix_timestamp(), ts.nanosecond()); + let later = FileTime::from_unix_time(ts.unix_timestamp() as i64 + 3600, ts.nanosecond() as u32); filetime::set_file_times(at.plus_as_string(file_a), now, now).unwrap(); filetime::set_file_times(at.plus_as_string(file_b), now, later).unwrap(); diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 6e5d656c4..6de635831 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -4,6 +4,7 @@ extern crate touch; use self::touch::filetime::{self, FileTime}; extern crate time; +use time::macros::{datetime, format_description}; use crate::common::util::*; use std::fs::remove_file; @@ -32,11 +33,18 @@ fn set_file_times(at: &AtPath, path: &str, atime: FileTime, mtime: FileTime) { // Adjusts for local timezone fn str_to_filetime(format: &str, s: &str) -> FileTime { - let mut tm = time::strptime(s, format).unwrap(); - tm.tm_utcoff = time::now().tm_utcoff; - tm.tm_isdst = -1; // Unknown flag DST - let ts = tm.to_timespec(); - FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32) + let format_description = match format { + "%y%m%d%H%M" => format_description!("[year repr:last_two][month][day][hour][minute]"), + "%y%m%d%H%M.%S" => { + format_description!("[year repr:last_two][month][day][hour][minute].[second]") + } + "%Y%m%d%H%M" => format_description!("[year][month][day][hour][minute]"), + "%Y%m%d%H%M.%S" => format_description!("[year][month][day][hour][minute].[second]"), + _ => panic!("unexpected dt format"), + }; + let tm = time::PrimitiveDateTime::parse(&s, &format_description).unwrap(); + let offset_dt = tm.assume_offset(time::OffsetDateTime::now_local().unwrap().offset()); + FileTime::from_unix_time(offset_dt.unix_timestamp(), tm.nanosecond()) } #[test] @@ -83,7 +91,10 @@ fn test_touch_set_mdhm_time() { let start_of_year = str_to_filetime( "%Y%m%d%H%M", - &format!("{}01010000", 1900 + time::now().tm_year), + &format!( + "{}01010000", + time::OffsetDateTime::now_local().unwrap().year() + ), ); let (atime, mtime) = get_file_times(&at, file); assert_eq!(atime, mtime); @@ -104,7 +115,7 @@ fn test_touch_set_mdhms_time() { let start_of_year = str_to_filetime( "%Y%m%d%H%M.%S", - &format!("{}01010000.00", 1900 + time::now().tm_year), + &format!("{}01010000.00", time::OffsetDateTime::now_utc().year()), ); let (atime, mtime) = get_file_times(&at, file); assert_eq!(atime, mtime); @@ -123,7 +134,7 @@ fn test_touch_set_ymdhm_time() { assert!(at.file_exists(file)); - let start_of_year = str_to_filetime("%y%m%d%H%M", "1501010000"); + let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000"); let (atime, mtime) = get_file_times(&at, file); assert_eq!(atime, mtime); assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45240); @@ -141,7 +152,7 @@ fn test_touch_set_ymdhms_time() { assert!(at.file_exists(file)); - let start_of_year = str_to_filetime("%y%m%d%H%M.%S", "1501010000.00"); + let start_of_year = str_to_filetime("%Y%m%d%H%M.%S", "201501010000.00"); let (atime, mtime) = get_file_times(&at, file); assert_eq!(atime, mtime); assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45296); @@ -430,18 +441,18 @@ fn test_touch_mtime_dst_succeeds() { assert_eq!(target_time, mtime); } -// is_dst_switch_hour returns true if timespec ts is just before the switch -// to Daylight Saving Time. -// For example, in EST (UTC-5), Timespec { sec: 1583647200, nsec: 0 } -// for March 8 2020 01:00:00 AM -// is just before the switch because on that day clock jumps by 1 hour, -// so 1 minute after 01:59:00 is 03:00:00. -fn is_dst_switch_hour(ts: time::Timespec) -> bool { - let ts_after = ts + time::Duration::hours(1); - let tm = time::at(ts); - let tm_after = time::at(ts_after); - tm_after.tm_hour == tm.tm_hour + 2 -} +// // is_dst_switch_hour returns true if timespec ts is just before the switch +// // to Daylight Saving Time. +// // For example, in EST (UTC-5), Timespec { sec: 1583647200, nsec: 0 } +// // for March 8 2020 01:00:00 AM +// // is just before the switch because on that day clock jumps by 1 hour, +// // so 1 minute after 01:59:00 is 03:00:00. +// fn is_dst_switch_hour(ts: time::Timespec) -> bool { +// let ts_after = ts + time::Duration::hours(1); +// let tm = time::at(ts); +// let tm_after = time::at(ts_after); +// tm_after.tm_hour == tm.tm_hour + 2 +// } // get_dst_switch_hour returns date string for which touch -m -t fails. // For example, in EST (UTC-5), that will be "202003080200" so @@ -450,23 +461,24 @@ fn is_dst_switch_hour(ts: time::Timespec) -> bool { // In other locales it will be a different date/time, and in some locales // it doesn't exist at all, in which case this function will return None. fn get_dst_switch_hour() -> Option { - let now = time::now(); + let now = time::OffsetDateTime::now_local().unwrap(); + // Start from January 1, 2020, 00:00. - let mut tm = time::strptime("20200101-0000", "%Y%m%d-%H%M").unwrap(); - tm.tm_isdst = -1; - tm.tm_utcoff = now.tm_utcoff; - let mut ts = tm.to_timespec(); - // Loop through all hours in year 2020 until we find the hour just - // before the switch to DST. - for _i in 0..(366 * 24) { - if is_dst_switch_hour(ts) { - let mut tm = time::at(ts); - tm.tm_hour += 1; - let s = time::strftime("%Y%m%d%H%M", &tm).unwrap(); - return Some(s); - } - ts = ts + time::Duration::hours(1); - } + let tm = datetime!(2020-01-01 00:00 UTC); + tm.to_offset(now.offset()); + + // let mut ts = tm.to_timespec(); + // // Loop through all hours in year 2020 until we find the hour just + // // before the switch to DST. + // for _i in 0..(366 * 24) { + // // if is_dst_switch_hour(ts) { + // // let mut tm = time::at(ts); + // // tm.tm_hour += 1; + // // let s = time::strftime("%Y%m%d%H%M", &tm).unwrap(); + // // return Some(s); + // // } + // ts = ts + time::Duration::hours(1); + // } None } From f810b55d8660abf98e4d0aad1842a123b3160932 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 23 Apr 2022 22:05:43 +0200 Subject: [PATCH 07/62] build in verbose mode (cfg isn't used) --- .github/workflows/CICD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 967e77b60..fbe04a1db 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -384,7 +384,7 @@ 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" From 3a576f2441bb29162576d49170f42241dc0e3581 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 23 Apr 2022 21:32:35 +0200 Subject: [PATCH 08/62] time: Various fixes --- .cargo/config | 9 +++++++++ .github/workflows/CICD.yml | 2 +- Cargo.lock | 30 +++++++++++++++++++++++++--- src/uu/touch/src/touch.rs | 3 +-- src/uucore/src/lib/features/fsext.rs | 2 +- src/uucore/src/lib/features/utmpx.rs | 4 ++-- tests/by-util/test_cp.rs | 12 +++++------ tests/by-util/test_touch.rs | 26 ++++++++++++++++++++---- 8 files changed, 69 insertions(+), 19 deletions(-) diff --git a/.cargo/config b/.cargo/config index 0a8fd3d00..26008597f 100644 --- a/.cargo/config +++ b/.cargo/config @@ -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"] diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index fbe04a1db..04acd4c18 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -386,7 +386,7 @@ jobs: command: test args: -v ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -p uucore -p coreutils env: - RUSTFLAGS: "-Awarnings" + RUSTFLAGS: "-Awarnings --cfg unsound_local_offset" deps: name: Dependencies diff --git a/Cargo.lock b/Cargo.lock index 497d7ab42..69a83941b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -871,7 +871,7 @@ checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.10.0+wasi-snapshot-preview1", ] [[package]] @@ -985,6 +985,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "keccak" version = "0.1.0" @@ -1958,12 +1964,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", - "wasi", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi 0.3.9", ] [[package]] -< time::OffsetDateTime { - let ts_nanos: i128 = (self.inner.ut_tv.tv_sec as i64 * 1_000_000_000 as i64 - + self.inner.ut_tv.tv_usec as i64 * 1_000 as i64) + let ts_nanos: i128 = (self.inner.ut_tv.tv_sec as i64 * 1_000_000_000_i64 + + self.inner.ut_tv.tv_usec as i64 * 1_000_i64) .into(); let local_offset = time::OffsetDateTime::now_local().unwrap().offset(); time::OffsetDateTime::from_unix_timestamp_nanos(ts_nanos) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 079e966be..90e85b76a 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1032,8 +1032,8 @@ fn test_cp_no_deref_folder_to_folder() { #[cfg(target_os = "linux")] fn test_cp_archive() { let (at, mut ucmd) = at_and_ucmd!(); - let ts = time::now().to_timespec(); - let previous = FileTime::from_unix_time(ts.sec as i64 - 3600, ts.nsec as u32); + let ts = time::OffsetDateTime::now_local().unwrap(); + let previous = FileTime::from_unix_time(ts.unix_timestamp() - 3600, ts.nanosecond() as u32); // set the file creation/modification an hour ago filetime::set_file_times( at.plus_as_string(TEST_HELLO_WORLD_SOURCE), @@ -1135,8 +1135,8 @@ fn test_cp_archive_recursive() { #[cfg(any(target_os = "linux", target_os = "android"))] fn test_cp_preserve_timestamps() { let (at, mut ucmd) = at_and_ucmd!(); - let ts = time::now().to_timespec(); - let previous = FileTime::from_unix_time(ts.sec as i64 - 3600, ts.nsec as u32); + let ts = time::OffsetDateTime::now_local().unwrap(); + let previous = FileTime::from_unix_time(ts.unix_timestamp() - 3600, ts.nanosecond()); // set the file creation/modification an hour ago filetime::set_file_times( at.plus_as_string(TEST_HELLO_WORLD_SOURCE), @@ -1168,8 +1168,8 @@ fn test_cp_preserve_timestamps() { #[cfg(any(target_os = "linux", target_os = "android"))] fn test_cp_no_preserve_timestamps() { let (at, mut ucmd) = at_and_ucmd!(); - let ts = time::now().to_timespec(); - let previous = FileTime::from_unix_time(ts.sec as i64 - 3600, ts.nsec as u32); + let ts = time::OffsetDateTime::now_local().unwrap(); + let previous = FileTime::from_unix_time(ts.unix_timestamp() - 3600, ts.nanosecond()); // set the file creation/modification an hour ago filetime::set_file_times( at.plus_as_string(TEST_HELLO_WORLD_SOURCE), diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 6de635831..2c538d8b4 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -1,4 +1,10 @@ -// spell-checker:ignore (formats) cymdhm cymdhms mdhm mdhms ymdhm ymdhms +// spell-checker:ignore (formats) cymdhm cymdhms mdhm mdhms ymdhm ymdhms datetime mktime + +// This test relies on +// --cfg unsound_local_offset +// https://github.com/time-rs/time/blob/deb8161b84f355b31e39ce09e40c4d6ce3fea837/src/sys/local_offset_at/unix.rs#L112-L120= +// See https://github.com/time-rs/time/issues/293#issuecomment-946382614= +// Defined in .cargo/config extern crate touch; use self::touch::filetime::{self, FileTime}; @@ -42,8 +48,14 @@ fn str_to_filetime(format: &str, s: &str) -> FileTime { "%Y%m%d%H%M.%S" => format_description!("[year][month][day][hour][minute].[second]"), _ => panic!("unexpected dt format"), }; - let tm = time::PrimitiveDateTime::parse(&s, &format_description).unwrap(); - let offset_dt = tm.assume_offset(time::OffsetDateTime::now_local().unwrap().offset()); + let tm = time::PrimitiveDateTime::parse(s, &format_description).unwrap(); + let d = match time::OffsetDateTime::now_local() { + Ok(now) => now, + Err(e) => { + panic!("Error {} retrieving the OffsetDateTime::now_local", e); + } + }; + let offset_dt = tm.assume_offset(d.offset()); FileTime::from_unix_time(offset_dt.unix_timestamp(), tm.nanosecond()) } @@ -461,7 +473,13 @@ fn test_touch_mtime_dst_succeeds() { // In other locales it will be a different date/time, and in some locales // it doesn't exist at all, in which case this function will return None. fn get_dst_switch_hour() -> Option { - let now = time::OffsetDateTime::now_local().unwrap(); + //let now = time::OffsetDateTime::now_local().unwrap(); + let now = match time::OffsetDateTime::now_local() { + Ok(now) => now, + Err(e) => { + panic!("Error {} retrieving the OffsetDateTime::now_local", e); + } + }; // Start from January 1, 2020, 00:00. let tm = datetime!(2020-01-01 00:00 UTC); From e23dd687155c91e50d1c9f90dbfe7d9ef047657a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 24 Apr 2022 09:50:39 +0200 Subject: [PATCH 09/62] time: Force the display of the tz sign --- src/uucore/src/lib/features/fsext.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index 75a0c2f97..0d64661ee 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -733,7 +733,7 @@ where } // match strftime "%Y-%m-%d %H:%M:%S.%f %z" -const PRETTY_DATETIME_FORMAT: &[time::format_description::FormatItem] = format_description!("[year]-[month]-[day padding:zero] [hour]:[minute]:[second].[subsecond] [offset_hour][offset_minute]"); +const PRETTY_DATETIME_FORMAT: &[time::format_description::FormatItem] = format_description!("[year]-[month]-[day padding:zero] [hour]:[minute]:[second].[subsecond] [offset_hour sign:mandatory][offset_minute]"); pub fn pretty_time(sec: i64, nsec: i64) -> String { // sec == seconds since UNIX_EPOCH From 326dc5080d74dd79406fa828e1754d50e78e9e8e Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 24 Apr 2022 09:50:58 +0200 Subject: [PATCH 10/62] stat: add a test to verify time easily --- tests/by-util/test_stat.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 90ad2d12a..6140f5017 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -283,6 +283,25 @@ fn test_char() { ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); } +#[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))] +#[test] +fn test_date() { + // Just test the date for the time 0.3 change + let args = [ + "-c", + #[cfg(any(target_os = "linux", target_os = "android"))] + "%z", + #[cfg(target_os = "linux")] + "/dev/pts/ptmx", + #[cfg(any(target_vendor = "apple"))] + "%z", + #[cfg(any(target_os = "android", target_vendor = "apple"))] + "/dev/ptmx", + ]; + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); +} #[cfg(unix)] #[test] fn test_multi_files() { From 10eaaae2723f61f8588dabcb78df9ec57f7ce80c Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 24 Apr 2022 09:51:15 +0200 Subject: [PATCH 11/62] time: take in account the local tz --- src/uucore/src/lib/features/fsext.rs | 29 ++++++++++++++++++++++++---- tests/by-util/test_stat.rs | 17 +++++++++++++++- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index 0d64661ee..3f5b2b77c 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -13,6 +13,7 @@ extern crate time; use time::macros::format_description; +use time::UtcOffset; pub use crate::*; // import macros from `../../macros.rs` @@ -733,16 +734,36 @@ where } // match strftime "%Y-%m-%d %H:%M:%S.%f %z" -const PRETTY_DATETIME_FORMAT: &[time::format_description::FormatItem] = format_description!("[year]-[month]-[day padding:zero] [hour]:[minute]:[second].[subsecond] [offset_hour sign:mandatory][offset_minute]"); +const PRETTY_DATETIME_FORMAT: &[time::format_description::FormatItem] = format_description!("[year]-[month]-[day padding:zero] [hour]:[minute]:[second].[subsecond digits:9] [offset_hour sign:mandatory][offset_minute]"); pub fn pretty_time(sec: i64, nsec: i64) -> String { // sec == seconds since UNIX_EPOCH // nsec == nanoseconds since (UNIX_EPOCH + sec) let ts_nanos: i128 = (sec * 1_000_000_000 + nsec).into(); - // TODO: return errors to caller - let tm = time::OffsetDateTime::from_unix_timestamp_nanos(ts_nanos).unwrap(); - let res = tm.format(&PRETTY_DATETIME_FORMAT).unwrap(); + // Return the date in UTC + let tm = match time::OffsetDateTime::from_unix_timestamp_nanos(ts_nanos) { + Ok(tm) => tm, + Err(e) => { + panic!("error: {}", e); + } + }; + + // Get the offset to convert to local time + // Because of DST (daylight saving), we get the local time back when + // the date was set + let local_offset = match UtcOffset::local_offset_at(tm) { + Ok(lo) => lo, + Err(e) => { + panic!("error: {}", e); + } + }; + + // Include the conversion to local time + let res = tm + .to_offset(local_offset) + .format(&PRETTY_DATETIME_FORMAT) + .unwrap(); if res.ends_with(" -0000") { res.replace(" -0000", " +0000") } else { diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 6140f5017..0871a48fe 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -292,7 +292,22 @@ fn test_date() { #[cfg(any(target_os = "linux", target_os = "android"))] "%z", #[cfg(target_os = "linux")] - "/dev/pts/ptmx", + "/bin/sh", + #[cfg(any(target_vendor = "apple"))] + "%z", + #[cfg(any(target_os = "android", target_vendor = "apple"))] + "/bin/sh", + ]; + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); + // Just test the date for the time 0.3 change + let args = [ + "-c", + #[cfg(any(target_os = "linux", target_os = "android"))] + "%z", + #[cfg(target_os = "linux")] + "/dev/ptmx", #[cfg(any(target_vendor = "apple"))] "%z", #[cfg(any(target_os = "android", target_vendor = "apple"))] From 3b3585bbe548a5259944685f3114c84730155929 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 27 Apr 2022 08:43:59 +0200 Subject: [PATCH 12/62] add time 0.1.44 to cargo deny And no longer ignore RUSTSEC-2022-0013 --- deny.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deny.toml b/deny.toml index 1d790456f..f659910e8 100644 --- a/deny.toml +++ b/deny.toml @@ -12,7 +12,6 @@ yanked = "warn" notice = "warn" ignore = [ "RUSTSEC-2020-0159", - "RUSTSEC-2022-0013", "RUSTSEC-2020-0071", #"RUSTSEC-0000-0000", ] @@ -87,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 From c009e1bed8a5b9c5eef667584fcf2b632dcdfaa2 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Thu, 28 Apr 2022 00:06:07 +0200 Subject: [PATCH 13/62] workaround the tests/touch/60-seconds test to skip leap second --- src/uu/touch/src/touch.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index a3a344ad4..e74aaa700 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -337,7 +337,12 @@ fn parse_timestamp(s: &str) -> UResult { format = YYYYMMDDHHMM_DOT_SS_FORMAT; ts = "20".to_owned() + &ts; } - + if (format == YYYYMMDDHHMM_DOT_SS_FORMAT || format == YYMMDDHHMM_DOT_SS_FORMAT) + && ts.ends_with(".60") + { + // Work around to disable leap seconds + ts = ts.replace(".60", ".59"); + } let tm = time::PrimitiveDateTime::parse(&ts, &format) .map_err(|_| USimpleError::new(1, format!("invalid date ts format {}", ts.quote())))?; From 2b11d773952fb45de8fa0a4360b67c160f24ed49 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Thu, 28 Apr 2022 08:22:48 +0200 Subject: [PATCH 14/62] time: Improve the l&f --- src/uu/touch/src/touch.rs | 24 ++++++++++++++++-------- src/uucore/Cargo.toml | 2 +- src/uucore/src/lib/features/fsext.rs | 7 ++++++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index e74aaa700..9a4c0fe5d 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -247,7 +247,8 @@ fn stat(path: &Path, follow: bool) -> UResult<(FileTime, FileTime)> { } const POSIX_LOCALE_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[weekday repr:short] [month repr:short] [day padding:space] [hour]:[minute]:[second] [year]" + "[weekday repr:short] [month repr:short] [day padding:space] \ + [hour]:[minute]:[second] [year]" ); const ISO_8601_FORMAT: &[time::format_description::FormatItem] = @@ -294,20 +295,27 @@ fn parse_date(s: &str) -> UResult { // "%Y%m%d%H%M.%S" 15 chars const YYYYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:full][month repr:numerical padding:zero][day][hour][minute].[second]" + "[year repr:full][month repr:numerical padding:zero]\ + [day][hour][minute].[second]" ); // "%Y%m%d%H%M" 12 chars -const YYYYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = - format_description!("[year repr:full][month repr:numerical padding:zero][day][hour][minute]"); +const YYYYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full][month repr:numerical padding:zero]\ + [day][hour][minute]" +); // "%y%m%d%H%M.%S" 13 chars -const YYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = - format_description!("[year repr:last_two padding:none][month][day][hour][minute].[second]"); +const YYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:last_two padding:none][month][day]\ + [hour][minute].[second]" +); // "%y%m%d%H%M" 10 chars -const YYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = - format_description!("[year repr:last_two padding:none][month padding:zero][day padding:zero][hour repr:24 padding:zero][minute padding:zero]"); +const YYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:last_two padding:none][month padding:zero][day padding:zero]\ + [hour repr:24 padding:zero][minute padding:zero]" +); fn parse_timestamp(s: &str) -> UResult { // TODO: handle error diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 5b363376d..c86a8cf07 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -26,7 +26,7 @@ wild = "2.0" # * optional itertools = { version="0.10.0", optional=true } thiserror = { version="1.0", optional=true } -time = { version="<= 0.3.10", optional=true, features = ["formatting", "local-offset", "macros"] } +time = { version="<= 0.3", optional=true, features = ["formatting", "local-offset", "macros"] } # * "problem" dependencies (pinned) data-encoding = { version="2.1", optional=true } data-encoding-macro = { version="0.1.12", optional=true } diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index 3f5b2b77c..3d7ca1c1f 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -734,7 +734,12 @@ where } // match strftime "%Y-%m-%d %H:%M:%S.%f %z" -const PRETTY_DATETIME_FORMAT: &[time::format_description::FormatItem] = format_description!("[year]-[month]-[day padding:zero] [hour]:[minute]:[second].[subsecond digits:9] [offset_hour sign:mandatory][offset_minute]"); +const PRETTY_DATETIME_FORMAT: &[time::format_description::FormatItem] = format_description!( + "\ +[year]-[month]-[day padding:zero] \ +[hour]:[minute]:[second].[subsecond digits:9] \ +[offset_hour sign:mandatory][offset_minute]" +); pub fn pretty_time(sec: i64, nsec: i64) -> String { // sec == seconds since UNIX_EPOCH From 31c28eeaa98854797eb432aa6c890002c5133b0b Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 29 Apr 2022 10:28:49 +0200 Subject: [PATCH 15/62] fix gnu/tests/touch/60-seconds --- src/uu/touch/src/touch.rs | 18 ++++++++++++++---- tests/by-util/test_touch.rs | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 9a4c0fe5d..331867b5f 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -17,6 +17,7 @@ use filetime::*; use std::fs::{self, File}; use std::path::{Path, PathBuf}; use time::macros::{format_description, time}; +use time::Duration; use uucore::display::Quotable; use uucore::error::{FromIo, UError, UResult, USimpleError}; use uucore::format_usage; @@ -345,16 +346,25 @@ fn parse_timestamp(s: &str) -> UResult { format = YYYYMMDDHHMM_DOT_SS_FORMAT; ts = "20".to_owned() + &ts; } - if (format == YYYYMMDDHHMM_DOT_SS_FORMAT || format == YYMMDDHHMM_DOT_SS_FORMAT) + + let leap_sec = if (format == YYYYMMDDHHMM_DOT_SS_FORMAT || format == YYMMDDHHMM_DOT_SS_FORMAT) && ts.ends_with(".60") { // Work around to disable leap seconds + // Used in gnu/tests/touch/60-seconds ts = ts.replace(".60", ".59"); - } + true + } else { + false + }; + let tm = time::PrimitiveDateTime::parse(&ts, &format) .map_err(|_| USimpleError::new(1, format!("invalid date ts format {}", ts.quote())))?; - - let local = to_local(tm); + let mut local = to_local(tm); + if leap_sec { + // We are dealing with a leap second, add it + local = local.saturating_add(Duration::SECOND); + } let ft = local_dt_to_filetime(local); // // We have to check that ft is valid time. Due to daylight saving diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 2c538d8b4..d23fb090e 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -603,3 +603,21 @@ fn test_no_dereference_no_file() { .stderr_contains("setting times of 'not-a-file-1': No such file or directory") .stderr_contains("setting times of 'not-a-file-2': No such file or directory"); } + +#[test] +fn test_touch_leap_second() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "test_touch_leap_sec"; + + ucmd.args(&["-t", "197001010000.60", file]) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(file)); + + let epoch = str_to_filetime("%Y%m%d%H%M", "197001010000"); + let (atime, mtime) = get_file_times(&at, file); + assert_eq!(atime, mtime); + assert_eq!(atime.unix_seconds() - epoch.unix_seconds(), 60); + assert_eq!(mtime.unix_seconds() - epoch.unix_seconds(), 60); +} From 9d81d6fef2729db4765529cf4b3b195a4b513626 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 29 Apr 2022 10:32:28 +0200 Subject: [PATCH 16/62] touch: add support of -d '1970-01-01 18:43:33.023456789' --- deny.toml | 2 +- src/uu/touch/src/touch.rs | 74 +++++++++++++++++++++++-------------- tests/by-util/test_touch.rs | 36 ++++++++++++++++++ 3 files changed, 84 insertions(+), 28 deletions(-) diff --git a/deny.toml b/deny.toml index f659910e8..8154bbf90 100644 --- a/deny.toml +++ b/deny.toml @@ -64,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 diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 331867b5f..5264401ef 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -6,7 +6,7 @@ // For the full copyright and license information, please view the LICENSE file // that was distributed with this source code. -// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm clapv PWSTR lpszfilepath hresult mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME subsecond +// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm clapv PWSTR lpszfilepath hresult mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME YYYYMMDDHHMMS pub extern crate filetime; #[macro_use] @@ -255,6 +255,41 @@ const POSIX_LOCALE_FORMAT: &[time::format_description::FormatItem] = format_desc const ISO_8601_FORMAT: &[time::format_description::FormatItem] = format_description!("[year]-[month]-[day]"); +// "%Y%m%d%H%M.%S" 15 chars +const YYYYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full][month repr:numerical padding:zero]\ + [day][hour][minute].[second]" +); + +// "%Y-%m-%d %H:%M:%S.%SS" 12 chars +const YYYYMMDDHHMMSS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full]-[month repr:numerical padding:zero]-\ + [day] [hour]:[minute]:[second].[subsecond]" +); +// "%Y-%m-%d %H:%M:%S" 12 chars +const YYYYMMDDHHMMS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full]-[month repr:numerical padding:zero]-\ + [day] [hour]:[minute]:[second]" +); + +// "%Y%m%d%H%M" 12 chars +const YYYYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full][month repr:numerical padding:zero]\ + [day][hour][minute]" +); + +// "%y%m%d%H%M.%S" 13 chars +const YYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:last_two padding:none][month][day]\ + [hour][minute].[second]" +); + +// "%y%m%d%H%M" 10 chars +const YYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:last_two padding:none][month padding:zero][day padding:zero]\ + [hour repr:24 padding:zero][minute padding:zero]" +); + fn parse_date(s: &str) -> UResult { // This isn't actually compatible with GNU touch, but there doesn't seem to // be any simple specification for what format this parameter allows and I'm @@ -269,8 +304,17 @@ fn parse_date(s: &str) -> UResult { // which is equivalent to the POSIX locale: %a %b %e %H:%M:%S %Y // Tue Dec 3 ... // ("%c", POSIX_LOCALE_FORMAT), - if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &POSIX_LOCALE_FORMAT) { - return Ok(local_dt_to_filetime(to_local(parsed))); + // + // But also support other format found in the GNU tests like + // in tests/misc/stat-nanoseconds.sh + for fmt in [ + POSIX_LOCALE_FORMAT, + YYYYMMDDHHMMS_FORMAT, + YYYYMMDDHHMMSS_FORMAT, + ] { + if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &fmt) { + return Ok(local_dt_to_filetime(to_local(parsed))); + } } // "Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99)" @@ -294,30 +338,6 @@ fn parse_date(s: &str) -> UResult { Err(USimpleError::new(1, format!("Unable to parse date: {}", s))) } -// "%Y%m%d%H%M.%S" 15 chars -const YYYYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:full][month repr:numerical padding:zero]\ - [day][hour][minute].[second]" -); - -// "%Y%m%d%H%M" 12 chars -const YYYYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:full][month repr:numerical padding:zero]\ - [day][hour][minute]" -); - -// "%y%m%d%H%M.%S" 13 chars -const YYMMDDHHMM_DOT_SS_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:last_two padding:none][month][day]\ - [hour][minute].[second]" -); - -// "%y%m%d%H%M" 10 chars -const YYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( - "[year repr:last_two padding:none][month padding:zero][day padding:zero]\ - [hour repr:24 padding:zero][minute padding:zero]" -); - fn parse_timestamp(s: &str) -> UResult { // TODO: handle error let now = time::OffsetDateTime::now_utc(); diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index d23fb090e..ed62692f4 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -427,6 +427,42 @@ fn test_touch_set_date3() { assert_eq!(mtime, expected); } +#[test] +fn test_touch_set_date4() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "test_touch_set_date"; + + ucmd.args(&["-d", "1970-01-01 18:43:33", file]) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(file)); + + let expected = FileTime::from_unix_time(60213, 0); + let (atime, mtime) = get_file_times(&at, file); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); +} + +#[test] +fn test_touch_set_date5() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "test_touch_set_date"; + + ucmd.args(&["-d", "1970-01-01 18:43:33.023456789", file]) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(file)); + + let expected = FileTime::from_unix_time(60213, 023456789); + let (atime, mtime) = get_file_times(&at, file); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); +} + #[test] fn test_touch_set_date_wrong_format() { let (_at, mut ucmd) = at_and_ucmd!(); From 417b4a22d093c225c78d4fffca17b8926a261912 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 1 May 2022 17:07:29 +0200 Subject: [PATCH 17/62] GNU CI: show the new error --- .github/workflows/GnuTests.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index d306092c6..fedd6e4d5 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -170,6 +170,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/^FAIL: \([[:print:]]\+\).*/\1/p" "${REF_LOG_FILE}" | sort) + NEW_ERROR=$(sed -n "s/^FAIL: \([[: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 +188,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 failed: ${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 From ae65dcc7d2affbf6b50145ed38f58e04f2bd1b86 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 1 May 2022 17:07:29 +0200 Subject: [PATCH 18/62] GNU CI: show the new error --- .github/workflows/GnuTests.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index d306092c6..f2b0ddd45 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -170,6 +170,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/^FAIL: \([[:print:]]\+\).*/\1/p" "${REF_LOG_FILE}" | sort) + NEW_ERROR=$(sed -n "s/^FAIL: \([[: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 +188,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 From 0314f3ed8e6b0560fa67d2d6cf48133161334575 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 1 May 2022 12:51:40 +0200 Subject: [PATCH 19/62] GNU testsuite: no need to rerun the GNU build At least, two use cases: * when hacking on test update * when we want to rebuild only Rust coreutils with the right option Indeed, the GNU code should not cache often in this case --- util/build-gnu.sh | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 6f0ec32f7..83993fde9 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -62,14 +62,23 @@ for binary in $(./build-aux/gen-lists-of-programs.sh --list-progs); do } done -./bootstrap -./configure --quiet --disable-gcc-warnings -#Add timeout to to protect against hangs -sed -i 's|^"\$@|/usr/bin/timeout 600 "\$@|' build-aux/test-driver -# Change the PATH in the Makefile to test the uutils coreutils instead of the GNU coreutils -sed -i "s/^[[:blank:]]*PATH=.*/ PATH='${UU_BUILD_DIR//\//\\/}\$(PATH_SEPARATOR)'\"\$\$PATH\" \\\/" Makefile -sed -i 's| tr | /usr/bin/tr |' tests/init.sh -make -j "$(nproc)" +if test -f gnu-built; then + echo "GNU build already found. Skip" + echo "'rm -f $(pwd)/gnu-built' to force the build" + echo "Note: the customization of the tests will still happen" + exit 0 +else + ./bootstrap + ./configure --quiet --disable-gcc-warnings + #Add timeout to to protect against hangs + sed -i 's|^"\$@|/usr/bin/timeout 600 "\$@|' build-aux/test-driver + # Change the PATH in the Makefile to test the uutils coreutils instead of the GNU coreutils + sed -i "s/^[[:blank:]]*PATH=.*/ PATH='${UU_BUILD_DIR//\//\\/}\$(PATH_SEPARATOR)'\"\$\$PATH\" \\\/" Makefile + sed -i 's| tr | /usr/bin/tr |' tests/init.sh + make -j "$(nproc)" + touch gnu-built +fi + # Handle generated factor tests t_first=00 t_max=36 From 2e60dce11a04c69b697b884020185e85fda14061 Mon Sep 17 00:00:00 2001 From: Hanif Ariffin Date: Fri, 4 Feb 2022 19:29:24 +0800 Subject: [PATCH 20/62] printf: Default left-justify integer conversion to 1 width When using left-justify with integer conversion (like `printf '%-o'`), default the minimum width to 1. Closes: https://github.com/uutils/coreutils/issues/3050 Signed-off-by: Hanif Ariffin --- src/uucore/src/lib/features/tokenize/sub.rs | 6 +++++- tests/by-util/test_printf.rs | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/uucore/src/lib/features/tokenize/sub.rs b/src/uucore/src/lib/features/tokenize/sub.rs index f8b5b5caf..216953a43 100644 --- a/src/uucore/src/lib/features/tokenize/sub.rs +++ b/src/uucore/src/lib/features/tokenize/sub.rs @@ -152,7 +152,11 @@ impl SubParser { if parser.min_width_is_asterisk { CanAsterisk::Asterisk } else { - CanAsterisk::Fixed(parser.min_width_tmp.map(|x| x.parse::().unwrap())) + CanAsterisk::Fixed( + parser + .min_width_tmp + .map(|x| x.parse::().unwrap_or(1)), + ) }, if parser.second_field_is_asterisk { CanAsterisk::Asterisk diff --git a/tests/by-util/test_printf.rs b/tests/by-util/test_printf.rs index d5be4cd17..77f64750c 100644 --- a/tests/by-util/test_printf.rs +++ b/tests/by-util/test_printf.rs @@ -446,6 +446,14 @@ fn sub_any_specifiers_after_period() { .stdout_only("3"); } +#[test] +fn unspecified_left_justify_is_1_width() { + new_ucmd!() + .args(&["%-o"]) //spell-checker:disable-line + .succeeds() + .stdout_only("0"); +} + #[test] fn sub_any_specifiers_after_second_param() { new_ucmd!() From e991838ca8072b58ceccc3e9fd3b784cb0f61a71 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sun, 19 Sep 2021 22:24:11 +0200 Subject: [PATCH 21/62] tests/util: add a convenience wrapper to run a ucmd with root permissions --- tests/common/util.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/common/util.rs b/tests/common/util.rs index 5a669fcd4..47f8eb842 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1362,6 +1362,58 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< )) } +/// This is a convenience wrapper to run a ucmd with root permissions. +/// This runs 'sudo -E --non-interactive target/debug/coreutils util_name args` +/// This is primarily designed to run in the CICD environment where whoami is in $path +/// and where non-interactive sudo is possible. +/// To check if i) non-interactive sudo is possible and ii) if sudo works, this runs: +/// 'sudo -E --non-interactive whoami' first. +/// +/// Example: +/// +/// ```no_run +/// use crate::common::util::*; +/// #[test] +/// fn test_xyz() { +/// let ts = TestScenario::new("whoami"); +/// let expected = "root\n".to_string(); +/// if let Ok(result) = run_ucmd_as_root(&ts, &[]) { +/// result.stdout_is(expected); +/// } else { +/// print!("TEST SKIPPED"); +/// } +/// } +///``` +#[cfg(unix)] +pub fn run_ucmd_as_root( + ts: &TestScenario, + args: &[&str], +) -> std::result::Result { + if ts + .cmd_keepenv("sudo") + .env("LC_ALL", "C") + .arg("-E") + .arg("--non-interactive") + .arg("whoami") + .run() + .stdout_str() + .trim() + != "root" + { + Err("\"sudo whoami\" didn't return \"root\"".to_string()) + } else { + Ok(ts + .cmd_keepenv("sudo") + .env("LC_ALL", "C") + .arg("-E") + .arg("--non-interactive") + .arg(&ts.bin_path) + .arg(&ts.util_name) + .args(args) + .run()) + } +} + /// Sanity checks for test utils #[cfg(test)] mod tests { @@ -1712,4 +1764,20 @@ mod tests { std::assert_eq!(host_name_for("gwho"), "gwho"); } } + + #[test] + #[cfg(unix)] + fn test_run_ucmd_as_root() { + // We need non-interactive `sudo. + // CICD environment should allow non-interactive `sudo`. + // Return early if we can't guarantee non-interactive `sudo` + if !is_ci() { + return; + } + let ts = TestScenario::new("whoami"); + std::assert_eq!( + run_ucmd_as_root(&ts, &[]).unwrap().stdout_str().trim(), + "root" + ); + } } From de01b11a7d2a332153a2db948e4d8ef4f1f493c2 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Mon, 20 Sep 2021 00:20:06 +0200 Subject: [PATCH 22/62] Update util.rs add feature for `whoami` --- tests/common/util.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/common/util.rs b/tests/common/util.rs index 47f8eb842..a0eb12459 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1767,6 +1767,7 @@ mod tests { #[test] #[cfg(unix)] + #[cfg(feature = "whoami")] fn test_run_ucmd_as_root() { // We need non-interactive `sudo. // CICD environment should allow non-interactive `sudo`. From bab7ba8a527f441e6cccb543b5fc5f64cbef4e04 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Tue, 21 Sep 2021 00:23:23 +0200 Subject: [PATCH 23/62] Update util.rs --- tests/common/util.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/common/util.rs b/tests/common/util.rs index a0eb12459..05cc6937a 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1364,7 +1364,7 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< /// This is a convenience wrapper to run a ucmd with root permissions. /// This runs 'sudo -E --non-interactive target/debug/coreutils util_name args` -/// This is primarily designed to run in the CICD environment where whoami is in $path +/// This is primarily designed to run in an environment where whoami is in $path /// and where non-interactive sudo is possible. /// To check if i) non-interactive sudo is possible and ii) if sudo works, this runs: /// 'sudo -E --non-interactive whoami' first. @@ -1389,6 +1389,7 @@ pub fn run_ucmd_as_root( ts: &TestScenario, args: &[&str], ) -> std::result::Result { + // Apparently CICD environment has no `sudo`? if ts .cmd_keepenv("sudo") .env("LC_ALL", "C") @@ -1769,16 +1770,18 @@ mod tests { #[cfg(unix)] #[cfg(feature = "whoami")] fn test_run_ucmd_as_root() { - // We need non-interactive `sudo. - // CICD environment should allow non-interactive `sudo`. - // Return early if we can't guarantee non-interactive `sudo` - if !is_ci() { - return; + // Skip test if we can't guarantee non-interactive `sudo`. + if let Ok(_status) = Command::new("sudo") + .args(&["-E", "-v", "--non-interactive"]) + .status() + { + let ts = TestScenario::new("whoami"); + std::assert_eq!( + run_ucmd_as_root(&ts, &[]).unwrap().stdout_str().trim(), + "root" + ); + } else { + print!("TEST SKIPPED"); } - let ts = TestScenario::new("whoami"); - std::assert_eq!( - run_ucmd_as_root(&ts, &[]).unwrap().stdout_str().trim(), - "root" - ); } } From eaad6c5286d435285fefea0a84913ecdbc0df356 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 30 Jan 2022 10:05:05 +0100 Subject: [PATCH 24/62] more comment mostly to retrigger the ci :) --- tests/common/util.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/common/util.rs b/tests/common/util.rs index 05cc6937a..34bdc72f3 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1363,6 +1363,7 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< } /// This is a convenience wrapper to run a ucmd with root permissions. +/// It can be used to test programs when being root is needed /// This runs 'sudo -E --non-interactive target/debug/coreutils util_name args` /// This is primarily designed to run in an environment where whoami is in $path /// and where non-interactive sudo is possible. From 0dc3eafaa43789acd73985eb4079f2a02f32b576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 06:36:27 +0000 Subject: [PATCH 25/62] build(deps): bump clap_complete from 3.1.2 to 3.1.3 Bumps [clap_complete](https://github.com/clap-rs/clap) from 3.1.2 to 3.1.3. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v3.1.2...clap_complete-v3.1.3) --- updated-dependencies: - dependency-name: clap_complete dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a24abb936..a99566220 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,9 +273,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1506b87ee866f7a53a5131f7b31fba656170d797e873d0609884cfd56b8bbda8" +checksum = "1d7ca9141e27e6ebc52e3c378b0c07f3cea52db46ed1cc5861735fb697b56356" dependencies = [ "clap 3.1.12", ] From de6aa6de9b2df29c81b117dcabb8ef1c9ff2f5fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 06:36:41 +0000 Subject: [PATCH 26/62] build(deps): bump libc from 0.2.124 to 0.2.125 Bumps [libc](https://github.com/rust-lang/libc) from 0.2.124 to 0.2.125. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.124...0.2.125) --- updated-dependencies: - dependency-name: libc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- src/uu/chmod/Cargo.toml | 2 +- src/uu/cp/Cargo.toml | 2 +- src/uu/hostid/Cargo.toml | 2 +- src/uu/kill/Cargo.toml | 2 +- src/uu/logname/Cargo.toml | 2 +- src/uu/mkfifo/Cargo.toml | 2 +- src/uu/mknod/Cargo.toml | 2 +- src/uu/nice/Cargo.toml | 2 +- src/uu/nohup/Cargo.toml | 2 +- src/uu/nproc/Cargo.toml | 2 +- src/uu/pathchk/Cargo.toml | 2 +- src/uu/rmdir/Cargo.toml | 2 +- src/uu/sync/Cargo.toml | 2 +- src/uu/tail/Cargo.toml | 2 +- src/uu/tee/Cargo.toml | 2 +- src/uu/test/Cargo.toml | 2 +- src/uu/timeout/Cargo.toml | 2 +- src/uu/tty/Cargo.toml | 2 +- src/uu/whoami/Cargo.toml | 2 +- src/uucore/Cargo.toml | 2 +- 21 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a24abb936..2a46b14ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1015,9 +1015,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.124" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libloading" diff --git a/src/uu/chmod/Cargo.toml b/src/uu/chmod/Cargo.toml index 9fab6011e..df0b089fa 100644 --- a/src/uu/chmod/Cargo.toml +++ b/src/uu/chmod/Cargo.toml @@ -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]] diff --git a/src/uu/cp/Cargo.toml b/src/uu/cp/Cargo.toml index 9e1141650..f9036101a 100644 --- a/src/uu/cp/Cargo.toml +++ b/src/uu/cp/Cargo.toml @@ -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"] } diff --git a/src/uu/hostid/Cargo.toml b/src/uu/hostid/Cargo.toml index 0a2948459..d29160b21 100644 --- a/src/uu/hostid/Cargo.toml +++ b/src/uu/hostid/Cargo.toml @@ -16,7 +16,7 @@ path = "src/hostid.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" } [[bin]] diff --git a/src/uu/kill/Cargo.toml b/src/uu/kill/Cargo.toml index 354ad1d3f..24347a90a 100644 --- a/src/uu/kill/Cargo.toml +++ b/src/uu/kill/Cargo.toml @@ -16,7 +16,7 @@ path = "src/kill.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=["signals"] } [[bin]] diff --git a/src/uu/logname/Cargo.toml b/src/uu/logname/Cargo.toml index 22b976dd6..fe7f2f738 100644 --- a/src/uu/logname/Cargo.toml +++ b/src/uu/logname/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/logname.rs" [dependencies] -libc = "0.2.124" +libc = "0.2.125" clap = { version = "3.1", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.11", package="uucore", path="../../uucore" } diff --git a/src/uu/mkfifo/Cargo.toml b/src/uu/mkfifo/Cargo.toml index a6c801747..821d67d53 100644 --- a/src/uu/mkfifo/Cargo.toml +++ b/src/uu/mkfifo/Cargo.toml @@ -16,7 +16,7 @@ path = "src/mkfifo.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" } [[bin]] diff --git a/src/uu/mknod/Cargo.toml b/src/uu/mknod/Cargo.toml index 53cc62313..88c9e3fb0 100644 --- a/src/uu/mknod/Cargo.toml +++ b/src/uu/mknod/Cargo.toml @@ -17,7 +17,7 @@ path = "src/mknod.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=["mode"] } [[bin]] diff --git a/src/uu/nice/Cargo.toml b/src/uu/nice/Cargo.toml index ab4b6c700..9b6ca52bd 100644 --- a/src/uu/nice/Cargo.toml +++ b/src/uu/nice/Cargo.toml @@ -16,7 +16,7 @@ path = "src/nice.rs" [dependencies] clap = { version = "3.1", features = ["wrap_help", "cargo"] } -libc = "0.2.124" +libc = "0.2.125" nix = { version = "0.24.1", default-features = false } uucore = { version=">=0.0.11", package="uucore", path="../../uucore" } diff --git a/src/uu/nohup/Cargo.toml b/src/uu/nohup/Cargo.toml index 26e5fd7ae..ba38a7ecd 100644 --- a/src/uu/nohup/Cargo.toml +++ b/src/uu/nohup/Cargo.toml @@ -16,7 +16,7 @@ path = "src/nohup.rs" [dependencies] clap = { version = "3.1", features = ["wrap_help", "cargo"] } -libc = "0.2.124" +libc = "0.2.125" atty = "0.2" uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["fs"] } diff --git a/src/uu/nproc/Cargo.toml b/src/uu/nproc/Cargo.toml index 80c1cb38b..f52f2d0db 100644 --- a/src/uu/nproc/Cargo.toml +++ b/src/uu/nproc/Cargo.toml @@ -15,7 +15,7 @@ edition = "2021" path = "src/nproc.rs" [dependencies] -libc = "0.2.124" +libc = "0.2.125" num_cpus = "1.10" clap = { version = "3.1", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["fs"] } diff --git a/src/uu/pathchk/Cargo.toml b/src/uu/pathchk/Cargo.toml index 44cab8559..dd8b83076 100644 --- a/src/uu/pathchk/Cargo.toml +++ b/src/uu/pathchk/Cargo.toml @@ -16,7 +16,7 @@ path = "src/pathchk.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" } [[bin]] diff --git a/src/uu/rmdir/Cargo.toml b/src/uu/rmdir/Cargo.toml index b61def5ad..0894fa411 100644 --- a/src/uu/rmdir/Cargo.toml +++ b/src/uu/rmdir/Cargo.toml @@ -17,7 +17,7 @@ path = "src/rmdir.rs" [dependencies] clap = { version = "3.1", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.11", package="uucore", path="../../uucore" } -libc = "0.2.124" +libc = "0.2.125" [[bin]] name = "rmdir" diff --git a/src/uu/sync/Cargo.toml b/src/uu/sync/Cargo.toml index ece7a5930..f6e57391d 100644 --- a/src/uu/sync/Cargo.toml +++ b/src/uu/sync/Cargo.toml @@ -16,7 +16,7 @@ path = "src/sync.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=["wide"] } winapi = { version = "0.3", features = ["errhandlingapi", "fileapi", "handleapi", "std", "winbase", "winerror"] } diff --git a/src/uu/tail/Cargo.toml b/src/uu/tail/Cargo.toml index eebbf9606..7006ddb67 100644 --- a/src/uu/tail/Cargo.toml +++ b/src/uu/tail/Cargo.toml @@ -16,7 +16,7 @@ path = "src/tail.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=["ringbuffer", "lines"] } [target.'cfg(windows)'.dependencies] diff --git a/src/uu/tee/Cargo.toml b/src/uu/tee/Cargo.toml index 7257d9854..07ee9e33b 100644 --- a/src/uu/tee/Cargo.toml +++ b/src/uu/tee/Cargo.toml @@ -16,7 +16,7 @@ path = "src/tee.rs" [dependencies] clap = { version = "3.1", features = ["wrap_help", "cargo"] } -libc = "0.2.124" +libc = "0.2.125" retain_mut = "=0.1.7" # ToDO: [2021-01-01; rivy; maint/MinSRV] ~ v0.1.5 uses const generics which aren't stabilized until rust v1.51.0 uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["libc"] } diff --git a/src/uu/test/Cargo.toml b/src/uu/test/Cargo.toml index 6bd1cfc90..58f891541 100644 --- a/src/uu/test/Cargo.toml +++ b/src/uu/test/Cargo.toml @@ -16,7 +16,7 @@ path = "src/test.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" } [target.'cfg(target_os = "redox")'.dependencies] diff --git a/src/uu/timeout/Cargo.toml b/src/uu/timeout/Cargo.toml index e555cb1b7..d285c3214 100644 --- a/src/uu/timeout/Cargo.toml +++ b/src/uu/timeout/Cargo.toml @@ -16,7 +16,7 @@ path = "src/timeout.rs" [dependencies] clap = { version = "3.1", features = ["wrap_help", "cargo"] } -libc = "0.2.124" +libc = "0.2.125" nix = { version = "0.24.1", default-features = false, features = ["signal"] } uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["process", "signals"] } diff --git a/src/uu/tty/Cargo.toml b/src/uu/tty/Cargo.toml index 2f3438558..da6446ab0 100644 --- a/src/uu/tty/Cargo.toml +++ b/src/uu/tty/Cargo.toml @@ -16,7 +16,7 @@ path = "src/tty.rs" [dependencies] clap = { version = "3.1", features = ["wrap_help", "cargo"] } -libc = "0.2.124" +libc = "0.2.125" atty = "0.2" uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["fs"] } diff --git a/src/uu/whoami/Cargo.toml b/src/uu/whoami/Cargo.toml index 2655fe892..253e2ba1b 100644 --- a/src/uu/whoami/Cargo.toml +++ b/src/uu/whoami/Cargo.toml @@ -22,7 +22,7 @@ uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=[ winapi = { version = "0.3", features = ["lmcons"] } [target.'cfg(unix)'.dependencies] -libc = "0.2.124" +libc = "0.2.125" [[bin]] name = "whoami" diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 6f74b238a..56e582bf8 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -31,7 +31,7 @@ time = { version="<= 0.1.43", optional=true } data-encoding = { version="2.1", optional=true } data-encoding-macro = { version="0.1.12", optional=true } z85 = { version="3.0.5", optional=true } -libc = { version="0.2.124", optional=true } +libc = { version="0.2.125", optional=true } once_cell = "1.10.0" os_display = "0.1.3" From a1e5f8e53f037c14ae356c4567ec459214622be2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 13:03:18 +0000 Subject: [PATCH 27/62] build(deps): bump memchr from 2.4.1 to 2.5.0 Bumps [memchr](https://github.com/BurntSushi/memchr) from 2.4.1 to 2.5.0. - [Release notes](https://github.com/BurntSushi/memchr/releases) - [Commits](https://github.com/BurntSushi/memchr/compare/2.4.1...2.5.0) --- updated-dependencies: - dependency-name: memchr dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 30 +++++++++++++++--------------- src/uu/sort/Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a24abb936..2f33f716a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,7 @@ version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ - "memchr 2.4.1", + "memchr 2.5.0", ] [[package]] @@ -163,7 +163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", - "memchr 2.4.1", + "memchr 2.5.0", "regex-automata", ] @@ -1015,9 +1015,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.124" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libloading" @@ -1082,9 +1082,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" @@ -1160,7 +1160,7 @@ version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ - "memchr 2.4.1", + "memchr 2.5.0", "minimal-lexical", ] @@ -1568,7 +1568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", - "memchr 2.4.1", + "memchr 2.5.0", "regex-syntax", ] @@ -2178,7 +2178,7 @@ dependencies = [ "atty", "bstr", "clap 3.1.12", - "memchr 2.4.1", + "memchr 2.5.0", "uucore", ] @@ -2347,7 +2347,7 @@ dependencies = [ "digest", "hex", "md-5", - "memchr 2.4.1", + "memchr 2.5.0", "regex", "sha1", "sha2", @@ -2360,7 +2360,7 @@ name = "uu_head" version = "0.0.13" dependencies = [ "clap 3.1.12", - "memchr 2.4.1", + "memchr 2.5.0", "uucore", ] @@ -2408,7 +2408,7 @@ name = "uu_join" version = "0.0.13" dependencies = [ "clap 3.1.12", - "memchr 2.4.1", + "memchr 2.5.0", "uucore", ] @@ -2753,7 +2753,7 @@ dependencies = [ "ctrlc", "fnv", "itertools", - "memchr 2.4.1", + "memchr 2.5.0", "ouroboros", "rand", "rayon", @@ -2767,7 +2767,7 @@ name = "uu_split" version = "0.0.13" dependencies = [ "clap 3.1.12", - "memchr 2.4.1", + "memchr 2.5.0", "uucore", ] @@ -2822,7 +2822,7 @@ name = "uu_tac" version = "0.0.13" dependencies = [ "clap 3.1.12", - "memchr 2.4.1", + "memchr 2.5.0", "memmap2", "regex", "uucore", diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index 69f7f7468..3c8be6a50 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -21,7 +21,7 @@ compare = "0.1.0" ctrlc = { version = "3.0", features = ["termination"] } fnv = "1.0.7" itertools = "0.10.0" -memchr = "2.4.0" +memchr = "2.5.0" ouroboros = "0.15.0" rand = "0.8" rayon = "1.5" From 1acbc0009e6fb2c5b92d8df15eda4b8eb1858dd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 13:06:15 +0000 Subject: [PATCH 28/62] build(deps): bump thiserror from 1.0.30 to 1.0.31 Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.30 to 1.0.31. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.30...1.0.31) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a46b14ec..14ba065c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,9 +273,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1506b87ee866f7a53a5131f7b31fba656170d797e873d0609884cfd56b8bbda8" +checksum = "1d7ca9141e27e6ebc52e3c378b0c07f3cea52db46ed1cc5861735fb697b56356" dependencies = [ "clap 3.1.12", ] @@ -1924,18 +1924,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote 1.0.14", From 15412f100a1fc14e72a4c48de495de9dec66a168 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sat, 30 Apr 2022 15:36:50 +0200 Subject: [PATCH 29/62] df: show "block-size argument too large" error --- src/uu/df/src/df.rs | 21 +++++++++++++++------ tests/by-util/test_df.rs | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index 2b9c929c7..b86b11f37 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -14,6 +14,7 @@ mod table; 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}; @@ -105,7 +106,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 +118,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 +160,12 @@ 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), + })?, include, exclude, show_total: matches.is_present(OPT_TOTAL), diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index 61ddcec5d..90781eb64 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -419,6 +419,30 @@ fn test_block_size_with_suffix() { //assert_eq!(get_header("1GB"), "1GB-blocks"); } +#[test] +fn test_too_large_block_size() { + fn run_command(size: &str) { + new_ucmd!() + .arg(format!("--block-size={}", size)) + .fails() + .stderr_contains(format!("--block-size argument '{}' too large", size)); + } + + let too_large_sizes = vec!["1Y", "1Z"]; + + for size in too_large_sizes { + run_command(size); + } +} + +#[test] +fn test_invalid_block_size() { + new_ucmd!() + .arg("--block-size=x") + .fails() + .stderr_contains("invalid --block-size argument 'x'"); +} + #[test] fn test_output_selects_columns() { let output = new_ucmd!() From badf947f8a343d40a7660d5fc490e149340b56e5 Mon Sep 17 00:00:00 2001 From: anastygnome Date: Mon, 2 May 2022 08:28:23 +0200 Subject: [PATCH 30/62] Do not dereference symlink even when dangling (fix #3364) Fixes an issue with cp not copying symlinks in spite of the -P (no dereference option) Fix issue #3364 Performance improvements Avoid useless read from metadata and reuse previous dest information Signed-off-by: anastygnome --- src/uu/cp/src/cp.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 913cf2769..ce85b58bc 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -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() From 70c451fa61cb342b8a4646c4ad053ebe1ec0f608 Mon Sep 17 00:00:00 2001 From: anastygnome Date: Mon, 2 May 2022 08:20:46 +0200 Subject: [PATCH 31/62] Add test for copying dangling symlink copy with dereference Signed-off-by: anastygnome --- tests/by-util/test_cp.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 079e966be..cdcaf2760 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1506,6 +1506,18 @@ fn test_copy_through_dangling_symlink() { .stderr_only("cp: not writing through dangling symlink 'target'"); } +#[test] +fn test_copy_through_dangling_symlink_no_dereference() { + let (at, mut ucmd) = at_and_ucmd!(); + at.symlink_file("no-such-file", "dangle"); + ucmd.arg("-P") + .arg("dangle") + .arg("d2") + .succeeds() + .no_stderr() + .no_stdout(); +} + #[test] #[cfg(unix)] fn test_cp_archive_on_nonexistent_file() { From a4e3f37aaf3ab7f553276e02dd87d4feafdbf226 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 21:30:25 +0000 Subject: [PATCH 32/62] build(deps): bump clap from 3.1.12 to 3.1.15 Bumps [clap](https://github.com/clap-rs/clap) from 3.1.12 to 3.1.15. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v3.1.12...v3.1.15) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 216 ++++++++++++++++++++++++++--------------------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ad9da7ba..ee06b62eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,9 +256,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.12" +version = "3.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c167e37342afc5f33fd87bbc870cedd020d2a6dffa05d45ccd9241fbdd146db" +checksum = "85a35a599b11c089a7f49105658d089b8f2cf0882993c17daf6de15285c2c35d" dependencies = [ "atty", "bitflags", @@ -277,14 +277,14 @@ version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7ca9141e27e6ebc52e3c378b0c07f3cea52db46ed1cc5861735fb697b56356" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", ] [[package]] name = "clap_lex" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669" +checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" dependencies = [ "os_str_bytes", ] @@ -316,7 +316,7 @@ version = "0.0.13" dependencies = [ "atty", "chrono", - "clap 3.1.12", + "clap 3.1.15", "clap_complete", "conv", "filetime", @@ -2033,7 +2033,7 @@ checksum = "7cf7d77f457ef8dfa11e4cd5933c5ddb5dc52a94664071951219a97710f0a32b" name = "uu_arch" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "platform-info", "uucore", ] @@ -2042,7 +2042,7 @@ dependencies = [ name = "uu_base32" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2058,7 +2058,7 @@ dependencies = [ name = "uu_basename" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2066,7 +2066,7 @@ dependencies = [ name = "uu_basenc" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uu_base32", "uucore", ] @@ -2076,7 +2076,7 @@ name = "uu_cat" version = "0.0.13" dependencies = [ "atty", - "clap 3.1.12", + "clap 3.1.15", "nix", "thiserror", "unix_socket", @@ -2087,7 +2087,7 @@ dependencies = [ name = "uu_chcon" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "fts-sys", "libc", "selinux", @@ -2099,7 +2099,7 @@ dependencies = [ name = "uu_chgrp" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2107,7 +2107,7 @@ dependencies = [ name = "uu_chmod" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2116,7 +2116,7 @@ dependencies = [ name = "uu_chown" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2124,7 +2124,7 @@ dependencies = [ name = "uu_chroot" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2132,7 +2132,7 @@ dependencies = [ name = "uu_cksum" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2140,7 +2140,7 @@ dependencies = [ name = "uu_comm" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2148,7 +2148,7 @@ dependencies = [ name = "uu_cp" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "exacl", "filetime", "ioctl-sys", @@ -2165,7 +2165,7 @@ dependencies = [ name = "uu_csplit" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "regex", "thiserror", "uucore", @@ -2177,7 +2177,7 @@ version = "0.0.13" dependencies = [ "atty", "bstr", - "clap 3.1.12", + "clap 3.1.15", "memchr 2.5.0", "uucore", ] @@ -2187,7 +2187,7 @@ name = "uu_date" version = "0.0.13" dependencies = [ "chrono", - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", "winapi 0.3.9", @@ -2198,7 +2198,7 @@ name = "uu_dd" version = "0.0.13" dependencies = [ "byte-unit", - "clap 3.1.12", + "clap 3.1.15", "gcd", "libc", "signal-hook", @@ -2209,7 +2209,7 @@ dependencies = [ name = "uu_df" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "number_prefix", "unicode-width", "uucore", @@ -2219,7 +2219,7 @@ dependencies = [ name = "uu_dir" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "selinux", "uu_ls", "uucore", @@ -2229,7 +2229,7 @@ dependencies = [ name = "uu_dircolors" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "glob", "uucore", ] @@ -2238,7 +2238,7 @@ dependencies = [ name = "uu_dirname" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2247,7 +2247,7 @@ name = "uu_du" version = "0.0.13" dependencies = [ "chrono", - "clap 3.1.12", + "clap 3.1.15", "glob", "uucore", "winapi 0.3.9", @@ -2257,7 +2257,7 @@ dependencies = [ name = "uu_echo" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2265,7 +2265,7 @@ dependencies = [ name = "uu_env" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "rust-ini", "uucore", ] @@ -2274,7 +2274,7 @@ dependencies = [ name = "uu_expand" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "unicode-width", "uucore", ] @@ -2283,7 +2283,7 @@ dependencies = [ name = "uu_expr" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "num-bigint", "num-traits", "onig", @@ -2294,7 +2294,7 @@ dependencies = [ name = "uu_factor" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "coz", "num-traits", "paste", @@ -2308,7 +2308,7 @@ dependencies = [ name = "uu_false" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2316,7 +2316,7 @@ dependencies = [ name = "uu_fmt" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "unicode-width", "uucore", ] @@ -2325,7 +2325,7 @@ dependencies = [ name = "uu_fold" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2333,7 +2333,7 @@ dependencies = [ name = "uu_groups" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2343,7 +2343,7 @@ version = "0.0.13" dependencies = [ "blake2b_simd", "blake3", - "clap 3.1.12", + "clap 3.1.15", "digest", "hex", "md-5", @@ -2359,7 +2359,7 @@ dependencies = [ name = "uu_head" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "memchr 2.5.0", "uucore", ] @@ -2368,7 +2368,7 @@ dependencies = [ name = "uu_hostid" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2377,7 +2377,7 @@ dependencies = [ name = "uu_hostname" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "hostname", "uucore", "winapi 0.3.9", @@ -2387,7 +2387,7 @@ dependencies = [ name = "uu_id" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "selinux", "uucore", ] @@ -2396,7 +2396,7 @@ dependencies = [ name = "uu_install" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "file_diff", "filetime", "libc", @@ -2407,7 +2407,7 @@ dependencies = [ name = "uu_join" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "memchr 2.5.0", "uucore", ] @@ -2416,7 +2416,7 @@ dependencies = [ name = "uu_kill" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2425,7 +2425,7 @@ dependencies = [ name = "uu_link" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2433,7 +2433,7 @@ dependencies = [ name = "uu_ln" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2441,7 +2441,7 @@ dependencies = [ name = "uu_logname" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2452,7 +2452,7 @@ version = "0.0.13" dependencies = [ "atty", "chrono", - "clap 3.1.12", + "clap 3.1.15", "glob", "lazy_static", "lscolors", @@ -2469,7 +2469,7 @@ dependencies = [ name = "uu_mkdir" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2477,7 +2477,7 @@ dependencies = [ name = "uu_mkfifo" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2486,7 +2486,7 @@ dependencies = [ name = "uu_mknod" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2495,7 +2495,7 @@ dependencies = [ name = "uu_mktemp" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "rand", "tempfile", "uucore", @@ -2506,7 +2506,7 @@ name = "uu_more" version = "0.0.13" dependencies = [ "atty", - "clap 3.1.12", + "clap 3.1.15", "crossterm", "nix", "unicode-segmentation", @@ -2518,7 +2518,7 @@ dependencies = [ name = "uu_mv" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "fs_extra", "uucore", ] @@ -2527,7 +2527,7 @@ dependencies = [ name = "uu_nice" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "nix", "uucore", @@ -2537,7 +2537,7 @@ dependencies = [ name = "uu_nl" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "regex", "uucore", ] @@ -2547,7 +2547,7 @@ name = "uu_nohup" version = "0.0.13" dependencies = [ "atty", - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2556,7 +2556,7 @@ dependencies = [ name = "uu_nproc" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "num_cpus", "uucore", @@ -2566,7 +2566,7 @@ dependencies = [ name = "uu_numfmt" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2575,7 +2575,7 @@ name = "uu_od" version = "0.0.13" dependencies = [ "byteorder", - "clap 3.1.12", + "clap 3.1.15", "half", "uucore", ] @@ -2584,7 +2584,7 @@ dependencies = [ name = "uu_paste" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2592,7 +2592,7 @@ dependencies = [ name = "uu_pathchk" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2601,7 +2601,7 @@ dependencies = [ name = "uu_pinky" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2610,7 +2610,7 @@ name = "uu_pr" version = "0.0.13" dependencies = [ "chrono", - "clap 3.1.12", + "clap 3.1.15", "itertools", "quick-error", "regex", @@ -2621,7 +2621,7 @@ dependencies = [ name = "uu_printenv" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2629,7 +2629,7 @@ dependencies = [ name = "uu_printf" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2637,7 +2637,7 @@ dependencies = [ name = "uu_ptx" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "regex", "uucore", ] @@ -2646,7 +2646,7 @@ dependencies = [ name = "uu_pwd" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2654,7 +2654,7 @@ dependencies = [ name = "uu_readlink" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2662,7 +2662,7 @@ dependencies = [ name = "uu_realpath" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2670,7 +2670,7 @@ dependencies = [ name = "uu_relpath" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2678,7 +2678,7 @@ dependencies = [ name = "uu_rm" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "remove_dir_all 0.7.0", "uucore", "walkdir", @@ -2689,7 +2689,7 @@ dependencies = [ name = "uu_rmdir" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2698,7 +2698,7 @@ dependencies = [ name = "uu_runcon" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "selinux", "thiserror", @@ -2710,7 +2710,7 @@ name = "uu_seq" version = "0.0.13" dependencies = [ "bigdecimal", - "clap 3.1.12", + "clap 3.1.15", "num-bigint", "num-traits", "uucore", @@ -2720,7 +2720,7 @@ dependencies = [ name = "uu_shred" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "rand", "uucore", ] @@ -2729,7 +2729,7 @@ dependencies = [ name = "uu_shuf" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "rand", "rand_core", "uucore", @@ -2739,7 +2739,7 @@ dependencies = [ name = "uu_sleep" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2748,7 +2748,7 @@ name = "uu_sort" version = "0.0.13" dependencies = [ "binary-heap-plus", - "clap 3.1.12", + "clap 3.1.15", "compare", "ctrlc", "fnv", @@ -2766,7 +2766,7 @@ dependencies = [ name = "uu_split" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "memchr 2.5.0", "uucore", ] @@ -2775,7 +2775,7 @@ dependencies = [ name = "uu_stat" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2783,7 +2783,7 @@ dependencies = [ name = "uu_stdbuf" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "tempfile", "uu_stdbuf_libstdbuf", "uucore", @@ -2803,7 +2803,7 @@ dependencies = [ name = "uu_sum" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2811,7 +2811,7 @@ dependencies = [ name = "uu_sync" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", "winapi 0.3.9", @@ -2821,7 +2821,7 @@ dependencies = [ name = "uu_tac" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "memchr 2.5.0", "memmap2", "regex", @@ -2832,7 +2832,7 @@ dependencies = [ name = "uu_tail" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "nix", "uucore", @@ -2843,7 +2843,7 @@ dependencies = [ name = "uu_tee" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "retain_mut", "uucore", @@ -2853,7 +2853,7 @@ dependencies = [ name = "uu_test" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "redox_syscall", "uucore", @@ -2863,7 +2863,7 @@ dependencies = [ name = "uu_timeout" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "nix", "uucore", @@ -2873,7 +2873,7 @@ dependencies = [ name = "uu_touch" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "filetime", "time", "uucore", @@ -2884,7 +2884,7 @@ dependencies = [ name = "uu_tr" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "nom", "uucore", ] @@ -2893,7 +2893,7 @@ dependencies = [ name = "uu_true" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2901,7 +2901,7 @@ dependencies = [ name = "uu_truncate" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2909,7 +2909,7 @@ dependencies = [ name = "uu_tsort" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2918,7 +2918,7 @@ name = "uu_tty" version = "0.0.13" dependencies = [ "atty", - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", ] @@ -2927,7 +2927,7 @@ dependencies = [ name = "uu_uname" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "platform-info", "uucore", ] @@ -2936,7 +2936,7 @@ dependencies = [ name = "uu_unexpand" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "unicode-width", "uucore", ] @@ -2945,7 +2945,7 @@ dependencies = [ name = "uu_uniq" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "strum", "strum_macros", "uucore", @@ -2955,7 +2955,7 @@ dependencies = [ name = "uu_unlink" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2964,7 +2964,7 @@ name = "uu_uptime" version = "0.0.13" dependencies = [ "chrono", - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2972,7 +2972,7 @@ dependencies = [ name = "uu_users" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -2980,7 +2980,7 @@ dependencies = [ name = "uu_vdir" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "selinux", "uu_ls", "uucore", @@ -2991,7 +2991,7 @@ name = "uu_wc" version = "0.0.13" dependencies = [ "bytecount", - "clap 3.1.12", + "clap 3.1.15", "libc", "nix", "unicode-width", @@ -3003,7 +3003,7 @@ dependencies = [ name = "uu_who" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "uucore", ] @@ -3011,7 +3011,7 @@ dependencies = [ name = "uu_whoami" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "libc", "uucore", "winapi 0.3.9", @@ -3021,7 +3021,7 @@ dependencies = [ name = "uu_yes" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "nix", "uucore", ] @@ -3030,7 +3030,7 @@ dependencies = [ name = "uucore" version = "0.0.13" dependencies = [ - "clap 3.1.12", + "clap 3.1.15", "data-encoding", "data-encoding-macro", "dns-lookup", From 3e30569c2f1c6dc30c904a2c2ecd893e0e5733e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 May 2022 06:13:02 +0000 Subject: [PATCH 33/62] build(deps): bump xattr from 0.2.2 to 0.2.3 Bumps [xattr](https://github.com/Stebalien/xattr) from 0.2.2 to 0.2.3. - [Release notes](https://github.com/Stebalien/xattr/releases) - [Commits](https://github.com/Stebalien/xattr/commits) --- updated-dependencies: - dependency-name: xattr dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- src/uu/cp/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee06b62eb..b503b60d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3208,9 +3208,9 @@ checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] name = "xattr" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ "libc", ] diff --git a/src/uu/cp/Cargo.toml b/src/uu/cp/Cargo.toml index f9036101a..3f3c2e317 100644 --- a/src/uu/cp/Cargo.toml +++ b/src/uu/cp/Cargo.toml @@ -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]] From 9bd883169dcf7ae7142dca372c516c83114da73c Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 4 May 2022 09:37:09 +0200 Subject: [PATCH 34/62] df: set min width of "Used" column to 5 --- src/uu/df/src/columns.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uu/df/src/columns.rs b/src/uu/df/src/columns.rs index bd8cab438..70b660a0b 100644 --- a/src/uu/df/src/columns.rs +++ b/src/uu/df/src/columns.rs @@ -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, } From 88a62c4922e61f5896a163997143fb2d9ce4d660 Mon Sep 17 00:00:00 2001 From: Ackerley Tng Date: Tue, 3 May 2022 08:22:05 -0700 Subject: [PATCH 35/62] du: use common error methods with show! instead of set_exit_code --- src/uu/du/src/du.rs | 30 ++++++++---------------------- tests/by-util/test_du.rs | 4 +--- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index ff7a5a5b7..b29a938a4 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -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, 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), diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 254e75166..bf506c8b5 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -435,9 +435,7 @@ fn test_du_no_permission() { ts.ccmd("chmod").arg("-r").arg(SUB_DIR_LINKS).succeeds(); let result = ts.ucmd().arg(SUB_DIR_LINKS).fails(); - result.stderr_contains( - "du: cannot read directory 'subdir/links': Permission denied (os error 13)", - ); + result.stderr_contains("du: cannot read directory 'subdir/links': Permission denied"); #[cfg(any(target_os = "linux", target_os = "android"))] { From 7b84261df42278a23bed2239cc8cb93126503ec0 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sat, 30 Apr 2022 11:25:53 +0200 Subject: [PATCH 36/62] uucore/error: add custom exit codes for clap errors This allows us to use clap errors as UResult and specify the exit code for invalid arguments per util. --- src/uucore/src/lib/mods/error.rs | 73 +++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index dbe4d5bc1..1af6ef781 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -617,12 +617,75 @@ impl From for Box { } } -/// Implementations for clap::Error -impl UError for clap::Error { +/// A wrapper for `clap::Error` that implements [`UError`] +/// +/// Contains a custom error code. When `Display::fmt` is called on this struct +/// the [`clap::Error`] will be printed _directly to `stdout` or `stderr`_. +/// This is because `clap` only supports colored output when it prints directly. +/// +/// [`ClapErrorWrapper`] is generally created by calling the +/// [`UClapError::with_exit_code`] method on [`clap::Error`] or using the [`From`] +/// implementation from [`clap::Error`] to `Box`, which constructs +/// a [`ClapErrorWrapper`] with an exit code of `1`. +/// +/// ```rust +/// use uucore::error::{ClapErrorWrapper, UError, UClapError}; +/// let command = clap::Command::new("test"); +/// let result: Result<_, ClapErrorWrapper> = command.try_get_matches().with_exit_code(125); +/// +/// let command = clap::Command::new("test"); +/// let result: Result<_, Box> = command.try_get_matches().map_err(Into::into); +/// ``` +#[derive(Debug)] +pub struct ClapErrorWrapper { + code: i32, + error: clap::Error, +} + +/// Extension trait for `clap::Error` to adjust the exit code. +pub trait UClapError { + fn with_exit_code(self, code: i32) -> T; +} + +impl From for Box { + fn from(e: clap::Error) -> Self { + Box::new(ClapErrorWrapper { code: 1, error: e }) + } +} + +impl UClapError for clap::Error { + fn with_exit_code(self, code: i32) -> ClapErrorWrapper { + ClapErrorWrapper { code, error: self } + } +} + +impl UClapError> + for Result +{ + fn with_exit_code(self, code: i32) -> Result { + self.map_err(|e| e.with_exit_code(code)) + } +} + +impl UError for ClapErrorWrapper { fn code(&self) -> i32 { - match self.kind() { - clap::ErrorKind::DisplayHelp | clap::ErrorKind::DisplayVersion => 0, - _ => 1, + // If the error is a DisplayHelp or DisplayVersion variant, + // we don't want to apply the custom error code, but leave + // it 0. + if let clap::ErrorKind::DisplayHelp | clap::ErrorKind::DisplayVersion = self.error.kind() { + 0 + } else { + self.code } } } + +impl Error for ClapErrorWrapper {} + +// This is abuse of the Display trait +impl Display for ClapErrorWrapper { + fn fmt(&self, _f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + self.error.print().unwrap(); + Ok(()) + } +} From 8df253da69a9826056a8f556e772a549a8900c3f Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sat, 30 Apr 2022 11:28:22 +0200 Subject: [PATCH 37/62] cat: set exit code for invalid arguments to 1 instead of 2 --- src/uu/cat/src/cat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/cat/src/cat.rs b/src/uu/cat/src/cat.rs index edba1b8d0..67de917f7 100644 --- a/src/uu/cat/src/cat.rs +++ b/src/uu/cat/src/cat.rs @@ -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 From 1bb85acc71b8276c910d850ea79d98f5009c0691 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sat, 30 Apr 2022 22:45:17 +0200 Subject: [PATCH 38/62] nice: set exit code for clap errors to 125 --- src/uu/nice/src/nice.rs | 4 ++-- tests/by-util/test_nice.rs | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/uu/nice/src/nice.rs b/src/uu/nice/src/nice.rs index b75dd979e..e78de828b 100644 --- a/src/uu/nice/src/nice.rs +++ b/src/uu/nice/src/nice.rs @@ -17,7 +17,7 @@ use std::ptr; use clap::{crate_version, Arg, Command}; use uucore::{ - error::{set_exit_code, UResult, USimpleError, UUsageError}, + error::{set_exit_code, UClapError, UResult, USimpleError, UUsageError}, format_usage, }; @@ -35,7 +35,7 @@ const USAGE: &str = "{} [OPTIONS] [COMMAND [ARGS]]"; #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let matches = uu_app().get_matches_from(args); + let matches = uu_app().try_get_matches_from(args).with_exit_code(125)?; let mut niceness = unsafe { nix::errno::Errno::clear(); diff --git a/tests/by-util/test_nice.rs b/tests/by-util/test_nice.rs index 2b53ed437..036723cde 100644 --- a/tests/by-util/test_nice.rs +++ b/tests/by-util/test_nice.rs @@ -58,3 +58,8 @@ fn test_command_where_command_takes_n_flag() { .run() .stdout_is("a"); } + +#[test] +fn test_invalid_argument() { + new_ucmd!().arg("--invalid").fails().code_is(125); +} From 24097262589b7cdb48ab166407b1a35e11618337 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Sun, 1 May 2022 20:51:25 +0200 Subject: [PATCH 39/62] base: set exit code to 1 for clap errors --- src/uu/base32/src/base_common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/base32/src/base_common.rs b/src/uu/base32/src/base_common.rs index 100c85b1f..148bad2f8 100644 --- a/src/uu/base32/src/base_common.rs +++ b/src/uu/base32/src/base_common.rs @@ -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> { From c7b7f19559c84feafa9959495d4f1fb0e44d9935 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 4 May 2022 19:10:28 +0200 Subject: [PATCH 40/62] cp: use new clap error mechanism --- src/uu/cp/src/cp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index ce85b58bc..1b47b7828 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -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)?; From 46e029f34c02a3ad0bb663d070bfb75a4ff9acb9 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 20 Apr 2022 08:06:24 +0200 Subject: [PATCH 41/62] df: refactor HumanReadable handling The refactoring consists of three parts: 1) Introduction of SizeFormat & HumanReadable enums 2) Addition of a size_format field to the options struct 3) Movement of header logic from BlockSize to Header --- src/uu/df/src/blocks.rs | 79 ++++++++++++++++++++++------------------- src/uu/df/src/df.rs | 12 +++++++ src/uu/df/src/table.rs | 47 ++++++++++++------------ 3 files changed, 80 insertions(+), 58 deletions(-) diff --git a/src/uu/df/src/blocks.rs b/src/uu/df/src/blocks.rs index efeae2a70..f49650472 100644 --- a/src/uu/df/src/blocks.rs +++ b/src/uu/df/src/blocks.rs @@ -3,7 +3,7 @@ // * 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; @@ -117,14 +117,46 @@ fn to_magnitude_and_suffix(n: u128) -> Result { } } +/// 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)`. pub(crate) enum BlockSize { @@ -132,20 +164,6 @@ pub(crate) enum BlockSize { /// /// 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 { @@ -155,11 +173,7 @@ impl Default for BlockSize { } pub(crate) fn block_size_from_matches(matches: &ArgMatches) -> Result { - 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 { @@ -170,10 +184,8 @@ pub(crate) fn block_size_from_matches(matches: &ArgMatches) -> Result 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), }, } @@ -229,13 +241,8 @@ mod tests { #[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"); } } diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index b86b11f37..344314198 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -11,6 +11,7 @@ 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}; @@ -62,6 +63,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. @@ -89,6 +91,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(), @@ -166,6 +169,15 @@ impl Options { ), 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), diff --git a/src/uu/df/src/table.rs b/src/uu/df/src/table.rs index 6b64ce02c..64c5033ed 100644 --- a/src/uu/df/src/table.rs +++ b/src/uu/df/src/table.rs @@ -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}; @@ -523,7 +526,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 +545,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!( @@ -689,7 +692,7 @@ 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() }; @@ -730,7 +733,7 @@ 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() }; From 00a3ec2d1f68e1c6d11f6f1d27651d2e1ae6dbf0 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 4 May 2022 16:11:03 +0200 Subject: [PATCH 42/62] df: implement Default for Row for unit tests --- src/uu/df/src/table.rs | 113 +++++++++++++---------------------------- 1 file changed, 34 insertions(+), 79 deletions(-) diff --git a/src/uu/df/src/table.rs b/src/uu/df/src/table.rs index 6b64ce02c..0d57bc93b 100644 --- a/src/uu/df/src/table.rs +++ b/src/uu/df/src/table.rs @@ -446,6 +446,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(); @@ -565,9 +589,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 +597,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 +614,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 +623,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 +640,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 +665,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")); @@ -694,7 +681,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(), @@ -704,13 +690,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!( @@ -735,7 +715,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(), @@ -745,13 +724,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 +744,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%")); } } From 24f78ddb9ecf28eaa33ec0b37350bd9711d982d1 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 5 May 2022 13:55:38 +0200 Subject: [PATCH 43/62] docs: remove duplicate "at", add missing newline --- docs/src/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 3ea5d913a..c51fbb198 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -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. \ No newline at end of file +> a work in progress. From f5ffa9412940d4fe74b89d2931eb7ccf8198f8d0 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Thu, 5 May 2022 19:53:38 +0200 Subject: [PATCH 44/62] test_stat: add tests for issues with stdin * add tests for: https://github.com/uutils/coreutils/issues/3485 * add test for: https://github.com/uutils/coreutils/pull/3280 --- tests/by-util/test_stat.rs | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 90ad2d12a..53e83bef6 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -311,3 +311,58 @@ fn test_printf() { let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); } + +#[cfg(unix)] +#[test] +#[cfg(disable_until_fixed)] +fn test_stdin_pipe_fifo1() { + // $ echo | stat - + // File: - + // Size: 0 Blocks: 0 IO Block: 4096 fifo + // use std::process::{Command, Stdio}; + new_ucmd!() + .arg("-") + .set_stdin(std::process::Stdio::piped()) + .run() + .no_stderr() + .stdout_contains("fifo") + .stdout_contains("File: -") + .succeeded(); +} + +#[cfg(unix)] +#[test] +#[cfg(disable_until_fixed)] +fn test_stdin_pipe_fifo2() { + // $ stat - + // File: - + // Size: 0 Blocks: 0 IO Block: 1024 character special file + new_ucmd!() + .arg("-") + .run() + .no_stderr() + .stdout_contains("character special file") + .stdout_contains("File: -") + .succeeded(); +} + +#[cfg(unix)] +#[test] +#[cfg(disable_until_fixed)] +fn test_stdin_redirect() { + // $ touch f && stat - < f + // File: - + // Size: 0 Blocks: 0 IO Block: 4096 regular empty file + + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + at.touch("f"); + new_ucmd!() + .arg("-") + .set_stdin(std::fs::File::open("f").unwrap()) + .run() + .no_stderr() + .stdout_contains("regular empty file") + .stdout_contains("File: -") + .succeeded(); +} From e70b99dad0b01758b71faf76a31094541f23112f Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 29 Apr 2022 10:32:28 +0200 Subject: [PATCH 45/62] touch: add support of -d '1970-01-01 18:43:33.023456789' --- src/uu/touch/src/touch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 5264401ef..1d90ed4d7 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -6,7 +6,7 @@ // For the full copyright and license information, please view the LICENSE file // that was distributed with this source code. -// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm clapv PWSTR lpszfilepath hresult mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME YYYYMMDDHHMMS +// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm clapv PWSTR lpszfilepath hresult mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME YYYYMMDDHHMMS subsecond pub extern crate filetime; #[macro_use] From 65d0f5ba9f0ba9a4271d293fd0e7538c6a502783 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 2 May 2022 22:32:37 +0200 Subject: [PATCH 46/62] to_local: manage the error --- src/uu/touch/src/touch.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 1d90ed4d7..8e8e4c458 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -43,8 +43,13 @@ pub mod options { static ARG_FILES: &str = "files"; fn to_local(tm: time::PrimitiveDateTime) -> time::OffsetDateTime { - // TODO: handle error getting now - tm.assume_offset(time::OffsetDateTime::now_local().unwrap().offset()) + let offset = match time::OffsetDateTime::now_local() { + Ok(lo) => lo.offset(), + Err(e) => { + panic!("error: {}", e); + } + }; + tm.assume_offset(offset) } fn local_dt_to_filetime(dt: time::OffsetDateTime) -> FileTime { From e691330f02f02c6ac5fae05d82a24d75a22fb3e8 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Thu, 5 May 2022 17:58:37 -0400 Subject: [PATCH 47/62] mktemp: return MkTempError from parse_template() Change the return type of the `parse_template()` helper function in the `mktemp` program so that it returns `Result<..., MkTempError>` instead of `UResult<...>`. This separates the lower level helper function from the higher level `UResult` abstraction and will make it easier to refactor this code in future commits. --- src/uu/mktemp/src/mktemp.rs | 69 ++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index f999d6675..b14318679 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -205,20 +205,41 @@ pub fn uu_app<'a>() -> Command<'a> { ) } +/// Parse a template string into prefix, suffix, and random components. +/// +/// `temp` is the template string, with three or more consecutive `X`s +/// representing a placeholder for randomly generated characters (for +/// example, `"abc_XXX.txt"`). If `temp` ends in an `X`, then a suffix +/// can be specified by `suffix` instead. +/// +/// # Errors +/// +/// * If there are fewer than three consecutive `X`s in `temp`. +/// * If `suffix` is a [`Some`] object but `temp` does not end in `X`. +/// * If the suffix (specified either way) contains a path separator. +/// +/// # Examples +/// +/// ```rust,ignore +/// assert_eq!(parse_template("XXX", None).unwrap(), ("", 3, "")); +/// assert_eq!(parse_template("abcXXX", None).unwrap(), ("abc", 3, "")); +/// assert_eq!(parse_template("XXXdef", None).unwrap(), ("", 3, "def")); +/// assert_eq!(parse_template("abcXXXdef", None).unwrap(), ("abc", 3, "def")); +/// ``` fn parse_template<'a>( temp: &'a str, suffix: Option<&'a str>, -) -> UResult<(&'a str, usize, &'a str)> { +) -> Result<(&'a str, usize, &'a str), MkTempError> { let right = match temp.rfind('X') { Some(r) => r + 1, - None => return Err(MkTempError::TooFewXs(temp.into()).into()), + None => return Err(MkTempError::TooFewXs(temp.into())), }; let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1); let prefix = &temp[..left]; let rand = right - left; if rand < 3 { - return Err(MkTempError::TooFewXs(temp.into()).into()); + return Err(MkTempError::TooFewXs(temp.into())); } let mut suf = &temp[right..]; @@ -227,12 +248,12 @@ fn parse_template<'a>( if suf.is_empty() { suf = s; } else { - return Err(MkTempError::MustEndInX(temp.into()).into()); + return Err(MkTempError::MustEndInX(temp.into())); } }; if suf.chars().any(is_separator) { - return Err(MkTempError::ContainsDirSeparator(suf.into()).into()); + return Err(MkTempError::ContainsDirSeparator(suf.into())); } Ok((prefix, rand, suf)) @@ -304,3 +325,41 @@ fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned()) } + +#[cfg(test)] +mod tests { + use crate::parse_template; + + #[test] + fn test_parse_template_no_suffix() { + assert_eq!(parse_template("XXX", None).unwrap(), ("", 3, "")); + assert_eq!(parse_template("abcXXX", None).unwrap(), ("abc", 3, "")); + assert_eq!(parse_template("XXXdef", None).unwrap(), ("", 3, "def")); + assert_eq!( + parse_template("abcXXXdef", None).unwrap(), + ("abc", 3, "def") + ); + } + + #[test] + fn test_parse_template_suffix() { + assert_eq!(parse_template("XXX", Some("def")).unwrap(), ("", 3, "def")); + assert_eq!( + parse_template("abcXXX", Some("def")).unwrap(), + ("abc", 3, "def") + ); + } + + #[test] + fn test_parse_template_errors() { + // TODO This should be an error as well, but we are not + // catching it just yet. A future commit will correct this. + // + // assert!(parse_template("a/bXXX", None).is_err()); + // + assert!(parse_template("XXXa/b", None).is_err()); + assert!(parse_template("XX", None).is_err()); + assert!(parse_template("XXXabc", Some("def")).is_err()); + assert!(parse_template("XXX", Some("a/b")).is_err()); + } +} From 608b1afde51542222e8ab64c1681013249e083c2 Mon Sep 17 00:00:00 2001 From: naveensrinivasan <172697+naveensrinivasan@users.noreply.github.com> Date: Thu, 5 May 2022 19:38:10 -0500 Subject: [PATCH 48/62] chore: Included githubactions in the dependabot config This should help with keeping the GitHub actions updated on new releases. This will also help with keeping it secure. Dependabot helps in keeping the supply chain secure https://docs.github.com/en/code-security/dependabot GitHub actions up to date https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot https://github.com/ossf/scorecard/blob/main/docs/checks.md#dependency-update-tool Signed-off-by: naveensrinivasan <172697+naveensrinivasan@users.noreply.github.com> --- .github/dependabot.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ef7519b88..cfcddbb14 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -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 From be1f41e24cf2dba128abcb5ee181b58b07008741 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 6 May 2022 08:02:22 +0200 Subject: [PATCH 49/62] df: set names for arg values & add missing space --- src/uu/df/src/df.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index 344314198..d9fb1be7b 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -445,6 +445,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.\ @@ -501,6 +502,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) @@ -510,7 +512,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.", ), ) @@ -533,6 +535,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"), ) @@ -549,6 +552,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"), From 97c59d78578cf9402946b1bd4fad7777da496362 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 06:29:14 +0000 Subject: [PATCH 50/62] build(deps): bump num-traits from 0.2.14 to 0.2.15 Bumps [num-traits](https://github.com/rust-num/num-traits) from 0.2.14 to 0.2.15. - [Release notes](https://github.com/rust-num/num-traits/releases) - [Changelog](https://github.com/rust-num/num-traits/blob/master/RELEASES.md) - [Commits](https://github.com/rust-num/num-traits/compare/num-traits-0.2.14...num-traits-0.2.15) --- updated-dependencies: - dependency-name: num-traits dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- src/uu/expr/Cargo.toml | 2 +- src/uu/factor/Cargo.toml | 4 ++-- src/uu/seq/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b503b60d5..4f73fe91e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1196,9 +1196,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] diff --git a/src/uu/expr/Cargo.toml b/src/uu/expr/Cargo.toml index c4a1bae4a..9ea8008af 100644 --- a/src/uu/expr/Cargo.toml +++ b/src/uu/expr/Cargo.toml @@ -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" } diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index e1620ed90..242616718 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -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.13" # 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" } diff --git a/src/uu/seq/Cargo.toml b/src/uu/seq/Cargo.toml index ad8bba5b6..67226093d 100644 --- a/src/uu/seq/Cargo.toml +++ b/src/uu/seq/Cargo.toml @@ -19,7 +19,7 @@ path = "src/seq.rs" bigdecimal = "0.3" clap = { version = "3.1", features = ["wrap_help", "cargo"] } num-bigint = "0.4.0" -num-traits = "0.2.14" +num-traits = "0.2.15" uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["memo"] } [[bin]] From a60f6dc67eca2591639f7f6e90d4f21ae3602eb4 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 4 May 2022 22:36:21 +0200 Subject: [PATCH 51/62] Update num-traits for real --- src/uu/factor/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index 242616718..20a21ac00 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -17,7 +17,7 @@ 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.15 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" } From 06ef89b3d822dccbf0dfff1683486498c6fcfc6f Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Thu, 5 May 2022 22:48:37 +0200 Subject: [PATCH 52/62] touch: improve the -d option support of other dates --- src/uu/touch/src/touch.rs | 25 +++++++++++++++++-------- tests/by-util/test_touch.rs | 10 ++++++++-- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 8e8e4c458..c082aed23 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -16,7 +16,7 @@ use clap::{crate_version, Arg, ArgGroup, Command}; use filetime::*; use std::fs::{self, File}; use std::path::{Path, PathBuf}; -use time::macros::{format_description, time}; +use time::macros::{format_description, offset, time}; use time::Duration; use uucore::display::Quotable; use uucore::error::{FromIo, UError, UResult, USimpleError}; @@ -42,6 +42,7 @@ pub mod options { static ARG_FILES: &str = "files"; +// Convert a date/time to a date with a TZ offset fn to_local(tm: time::PrimitiveDateTime) -> time::OffsetDateTime { let offset = match time::OffsetDateTime::now_local() { Ok(lo) => lo.offset(), @@ -52,10 +53,18 @@ fn to_local(tm: time::PrimitiveDateTime) -> time::OffsetDateTime { tm.assume_offset(offset) } +// Convert a date/time with a TZ offset into a FileTime fn local_dt_to_filetime(dt: time::OffsetDateTime) -> FileTime { FileTime::from_unix_time(dt.unix_timestamp(), dt.nanosecond()) } +// Convert a date/time, considering that the input is in UTC time +// Used for touch -d 1970-01-01 18:43:33.023456789 for example +fn dt_to_filename(tm: time::PrimitiveDateTime) -> FileTime { + let dt = tm.assume_offset(offset!(UTC)); + local_dt_to_filetime(dt) +} + #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().get_matches_from(args); @@ -310,15 +319,15 @@ fn parse_date(s: &str) -> UResult { // Tue Dec 3 ... // ("%c", POSIX_LOCALE_FORMAT), // - // But also support other format found in the GNU tests like + if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &POSIX_LOCALE_FORMAT) { + return Ok(local_dt_to_filetime(to_local(parsed))); + } + + // Also support other formats found in the GNU tests like // in tests/misc/stat-nanoseconds.sh - for fmt in [ - POSIX_LOCALE_FORMAT, - YYYYMMDDHHMMS_FORMAT, - YYYYMMDDHHMMSS_FORMAT, - ] { + for fmt in [YYYYMMDDHHMMS_FORMAT, YYYYMMDDHHMMSS_FORMAT] { if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &fmt) { - return Ok(local_dt_to_filetime(to_local(parsed))); + return Ok(dt_to_filename(parsed)); } } diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index ed62692f4..9b8eebbf0 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -438,7 +438,7 @@ fn test_touch_set_date4() { assert!(at.file_exists(file)); - let expected = FileTime::from_unix_time(60213, 0); + let expected = FileTime::from_unix_time(67413, 0); let (atime, mtime) = get_file_times(&at, file); assert_eq!(atime, mtime); assert_eq!(atime, expected); @@ -456,7 +456,13 @@ fn test_touch_set_date5() { assert!(at.file_exists(file)); - let expected = FileTime::from_unix_time(60213, 023456789); + // Slightly different result on Windows for nano seconds + // TODO: investigate + #[cfg(windows)] + let expected = FileTime::from_unix_time(67413, 23456700); + #[cfg(not(windows))] + let expected = FileTime::from_unix_time(67413, 23456789); + let (atime, mtime) = get_file_times(&at, file); assert_eq!(atime, mtime); assert_eq!(atime, expected); From 5a3933a882ae0daec84bad9fc3c517e1bda58011 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 6 May 2022 15:37:52 +0200 Subject: [PATCH 53/62] df: fix "Size" header for multiples of 1000 & 1024 --- src/uu/df/src/blocks.rs | 11 +++++++++-- tests/by-util/test_df.rs | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/uu/df/src/blocks.rs b/src/uu/df/src/blocks.rs index f49650472..e964a208a 100644 --- a/src/uu/df/src/blocks.rs +++ b/src/uu/df/src/blocks.rs @@ -73,7 +73,7 @@ fn to_magnitude_and_suffix_1024(n: u128) -> Result { Err(()) } -/// Convert a number, except multiples of 1024, into a string like "12kB" or "34MB". +/// Convert a number into a string like "12kB" or "34MB". /// /// Powers of 1000 become "1kB", "1MB", "1GB", etc. /// @@ -110,7 +110,7 @@ fn to_magnitude_and_suffix_not_powers_of_1024(n: u128) -> Result { /// /// If the number is too large to represent. fn to_magnitude_and_suffix(n: u128) -> Result { - if n % 1024 == 0 { + if n % 1024 == 0 && n % 1000 != 0 { to_magnitude_and_suffix_1024(n) } else { to_magnitude_and_suffix_not_powers_of_1024(n) @@ -239,6 +239,13 @@ mod tests { assert_eq!(to_magnitude_and_suffix(1_000_000_001).unwrap(), "1.1GB"); } + #[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::Bytes(1024)), "1K"); diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index f03a71a7b..511956ec4 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -392,6 +392,11 @@ fn test_block_size_1024() { assert_eq!(get_header(2 * 1024 * 1024), "2M-blocks"); assert_eq!(get_header(1024 * 1024 * 1024), "1G-blocks"); assert_eq!(get_header(34 * 1024 * 1024 * 1024), "34G-blocks"); + + // multiples of both 1024 and 1000 + assert_eq!(get_header(128_000), "128kB-blocks"); + assert_eq!(get_header(1000 * 1024), "1.1MB-blocks"); + assert_eq!(get_header(1_000_000_000_000), "1TB-blocks"); } #[test] From 39520a84ab7ca2515913b0621d91d60f05775fd7 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 6 May 2022 23:54:12 +0200 Subject: [PATCH 54/62] fix the GNU error detection --- .github/workflows/GnuTests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index f2b0ddd45..3a152be22 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -170,8 +170,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/^FAIL: \([[:print:]]\+\).*/\1/p" "${REF_LOG_FILE}" | sort) - NEW_ERROR=$(sed -n "s/^FAIL: \([[:print:]]\+\).*/\1/p" '${{ steps.vars.outputs.path_GNU_tests }}/test-suite.log' | sort) + 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} From a640ed64896b0fc5ff35362f1e2b27ead8d8c7f0 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 6 May 2022 23:54:12 +0200 Subject: [PATCH 55/62] fix the GNU error detection --- .github/workflows/GnuTests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index a20ddd8a8..c8d3c8b94 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -174,8 +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/^FAIL: \([[:print:]]\+\).*/\1/p" "${REF_LOG_FILE}" | sort) - NEW_ERROR=$(sed -n "s/^FAIL: \([[:print:]]\+\).*/\1/p" '${{ steps.vars.outputs.path_GNU_tests }}/test-suite.log' | sort) + 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} From f668b69a2caa4e257128442a9ee6fae082ba768f Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 5 May 2022 10:53:40 +0200 Subject: [PATCH 56/62] df: use blocksize of 512 if POSIXLY_CORRECT is set --- src/uu/df/src/blocks.rs | 19 +++++++++++++++++-- src/uu/df/src/df.rs | 8 ++++++++ tests/by-util/test_df.rs | 20 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/uu/df/src/blocks.rs b/src/uu/df/src/blocks.rs index e964a208a..bb6e06333 100644 --- a/src/uu/df/src/blocks.rs +++ b/src/uu/df/src/blocks.rs @@ -5,7 +5,7 @@ //! Types for representing and displaying block sizes. use crate::OPT_BLOCKSIZE; use clap::ArgMatches; -use std::fmt; +use std::{env, fmt}; use uucore::parse_size::{parse_size, ParseSizeError}; @@ -159,6 +159,7 @@ pub(crate) enum HumanReadable { /// size. /// /// The default variant is `Bytes(1024)`. +#[derive(Debug, PartialEq)] pub(crate) enum BlockSize { /// A fixed number of bytes. /// @@ -168,7 +169,11 @@ pub(crate) enum BlockSize { impl Default for BlockSize { fn default() -> Self { - Self::Bytes(1024) + if env::var("POSIXLY_CORRECT").is_ok() { + Self::Bytes(512) + } else { + Self::Bytes(1024) + } } } @@ -195,6 +200,8 @@ impl fmt::Display for BlockSize { #[cfg(test)] mod tests { + use std::env; + use crate::blocks::{to_magnitude_and_suffix, BlockSize}; #[test] @@ -252,4 +259,12 @@ mod tests { 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"); + } } diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index d9fb1be7b..192cbcadf 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -32,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"; @@ -427,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) diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index 511956ec4..81a9eef72 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -375,6 +375,26 @@ fn test_iuse_percentage() { } } +#[test] +fn test_default_block_size() { + let output = new_ucmd!() + .arg("--output=size") + .succeeds() + .stdout_move_str(); + let header = output.lines().next().unwrap().to_string(); + + assert_eq!(header, "1K-blocks"); + + let output = new_ucmd!() + .arg("--output=size") + .env("POSIXLY_CORRECT", "1") + .succeeds() + .stdout_move_str(); + let header = output.lines().next().unwrap().to_string(); + + assert_eq!(header, "512B-blocks"); +} + #[test] fn test_block_size_1024() { fn get_header(block_size: u64) -> String { From 087d4b14fc205107d557d3300b63d29849888642 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 8 May 2022 21:27:08 +0200 Subject: [PATCH 57/62] Do not use the Rust/touch for tests/ls/abmon-align.sh --- util/build-gnu.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 83993fde9..942aa9d87 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -137,7 +137,8 @@ sed -i 's|chmod |/usr/bin/chmod |' tests/du/inacc-dir.sh tests/tail-2/tail-n0f.s sed -i 's|sort |/usr/bin/sort |' tests/ls/hyperlink.sh tests/misc/test-N.sh sed -i 's|split |/usr/bin/split |' tests/misc/factor-parallel.sh sed -i 's|id -|/usr/bin/id -|' tests/misc/runcon-no-reorder.sh -sed -i 's|touch |/usr/bin/touch |' tests/cp/preserve-link.sh tests/cp/reflink-perm.sh tests/ls/block-size.sh tests/mv/update.sh tests/misc/ls-time.sh tests/misc/stat-nanoseconds.sh tests/misc/time-style.sh tests/misc/test-N.sh +# tests/ls/abmon-align.sh - https://github.com/uutils/coreutils/issues/3505 +sed -i 's|touch |/usr/bin/touch |' tests/cp/preserve-link.sh tests/cp/reflink-perm.sh tests/ls/block-size.sh tests/mv/update.sh tests/misc/ls-time.sh tests/misc/stat-nanoseconds.sh tests/misc/time-style.sh tests/misc/test-N.sh tests/ls/abmon-align.sh sed -i 's|ln -|/usr/bin/ln -|' tests/cp/link-deref.sh sed -i 's|cp |/usr/bin/cp |' tests/mv/hard-2.sh sed -i 's|paste |/usr/bin/paste |' tests/misc/od-endian.sh From d5569847bd682f0df1eab95316fa9c81afe83676 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 8 May 2022 21:31:42 +0200 Subject: [PATCH 58/62] also support for tests/touch/no-rights.sh format --- src/uu/touch/src/touch.rs | 15 ++++++++++++++- tests/by-util/test_touch.rs | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index c082aed23..5444c8c10 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -280,12 +280,20 @@ const YYYYMMDDHHMMSS_FORMAT: &[time::format_description::FormatItem] = format_de "[year repr:full]-[month repr:numerical padding:zero]-\ [day] [hour]:[minute]:[second].[subsecond]" ); + // "%Y-%m-%d %H:%M:%S" 12 chars const YYYYMMDDHHMMS_FORMAT: &[time::format_description::FormatItem] = format_description!( "[year repr:full]-[month repr:numerical padding:zero]-\ [day] [hour]:[minute]:[second]" ); +// "%Y-%m-%d %H:%M" 12 chars +// Used for example in tests/touch/no-rights.sh +const YYYY_MM_DD_HH_MM_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year repr:full]-[month repr:numerical padding:zero]-\ + [day] [hour]:[minute]" +); + // "%Y%m%d%H%M" 12 chars const YYYYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_description!( "[year repr:full][month repr:numerical padding:zero]\ @@ -325,7 +333,12 @@ fn parse_date(s: &str) -> UResult { // Also support other formats found in the GNU tests like // in tests/misc/stat-nanoseconds.sh - for fmt in [YYYYMMDDHHMMS_FORMAT, YYYYMMDDHHMMSS_FORMAT] { + // or tests/touch/no-rights.sh + for fmt in [ + YYYYMMDDHHMMS_FORMAT, + YYYYMMDDHHMMSS_FORMAT, + YYYY_MM_DD_HH_MM_FORMAT, + ] { if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &fmt) { return Ok(dt_to_filename(parsed)); } diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 9b8eebbf0..5417a0dbe 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -469,6 +469,25 @@ fn test_touch_set_date5() { assert_eq!(mtime, expected); } +#[test] +fn test_touch_set_date6() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "test_touch_set_date"; + + ucmd.args(&["-d", "2000-01-01 00:00", file]) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(file)); + + let expected = FileTime::from_unix_time(946684800, 0); + + let (atime, mtime) = get_file_times(&at, file); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); +} + #[test] fn test_touch_set_date_wrong_format() { let (_at, mut ucmd) = at_and_ucmd!(); From f65d72e334f73aedb38c6e149480733f433f0e8a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 8 May 2022 21:52:12 +0200 Subject: [PATCH 59/62] also support for tests/touch/relative.sh --- src/uu/touch/src/touch.rs | 8 ++++++++ tests/by-util/test_touch.rs | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 5444c8c10..f71eb81d0 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -312,6 +312,13 @@ const YYMMDDHHMM_FORMAT: &[time::format_description::FormatItem] = format_descri [hour repr:24 padding:zero][minute padding:zero]" ); +// "%Y-%m-%d %H:%M +offset" +// Used for example in tests/touch/relative.sh +const YYYYMMDDHHMM_OFFSET_FORMAT: &[time::format_description::FormatItem] = format_description!( + "[year]-[month]-[day] [hour repr:24]:[minute] \ + [offset_hour sign:mandatory][offset_minute]" +); + fn parse_date(s: &str) -> UResult { // This isn't actually compatible with GNU touch, but there doesn't seem to // be any simple specification for what format this parameter allows and I'm @@ -338,6 +345,7 @@ fn parse_date(s: &str) -> UResult { YYYYMMDDHHMMS_FORMAT, YYYYMMDDHHMMSS_FORMAT, YYYY_MM_DD_HH_MM_FORMAT, + YYYYMMDDHHMM_OFFSET_FORMAT, ] { if let Ok(parsed) = time::PrimitiveDateTime::parse(s, &fmt) { return Ok(dt_to_filename(parsed)); diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 5417a0dbe..346e27919 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -488,6 +488,25 @@ fn test_touch_set_date6() { assert_eq!(mtime, expected); } +#[test] +fn test_touch_set_date7() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "test_touch_set_date"; + + ucmd.args(&["-d", "2004-01-16 12:00 +0000", file]) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(file)); + + let expected = FileTime::from_unix_time(1074254400, 0); + + let (atime, mtime) = get_file_times(&at, file); + assert_eq!(atime, mtime); + assert_eq!(atime, expected); + assert_eq!(mtime, expected); +} + #[test] fn test_touch_set_date_wrong_format() { let (_at, mut ucmd) = at_and_ucmd!(); From ece9ccdbfb48fe2cc1e3de8c13be159ad7fda839 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 10 May 2022 13:49:29 +0200 Subject: [PATCH 60/62] Add missing \# interpreter line --- util/android-commands.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/util/android-commands.sh b/util/android-commands.sh index 2a4fca416..0a245a004 100755 --- a/util/android-commands.sh +++ b/util/android-commands.sh @@ -1,3 +1,4 @@ +#!/bin/bash # spell-checker:ignore termux keyevent sdcard binutils unmatch adb's dumpsys logcat pkill # There are three shells: the host's, adb, and termux. Only adb lets us run From 7d8b1de213602e2476b5bf013bd871dc05d01071 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 10 May 2022 13:54:16 +0200 Subject: [PATCH 61/62] uniq: Disable one of the gnu test for failing too often See: https://github.com/uutils/coreutils/issues/3509 --- tests/by-util/test_uniq.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/by-util/test_uniq.rs b/tests/by-util/test_uniq.rs index b3f5fcd68..77ad10b32 100644 --- a/tests/by-util/test_uniq.rs +++ b/tests/by-util/test_uniq.rs @@ -680,6 +680,9 @@ fn gnu_tests() { stderr: None, exit: None, }, + /* + Disable as it fails too often. See: + https://github.com/uutils/coreutils/issues/3509 TestCase { name: "112", args: &["-D", "-c"], @@ -687,7 +690,7 @@ fn gnu_tests() { stdout: Some(""), stderr: Some("uniq: printing all duplicated lines and repeat counts is meaningless"), exit: Some(1), - }, + },*/ TestCase { name: "113", args: &["--all-repeated=separate"], From 12d7d9846abc825e95e95b00d2ce00e50b22068b Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Tue, 10 May 2022 13:46:22 +0200 Subject: [PATCH 62/62] test/util: improve `run_ucmd_as_root` for CICD * ensure that `fn run_no_wait` is only invoked if the system running the test has `sudo` in $path Previously, if run inside CICD, calling `fn run_ucmd_as_root` would provoke `fn run_no_wait` to panic because there's no `sudo`. --- tests/common/util.rs | 87 +++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 34 deletions(-) diff --git a/tests/common/util.rs b/tests/common/util.rs index 34bdc72f3..d601b90d8 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1370,6 +1370,8 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< /// To check if i) non-interactive sudo is possible and ii) if sudo works, this runs: /// 'sudo -E --non-interactive whoami' first. /// +/// This return an `Err()` if run inside CICD because there's no 'sudo'. +/// /// Example: /// /// ```no_run @@ -1381,7 +1383,7 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< /// if let Ok(result) = run_ucmd_as_root(&ts, &[]) { /// result.stdout_is(expected); /// } else { -/// print!("TEST SKIPPED"); +/// println!("TEST SKIPPED"); /// } /// } ///``` @@ -1390,29 +1392,37 @@ pub fn run_ucmd_as_root( ts: &TestScenario, args: &[&str], ) -> std::result::Result { - // Apparently CICD environment has no `sudo`? - if ts - .cmd_keepenv("sudo") - .env("LC_ALL", "C") - .arg("-E") - .arg("--non-interactive") - .arg("whoami") - .run() - .stdout_str() - .trim() - != "root" - { - Err("\"sudo whoami\" didn't return \"root\"".to_string()) - } else { - Ok(ts - .cmd_keepenv("sudo") + if !is_ci() { + // check if we can run 'sudo' + log_info("run", "sudo -E --non-interactive whoami"); + match Command::new("sudo") .env("LC_ALL", "C") - .arg("-E") - .arg("--non-interactive") - .arg(&ts.bin_path) - .arg(&ts.util_name) - .args(args) - .run()) + .args(&["-E", "--non-interactive", "whoami"]) + .output() + { + Ok(output) if String::from_utf8_lossy(&output.stdout).eq("root\n") => { + // we can run sudo and we're root + // run ucmd as root: + Ok(ts + .cmd_keepenv("sudo") + .env("LC_ALL", "C") + .arg("-E") + .arg("--non-interactive") + .arg(&ts.bin_path) + .arg(&ts.util_name) + .args(args) + .run()) + } + Ok(output) + if String::from_utf8_lossy(&output.stderr).eq("sudo: a password is required\n") => + { + Err("Cannot run non-interactive sudo".to_string()) + } + Ok(_output) => Err("\"sudo whoami\" didn't return \"root\"".to_string()), + Err(e) => Err(format!("{}: {}", UUTILS_WARNING, e)), + } + } else { + Err(format!("{}: {}", UUTILS_INFO, "cannot run inside CI")) } } @@ -1771,18 +1781,27 @@ mod tests { #[cfg(unix)] #[cfg(feature = "whoami")] fn test_run_ucmd_as_root() { - // Skip test if we can't guarantee non-interactive `sudo`. - if let Ok(_status) = Command::new("sudo") - .args(&["-E", "-v", "--non-interactive"]) - .status() - { - let ts = TestScenario::new("whoami"); - std::assert_eq!( - run_ucmd_as_root(&ts, &[]).unwrap().stdout_str().trim(), - "root" - ); + if !is_ci() { + // Skip test if we can't guarantee non-interactive `sudo`, or if we're not "root" + if let Ok(output) = Command::new("sudo") + .env("LC_ALL", "C") + .args(&["-E", "--non-interactive", "whoami"]) + .output() + { + if output.status.success() && String::from_utf8_lossy(&output.stdout).eq("root\n") { + let ts = TestScenario::new("whoami"); + std::assert_eq!( + run_ucmd_as_root(&ts, &[]).unwrap().stdout_str().trim(), + "root" + ); + } else { + println!("TEST SKIPPED (we're not root)"); + } + } else { + println!("TEST SKIPPED (cannot run sudo)"); + } } else { - print!("TEST SKIPPED"); + println!("TEST SKIPPED (cannot run inside CI)"); } } }