From cf7b90bbe7cb87099499876622f413a65a699038 Mon Sep 17 00:00:00 2001 From: Thomas Hurst Date: Tue, 28 Feb 2023 17:45:14 +0000 Subject: [PATCH 01/88] dd: use an alarm thread instead of elapsed() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quick benchmark on FreeBSD 13.1-RELEASE: Summary './dd-thread-alarm if=/dev/zero of=/dev/null count=4000000 status=progress' ran 1.17 ± 0.17 times faster than './dd-baseline if=/dev/zero of=/dev/null count=4000000 status=progress' --- src/uu/dd/src/dd.rs | 47 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index eaf89ca55..2baa12106 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -65,6 +65,46 @@ struct Settings { status: Option, } +use std::thread::sleep; +use std::time::Duration; + +use std::sync::{ + atomic::{AtomicBool, Ordering::Relaxed}, + Arc, +}; + +#[derive(Debug, Clone)] +pub struct Alarm { + interval: Duration, + trigger: Arc, +} + +impl Alarm { + pub fn with_interval(interval: Duration) -> Alarm { + let trigger = Arc::new(AtomicBool::default()); + + let weak_trigger = Arc::downgrade(&trigger); + std::thread::spawn(move || loop { + sleep(interval); + if let Some(trigger) = weak_trigger.upgrade() { + trigger.store(true, Relaxed); + } else { + break; + } + }); + + Alarm { interval, trigger } + } + + pub fn is_triggered(&self) -> bool { + self.trigger.swap(false, Relaxed) + } + + pub fn get_interval(&self) -> Duration { + self.interval + } +} + /// A number in blocks or bytes /// /// Some values (seek, skip, iseek, oseek) can have values either in blocks or in bytes. @@ -628,7 +668,6 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> { // information. let (prog_tx, rx) = mpsc::channel(); let output_thread = thread::spawn(gen_prog_updater(rx, i.settings.status)); - let mut progress_as_secs = 0; // Optimization: if no blocks are to be written, then don't // bother allocating any buffers. @@ -639,6 +678,7 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> { // Create a common buffer with a capacity of the block size. // This is the max size needed. let mut buf = vec![BUF_INIT_BYTE; bsize]; + let alarm = Alarm::with_interval(Duration::from_secs(1)); // The main read/write loop. // @@ -667,9 +707,8 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> { // error. rstat += rstat_update; wstat += wstat_update; - let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false); - if prog_update.duration.as_secs() >= progress_as_secs { - progress_as_secs = prog_update.duration.as_secs() + 1; + if alarm.is_triggered() { + let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false); prog_tx.send(prog_update).unwrap_or(()); } } From 52c93a4d107a6252c4cfe85c572075cacc493272 Mon Sep 17 00:00:00 2001 From: Thomas Hurst Date: Wed, 1 Mar 2023 13:56:18 +0000 Subject: [PATCH 02/88] dd: Simplify loop of progress Alarm thread --- src/uu/dd/src/dd.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 2baa12106..15c7e8ed4 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -80,20 +80,18 @@ pub struct Alarm { } impl Alarm { - pub fn with_interval(interval: Duration) -> Alarm { + pub fn with_interval(interval: Duration) -> Self { let trigger = Arc::new(AtomicBool::default()); let weak_trigger = Arc::downgrade(&trigger); - std::thread::spawn(move || loop { - sleep(interval); - if let Some(trigger) = weak_trigger.upgrade() { + std::thread::spawn(move || { + while let Some(trigger) = weak_trigger.upgrade() { + sleep(interval); trigger.store(true, Relaxed); - } else { - break; } }); - Alarm { interval, trigger } + Self { interval, trigger } } pub fn is_triggered(&self) -> bool { From 08e8b40e451b17c404c8795ae431636a3a48bca8 Mon Sep 17 00:00:00 2001 From: Joining7943 <111500881+Joining7943@users.noreply.github.com> Date: Thu, 20 Apr 2023 21:08:12 +0200 Subject: [PATCH 03/88] tail: Refactor paths::Input::from method, Settings::inputs now use Vec instead of VecDeque --- src/uu/tail/src/args.rs | 26 ++++++++++---------------- src/uu/tail/src/follow/watch.rs | 3 +-- src/uu/tail/src/paths.rs | 11 ++++++----- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/uu/tail/src/args.rs b/src/uu/tail/src/args.rs index 55014e029..eff332230 100644 --- a/src/uu/tail/src/args.rs +++ b/src/uu/tail/src/args.rs @@ -12,7 +12,6 @@ use clap::{Arg, ArgAction, ArgMatches, Command}; use fundu::DurationParser; use is_terminal::IsTerminal; use same_file::Handle; -use std::collections::VecDeque; use std::ffi::OsString; use std::time::Duration; use uucore::error::{UResult, USimpleError, UUsageError}; @@ -141,7 +140,8 @@ pub struct Settings { pub use_polling: bool, pub verbose: bool, pub presume_input_pipe: bool, - pub inputs: VecDeque, + /// `FILE(s)` positional arguments + pub inputs: Vec, } impl Default for Settings { @@ -173,11 +173,11 @@ impl Settings { } settings.mode = FilterMode::from_obsolete_args(args); let input = if let Some(name) = name { - Input::from(&name) + Input::from(name) } else { Input::default() }; - settings.inputs.push_back(input); + settings.inputs.push(input); settings } @@ -282,19 +282,13 @@ impl Settings { } } - let mut inputs: VecDeque = matches - .get_many::(options::ARG_FILES) - .map(|v| v.map(|string| Input::from(&string)).collect()) - .unwrap_or_default(); + settings.inputs = matches + .get_raw(options::ARG_FILES) + .map(|v| v.map(Input::from).collect()) + .unwrap_or_else(|| vec![Input::default()]); - // apply default and add '-' to inputs if none is present - if inputs.is_empty() { - inputs.push_front(Input::default()); - } - - settings.verbose = inputs.len() > 1 && !matches.get_flag(options::verbosity::QUIET); - - settings.inputs = inputs; + settings.verbose = + settings.inputs.len() > 1 && !matches.get_flag(options::verbosity::QUIET); Ok(settings) } diff --git a/src/uu/tail/src/follow/watch.rs b/src/uu/tail/src/follow/watch.rs index 2c3cf10b8..966f39120 100644 --- a/src/uu/tail/src/follow/watch.rs +++ b/src/uu/tail/src/follow/watch.rs @@ -10,7 +10,6 @@ use crate::follow::files::{FileHandling, PathData}; use crate::paths::{Input, InputKind, MetadataExtTail, PathExtTail}; use crate::{platform, text}; use notify::{RecommendedWatcher, RecursiveMode, Watcher, WatcherKind}; -use std::collections::VecDeque; use std::io::BufRead; use std::path::{Path, PathBuf}; use std::sync::mpsc::{self, channel, Receiver}; @@ -270,7 +269,7 @@ impl Observer { self.follow_name() && self.retry } - fn init_files(&mut self, inputs: &VecDeque) -> UResult<()> { + fn init_files(&mut self, inputs: &Vec) -> UResult<()> { if let Some(watcher_rx) = &mut self.watcher_rx { for input in inputs { match input.kind() { diff --git a/src/uu/tail/src/paths.rs b/src/uu/tail/src/paths.rs index 4badd6866..d813ea942 100644 --- a/src/uu/tail/src/paths.rs +++ b/src/uu/tail/src/paths.rs @@ -27,20 +27,21 @@ pub struct Input { } impl Input { - pub fn from>(string: &T) -> Self { - let kind = if string.as_ref() == Path::new(text::DASH) { + pub fn from>(string: T) -> Self { + let string = string.as_ref(); + let kind = if string == OsStr::new(text::DASH) { InputKind::Stdin } else { - InputKind::File(PathBuf::from(string.as_ref())) + InputKind::File(PathBuf::from(string)) }; let display_name = match kind { - InputKind::File(_) => string.as_ref().to_string_lossy().to_string(), + InputKind::File(_) => string.to_string_lossy().to_string(), InputKind::Stdin => { if cfg!(unix) { text::STDIN_HEADER.to_string() } else { - string.as_ref().to_string_lossy().to_string() + string.to_string_lossy().to_string() } } }; From ae60045f3f0cf35c4f893c02f22d3c93b396b37f Mon Sep 17 00:00:00 2001 From: Joining7943 <111500881+Joining7943@users.noreply.github.com> Date: Thu, 20 Apr 2023 21:12:24 +0200 Subject: [PATCH 04/88] tail: Fix printed header for stdin should be the same on all platforms --- src/uu/tail/src/paths.rs | 43 ++++++++++++++++++++++++++------------ tests/by-util/test_tail.rs | 6 +----- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/uu/tail/src/paths.rs b/src/uu/tail/src/paths.rs index d813ea942..cce3270a8 100644 --- a/src/uu/tail/src/paths.rs +++ b/src/uu/tail/src/paths.rs @@ -10,7 +10,10 @@ use std::ffi::OsStr; use std::fs::{File, Metadata}; use std::io::{Seek, SeekFrom}; #[cfg(unix)] -use std::os::unix::fs::{FileTypeExt, MetadataExt}; +use std::os::unix::{ + fs::{FileTypeExt, MetadataExt}, + prelude::OsStrExt, +}; use std::path::{Path, PathBuf}; use uucore::error::UResult; @@ -20,6 +23,30 @@ pub enum InputKind { Stdin, } +#[cfg(unix)] +impl From<&OsStr> for InputKind { + fn from(value: &OsStr) -> Self { + const DASH: [u8; 1] = [b'-']; + + if value.as_bytes() == DASH { + Self::Stdin + } else { + Self::File(PathBuf::from(value)) + } + } +} + +#[cfg(not(unix))] +impl From<&OsStr> for InputKind { + fn from(value: &OsStr) -> Self { + if value == OsStr::new(text::DASH) { + Self::Stdin + } else { + Self::File(PathBuf::from(value)) + } + } +} + #[derive(Debug, Clone)] pub struct Input { kind: InputKind, @@ -29,21 +56,11 @@ pub struct Input { impl Input { pub fn from>(string: T) -> Self { let string = string.as_ref(); - let kind = if string == OsStr::new(text::DASH) { - InputKind::Stdin - } else { - InputKind::File(PathBuf::from(string)) - }; + let kind = string.into(); let display_name = match kind { InputKind::File(_) => string.to_string_lossy().to_string(), - InputKind::Stdin => { - if cfg!(unix) { - text::STDIN_HEADER.to_string() - } else { - string.to_string_lossy().to_string() - } - } + InputKind::Stdin => text::STDIN_HEADER.to_string(), }; Self { kind, display_name } diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index f3e55e434..2391a5f7a 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -145,12 +145,8 @@ fn test_stdin_redirect_offset() { } #[test] -#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))] // FIXME: for currently not working platforms +#[cfg(all(not(target_vendor = "apple")))] // FIXME: for currently not working platforms fn test_stdin_redirect_offset2() { - // FIXME: windows: Failed because of difference in printed header. See below. - // actual : ==> - <== - // expected: ==> standard input <== - // like test_stdin_redirect_offset but with multiple files let ts = TestScenario::new(util_name!()); From 546631c8e77bb6256d6b211306ed71b5bbf0e16f Mon Sep 17 00:00:00 2001 From: Thomas Hurst Date: Wed, 3 May 2023 16:30:53 +0000 Subject: [PATCH 05/88] dd: Tidy includes --- src/uu/dd/src/dd.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 15c7e8ed4..541c85ff9 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -33,9 +33,12 @@ use std::os::unix::fs::FileTypeExt; #[cfg(any(target_os = "linux", target_os = "android"))] use std::os::unix::fs::OpenOptionsExt; use std::path::Path; -use std::sync::mpsc; +use std::sync::{ + atomic::{AtomicBool, Ordering::Relaxed}, + mpsc, Arc, +}; use std::thread; -use std::time; +use std::time::{Duration, Instant}; use clap::{crate_version, Arg, Command}; use gcd::Gcd; @@ -65,14 +68,6 @@ struct Settings { status: Option, } -use std::thread::sleep; -use std::time::Duration; - -use std::sync::{ - atomic::{AtomicBool, Ordering::Relaxed}, - Arc, -}; - #[derive(Debug, Clone)] pub struct Alarm { interval: Duration, @@ -84,9 +79,9 @@ impl Alarm { let trigger = Arc::new(AtomicBool::default()); let weak_trigger = Arc::downgrade(&trigger); - std::thread::spawn(move || { + thread::spawn(move || { while let Some(trigger) = weak_trigger.upgrade() { - sleep(interval); + thread::sleep(interval); trigger.store(true, Relaxed); } }); @@ -646,7 +641,7 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> { // of its report includes the throughput in bytes per second, // which requires knowing how long the process has been // running. - let start = time::Instant::now(); + let start = Instant::now(); // A good buffer size for reading. // @@ -718,7 +713,7 @@ fn finalize( output: &mut Output, rstat: ReadStat, wstat: WriteStat, - start: time::Instant, + start: Instant, prog_tx: &mpsc::Sender, output_thread: thread::JoinHandle, ) -> std::io::Result<()> { From 01a8623d216599449f6c895996e6ba64c12fbd89 Mon Sep 17 00:00:00 2001 From: Thomas Hurst Date: Wed, 3 May 2023 16:31:14 +0000 Subject: [PATCH 06/88] dd: Add documentation to Alarm struct --- src/uu/dd/src/dd.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 541c85ff9..41b7eb773 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -68,6 +68,15 @@ struct Settings { status: Option, } +/// A timer which triggers on a given interval +/// +/// After being constructed with [`Alarm::with_interval`], [`Alarm::is_triggered`] +/// will return true once per the given [`Duration`]. +/// +/// Can be cloned, but the trigger status is shared across all instances so only +/// the first caller each interval will yield true. +/// +/// When all instances are dropped the background thread will exit on the next interval. #[derive(Debug, Clone)] pub struct Alarm { interval: Duration, @@ -671,6 +680,11 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> { // Create a common buffer with a capacity of the block size. // This is the max size needed. let mut buf = vec![BUF_INIT_BYTE; bsize]; + + // Spawn a timer thread to provide a scheduled signal indicating when we + // should send an update of our progress to the reporting thread. + // + // This avoids the need to query the OS monotonic clock for every block. let alarm = Alarm::with_interval(Duration::from_secs(1)); // The main read/write loop. From 24b979c8219f45ede57f304c5e6029619829cf15 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 14 Jun 2023 10:35:13 +0200 Subject: [PATCH 07/88] uucore: introduce ShortcutValueParser --- src/uucore/src/lib/lib.rs | 1 + src/uucore/src/lib/parser.rs | 1 + .../src/lib/parser/shortcut_value_parser.rs | 141 ++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 src/uucore/src/lib/parser/shortcut_value_parser.rs diff --git a/src/uucore/src/lib/lib.rs b/src/uucore/src/lib/lib.rs index e76e540c8..ca9a48d25 100644 --- a/src/uucore/src/lib/lib.rs +++ b/src/uucore/src/lib/lib.rs @@ -33,6 +33,7 @@ pub use crate::mods::version_cmp; pub use crate::parser::parse_glob; pub use crate::parser::parse_size; pub use crate::parser::parse_time; +pub use crate::parser::shortcut_value_parser; // * feature-gated modules #[cfg(feature = "encoding")] diff --git a/src/uucore/src/lib/parser.rs b/src/uucore/src/lib/parser.rs index 8eae16bbf..fc3e46b5c 100644 --- a/src/uucore/src/lib/parser.rs +++ b/src/uucore/src/lib/parser.rs @@ -1,3 +1,4 @@ pub mod parse_glob; pub mod parse_size; pub mod parse_time; +pub mod shortcut_value_parser; diff --git a/src/uucore/src/lib/parser/shortcut_value_parser.rs b/src/uucore/src/lib/parser/shortcut_value_parser.rs new file mode 100644 index 000000000..0b0716158 --- /dev/null +++ b/src/uucore/src/lib/parser/shortcut_value_parser.rs @@ -0,0 +1,141 @@ +use clap::{ + builder::{PossibleValue, TypedValueParser}, + error::{ContextKind, ContextValue, ErrorKind}, +}; + +#[derive(Clone)] +pub struct ShortcutValueParser(Vec); + +/// `ShortcutValueParser` is similar to clap's `PossibleValuesParser`: it verifies that the value is +/// from an enumerated set of `PossibleValue`. +/// +/// Whereas `PossibleValuesParser` only accepts exact matches, `ShortcutValueParser` also accepts +/// shortcuts as long as they are unambiguous. +impl ShortcutValueParser { + pub fn new(values: impl Into) -> Self { + values.into() + } +} + +impl TypedValueParser for ShortcutValueParser { + type Value = String; + + fn parse_ref( + &self, + cmd: &clap::Command, + arg: Option<&clap::Arg>, + value: &std::ffi::OsStr, + ) -> Result { + let value = value + .to_str() + .ok_or(clap::Error::new(ErrorKind::InvalidUtf8))?; + + let matched_values: Vec<_> = self + .0 + .iter() + .filter(|x| x.get_name().starts_with(value)) + .collect(); + + if matched_values.len() == 1 { + Ok(matched_values[0].get_name().to_string()) + } else { + let mut err = clap::Error::new(ErrorKind::InvalidValue).with_cmd(cmd); + + if let Some(arg) = arg { + err.insert( + ContextKind::InvalidArg, + ContextValue::String(arg.to_string()), + ); + } + + err.insert( + ContextKind::InvalidValue, + ContextValue::String(value.to_string()), + ); + + err.insert( + ContextKind::ValidValue, + ContextValue::Strings(self.0.iter().map(|x| x.get_name().to_string()).collect()), + ); + + Err(err) + } + } + + fn possible_values(&self) -> Option + '_>> { + Some(Box::new(self.0.iter().cloned())) + } +} + +impl From for ShortcutValueParser +where + I: IntoIterator, + T: Into, +{ + fn from(values: I) -> Self { + Self(values.into_iter().map(|t| t.into()).collect()) + } +} + +#[cfg(test)] +mod tests { + use std::ffi::OsStr; + + use clap::{builder::TypedValueParser, error::ErrorKind, Command}; + + use super::ShortcutValueParser; + + #[test] + fn test_parse_ref() { + let cmd = Command::new("cmd"); + let parser = ShortcutValueParser::new(["abcd"]); + let values = ["a", "ab", "abc", "abcd"]; + + for value in values { + let result = parser.parse_ref(&cmd, None, OsStr::new(value)); + assert_eq!("abcd", result.unwrap()); + } + } + + #[test] + fn test_parse_ref_with_invalid_value() { + let cmd = Command::new("cmd"); + let parser = ShortcutValueParser::new(["abcd"]); + let invalid_values = ["e", "abe", "abcde"]; + + for invalid_value in invalid_values { + let result = parser.parse_ref(&cmd, None, OsStr::new(invalid_value)); + assert_eq!(ErrorKind::InvalidValue, result.unwrap_err().kind()); + } + } + + #[test] + fn test_parse_ref_with_ambiguous_value() { + let cmd = Command::new("cmd"); + let parser = ShortcutValueParser::new(["abcd", "abef"]); + let ambiguous_values = ["a", "ab"]; + + for ambiguous_value in ambiguous_values { + let result = parser.parse_ref(&cmd, None, OsStr::new(ambiguous_value)); + assert_eq!(ErrorKind::InvalidValue, result.unwrap_err().kind()); + } + + let result = parser.parse_ref(&cmd, None, OsStr::new("abc")); + assert_eq!("abcd", result.unwrap()); + + let result = parser.parse_ref(&cmd, None, OsStr::new("abe")); + assert_eq!("abef", result.unwrap()); + } + + #[test] + #[cfg(unix)] + fn test_parse_ref_with_invalid_utf8() { + use std::os::unix::prelude::OsStrExt; + + let parser = ShortcutValueParser::new(["abcd"]); + let cmd = Command::new("cmd"); + + let result = parser.parse_ref(&cmd, None, OsStr::from_bytes(&[0xc3 as u8, 0x28 as u8])); + assert_eq!(ErrorKind::InvalidUtf8, result.unwrap_err().kind()); + } +} From 643afbd731949c3a55db59eb1c2c7bb656d22d55 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 14 Jun 2023 10:36:14 +0200 Subject: [PATCH 08/88] date: use ShortcutValueParser --- src/uu/date/src/date.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 7bd64839c..adfb74128 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -26,14 +26,13 @@ use uucore::{format_usage, help_about, help_usage, show}; #[cfg(windows)] use windows_sys::Win32::{Foundation::SYSTEMTIME, System::SystemInformation::SetSystemTime}; +use uucore::shortcut_value_parser::ShortcutValueParser; + // Options const DATE: &str = "date"; const HOURS: &str = "hours"; const MINUTES: &str = "minutes"; const SECONDS: &str = "seconds"; -const HOUR: &str = "hour"; -const MINUTE: &str = "minute"; -const SECOND: &str = "second"; const NS: &str = "ns"; const ABOUT: &str = help_about!("date.md"); @@ -110,9 +109,9 @@ enum Iso8601Format { impl<'a> From<&'a str> for Iso8601Format { fn from(s: &str) -> Self { match s { - HOURS | HOUR => Self::Hours, - MINUTES | MINUTE => Self::Minutes, - SECONDS | SECOND => Self::Seconds, + HOURS => Self::Hours, + MINUTES => Self::Minutes, + SECONDS => Self::Seconds, NS => Self::Ns, DATE => Self::Date, // Note: This is caught by clap via `possible_values` @@ -131,7 +130,7 @@ impl<'a> From<&'a str> for Rfc3339Format { fn from(s: &str) -> Self { match s { DATE => Self::Date, - SECONDS | SECOND => Self::Seconds, + SECONDS => Self::Seconds, NS => Self::Ns, // Should be caught by clap _ => panic!("Invalid format: {s}"), @@ -317,7 +316,9 @@ pub fn uu_app() -> Command { .short('I') .long(OPT_ISO_8601) .value_name("FMT") - .value_parser([DATE, HOUR, HOURS, MINUTE, MINUTES, SECOND, SECONDS, NS]) + .value_parser(ShortcutValueParser::new([ + DATE, HOURS, MINUTES, SECONDS, NS, + ])) .num_args(0..=1) .default_missing_value(OPT_DATE) .help(ISO_8601_HELP_STRING), @@ -333,7 +334,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_RFC_3339) .long(OPT_RFC_3339) .value_name("FMT") - .value_parser([DATE, SECOND, SECONDS, NS]) + .value_parser(ShortcutValueParser::new([DATE, SECONDS, NS])) .help(RFC_3339_HELP_STRING), ) .arg( From 47d0ac4a421b370e4655051d59b05830aa8138da Mon Sep 17 00:00:00 2001 From: John Shin Date: Sat, 17 Jun 2023 19:31:27 -0700 Subject: [PATCH 09/88] sync: fix error msg --- src/uu/sync/src/sync.rs | 4 ++-- tests/by-util/test_sync.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index e12703bca..821ad639b 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -173,7 +173,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let path = Path::new(&f); if let Err(e) = open(path, OFlag::O_NONBLOCK, Mode::empty()) { if e != Errno::EACCES || (e == Errno::EACCES && path.is_dir()) { - return e.map_err_context(|| format!("cannot stat {}", f.quote()))?; + return e.map_err_context(|| format!("error opening {}", f.quote()))?; } } } @@ -183,7 +183,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if !Path::new(&f).exists() { return Err(USimpleError::new( 1, - format!("cannot stat {}: No such file or directory", f.quote()), + format!("error opening {}: No such file or directory", f.quote()), )); } } diff --git a/tests/by-util/test_sync.rs b/tests/by-util/test_sync.rs index d55a874ba..9cae3b8a0 100644 --- a/tests/by-util/test_sync.rs +++ b/tests/by-util/test_sync.rs @@ -41,7 +41,7 @@ fn test_sync_no_existing_files() { .arg("--data") .arg("do-no-exist") .fails() - .stderr_contains("cannot stat"); + .stderr_contains("error opening"); } #[test] @@ -63,9 +63,9 @@ fn test_sync_no_permission_dir() { ts.ccmd("chmod").arg("0").arg(dir).succeeds(); let result = ts.ucmd().arg("--data").arg(dir).fails(); - result.stderr_contains("sync: cannot stat 'foo': Permission denied"); + result.stderr_contains("sync: error opening 'foo': Permission denied"); let result = ts.ucmd().arg(dir).fails(); - result.stderr_contains("sync: cannot stat 'foo': Permission denied"); + result.stderr_contains("sync: error opening 'foo': Permission denied"); } #[cfg(not(target_os = "windows"))] From 5882151eb10878e177df2f483c7ca0b234a52b54 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sun, 18 Jun 2023 15:13:15 +0200 Subject: [PATCH 10/88] deny.toml: add hashbrown to skip list --- deny.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deny.toml b/deny.toml index 8687fbfae..780de3c8c 100644 --- a/deny.toml +++ b/deny.toml @@ -87,6 +87,8 @@ skip = [ { name = "redox_syscall", version = "0.3.5" }, # cpp_macros { name = "aho-corasick", version = "0.7.19" }, + # ordered-multimap (via rust-ini) + { name = "hashbrown", version = "0.13.2" }, ] # spell-checker: enable From 9fbc98fc4edb505d830fa696dad8fd1e8d684e7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 18 Jun 2023 14:05:34 +0000 Subject: [PATCH 11/88] chore(deps): update rust crate rust-ini to 0.19.0 --- Cargo.lock | 62 +++++++++++++++++++++++++++++++++++++++++++++++------- Cargo.toml | 2 +- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7394c98a1..2e39978ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -371,6 +371,28 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "const-random" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" +dependencies = [ + "const-random-macro", + "proc-macro-hack", +] + +[[package]] +name = "const-random-macro" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" +dependencies = [ + "getrandom", + "once_cell", + "proc-macro-hack", + "tiny-keccak", +] + [[package]] name = "constant_time_eq" version = "0.2.4" @@ -809,9 +831,12 @@ dependencies = [ [[package]] name = "dlv-list" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" +checksum = "d529fd73d344663edfd598ccb3f344e46034db51ebd103518eae34338248ad73" +dependencies = [ + "const-random", +] [[package]] name = "dns-lookup" @@ -1106,6 +1131,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1572,12 +1603,12 @@ dependencies = [ [[package]] name = "ordered-multimap" -version = "0.4.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.13.2", ] [[package]] @@ -1774,6 +1805,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.47" @@ -1973,9 +2010,9 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" +checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" dependencies = [ "cfg-if", "ordered-multimap", @@ -2329,6 +2366,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "typenum" version = "1.15.0" @@ -2347,7 +2393,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" dependencies = [ - "hashbrown", + "hashbrown 0.12.3", "regex", ] diff --git a/Cargo.toml b/Cargo.toml index c0f6ab779..e92f6719e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -312,7 +312,7 @@ rayon = "1.7" redox_syscall = "0.3" regex = "1.8.4" rstest = "0.17.0" -rust-ini = "0.18.0" +rust-ini = "0.19.0" same-file = "1.0.6" selinux = "0.4" signal-hook = "0.3.15" From 7306be6e5862fd7081ea735effe6c17290523d19 Mon Sep 17 00:00:00 2001 From: Kostiantyn Hryshchuk Date: Sun, 18 Jun 2023 15:26:23 +0200 Subject: [PATCH 12/88] fixed shred -u for windows fixed shred panic on windows --- src/uu/shred/src/shred.rs | 4 +++- tests/by-util/test_shred.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/uu/shred/src/shred.rs b/src/uu/shred/src/shred.rs index 5ec1d1213..fd14a3245 100644 --- a/src/uu/shred/src/shred.rs +++ b/src/uu/shred/src/shred.rs @@ -532,7 +532,9 @@ fn wipe_name(orig_path: &Path, verbose: bool) -> Option { } // Sync every file rename - let new_file = File::open(new_path.clone()) + let new_file = OpenOptions::new() + .write(true) + .open(new_path.clone()) .expect("Failed to open renamed file for syncing"); new_file.sync_all().expect("Failed to sync renamed file"); diff --git a/tests/by-util/test_shred.rs b/tests/by-util/test_shred.rs index a34345aee..d98b840c4 100644 --- a/tests/by-util/test_shred.rs +++ b/tests/by-util/test_shred.rs @@ -18,7 +18,7 @@ fn test_shred_remove() { at.touch(file_b); // Shred file_a. - scene.ucmd().arg("-u").arg(file_a).run(); + scene.ucmd().arg("-u").arg(file_a).succeeds(); // file_a was deleted, file_b exists. assert!(!at.file_exists(file_a)); From b7154a80e121e75429769c6c04ac16bc9dc1325d Mon Sep 17 00:00:00 2001 From: Damon Harris Date: Sun, 18 Jun 2023 07:41:11 +0530 Subject: [PATCH 13/88] od: fix parsing of hex input ending with `E` --- src/uu/od/src/parse_nrofbytes.rs | 3 ++- tests/by-util/test_od.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/uu/od/src/parse_nrofbytes.rs b/src/uu/od/src/parse_nrofbytes.rs index 4c310755b..7d3bca03d 100644 --- a/src/uu/od/src/parse_nrofbytes.rs +++ b/src/uu/od/src/parse_nrofbytes.rs @@ -43,7 +43,7 @@ pub fn parse_number_of_bytes(s: &str) -> Result { len -= 1; } #[cfg(target_pointer_width = "64")] - Some('E') => { + Some('E') if radix != 16 => { multiply = 1024 * 1024 * 1024 * 1024 * 1024 * 1024; len -= 1; } @@ -84,6 +84,7 @@ fn test_parse_number_of_bytes() { // hex input assert_eq!(15, parse_number_of_bytes("0xf").unwrap()); + assert_eq!(14, parse_number_of_bytes("0XE").unwrap()); assert_eq!(15, parse_number_of_bytes("0XF").unwrap()); assert_eq!(27, parse_number_of_bytes("0x1b").unwrap()); assert_eq!(16 * 1024, parse_number_of_bytes("0x10k").unwrap()); diff --git a/tests/by-util/test_od.rs b/tests/by-util/test_od.rs index 24626cd76..54ac06384 100644 --- a/tests/by-util/test_od.rs +++ b/tests/by-util/test_od.rs @@ -627,6 +627,35 @@ fn test_skip_bytes() { )); } +#[test] +fn test_skip_bytes_hex() { + let input = "abcdefghijklmnopq"; // spell-checker:disable-line + new_ucmd!() + .arg("-c") + .arg("--skip-bytes=0xB") + .run_piped_stdin(input.as_bytes()) + .no_stderr() + .success() + .stdout_is(unindent( + " + 0000013 l m n o p q + 0000021 + ", + )); + new_ucmd!() + .arg("-c") + .arg("--skip-bytes=0xE") + .run_piped_stdin(input.as_bytes()) + .no_stderr() + .success() + .stdout_is(unindent( + " + 0000016 o p q + 0000021 + ", + )); +} + #[test] fn test_skip_bytes_error() { let input = "12345"; From 6ebfaf4b9d5ff2350a4b87b18a326cd0e8b50c14 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Mon, 12 Jun 2023 15:58:49 +0200 Subject: [PATCH 14/88] sort: migrate from ouroboros to self_cell --- Cargo.lock | 67 ++++--------------------------------- Cargo.toml | 2 +- src/uu/sort/Cargo.toml | 2 +- src/uu/sort/src/chunks.rs | 31 ++++++++--------- src/uu/sort/src/ext_sort.rs | 2 +- src/uu/sort/src/merge.rs | 2 +- 6 files changed, 27 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e39978ca..5721d1f55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" - [[package]] name = "adler" version = "1.0.2" @@ -43,12 +37,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - [[package]] name = "android-tzdata" version = "0.1.1" @@ -1620,29 +1608,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "ouroboros" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" -dependencies = [ - "aliasable", - "ouroboros_macro", -] - -[[package]] -name = "ouroboros_macro" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" -dependencies = [ - "Inflector", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "output_vt100" version = "0.1.3" @@ -1781,30 +1746,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -2082,6 +2023,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +[[package]] +name = "self_cell" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3926e239738d36060909ffe6f511502f92149a45a1fade7fe031cb2d33e88b" + [[package]] name = "selinux" version = "0.4.0" @@ -3145,9 +3092,9 @@ dependencies = [ "fnv", "itertools", "memchr", - "ouroboros", "rand", "rayon", + "self_cell", "tempfile", "unicode-width", "uucore", diff --git a/Cargo.toml b/Cargo.toml index e92f6719e..8f639c036 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -300,7 +300,6 @@ num-traits = "0.2.15" number_prefix = "0.4" once_cell = "1.18.0" onig = { version = "~6.4", default-features = false } -ouroboros = "0.15.6" parse_datetime = "0.4.0" phf = "0.11.1" phf_codegen = "0.11.1" @@ -314,6 +313,7 @@ regex = "1.8.4" rstest = "0.17.0" rust-ini = "0.19.0" same-file = "1.0.6" +self_cell = "1.0.0" selinux = "0.4" signal-hook = "0.3.15" smallvec = { version = "1.10", features = ["union"] } diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index 7540522ed..533b31831 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -22,9 +22,9 @@ ctrlc = { workspace = true } fnv = { workspace = true } itertools = { workspace = true } memchr = { workspace = true } -ouroboros = { workspace = true } rand = { workspace = true } rayon = { workspace = true } +self_cell = { workspace = true } tempfile = { workspace = true } unicode-width = { workspace = true } uucore = { workspace = true, features = ["fs"] } diff --git a/src/uu/sort/src/chunks.rs b/src/uu/sort/src/chunks.rs index 9b60d5f5b..ffee7e453 100644 --- a/src/uu/sort/src/chunks.rs +++ b/src/uu/sort/src/chunks.rs @@ -16,21 +16,22 @@ use std::{ }; use memchr::memchr_iter; -use ouroboros::self_referencing; +use self_cell::self_cell; use uucore::error::{UResult, USimpleError}; use crate::{numeric_str_cmp::NumInfo, GeneralF64ParseResult, GlobalSettings, Line, SortError}; -/// The chunk that is passed around between threads. -/// `lines` consist of slices into `buffer`. -#[self_referencing(pub_extras)] -#[derive(Debug)] -pub struct Chunk { - pub buffer: Vec, - #[borrows(buffer)] - #[covariant] - pub contents: ChunkContents<'this>, -} +self_cell!( + /// The chunk that is passed around between threads. + pub struct Chunk { + owner: Vec, + + #[covariant] + dependent: ChunkContents, + } + + impl {Debug} +); #[derive(Debug)] pub struct ChunkContents<'a> { @@ -48,7 +49,7 @@ pub struct LineData<'a> { impl Chunk { /// Destroy this chunk and return its components to be reused. pub fn recycle(mut self) -> RecycledChunk { - let recycled_contents = self.with_contents_mut(|contents| { + let recycled_contents = self.with_dependent_mut(|_, contents| { contents.lines.clear(); contents.line_data.selections.clear(); contents.line_data.num_infos.clear(); @@ -81,15 +82,15 @@ impl Chunk { selections: recycled_contents.1, num_infos: recycled_contents.2, parsed_floats: recycled_contents.3, - buffer: self.into_heads().buffer, + buffer: self.into_owner(), } } pub fn lines(&self) -> &Vec { - &self.borrow_contents().lines + &self.borrow_dependent().lines } pub fn line_data(&self) -> &LineData { - &self.borrow_contents().line_data + &self.borrow_dependent().line_data } } diff --git a/src/uu/sort/src/ext_sort.rs b/src/uu/sort/src/ext_sort.rs index 45ddc7304..27cb12d0b 100644 --- a/src/uu/sort/src/ext_sort.rs +++ b/src/uu/sort/src/ext_sort.rs @@ -158,7 +158,7 @@ fn reader_writer< /// The function that is executed on the sorter thread. fn sorter(receiver: &Receiver, sender: &SyncSender, settings: &GlobalSettings) { while let Ok(mut payload) = receiver.recv() { - payload.with_contents_mut(|contents| { + payload.with_dependent_mut(|_, contents| { sort_by(&mut contents.lines, settings, &contents.line_data); }); if sender.send(payload).is_err() { diff --git a/src/uu/sort/src/merge.rs b/src/uu/sort/src/merge.rs index f6da0ee32..7c682d88f 100644 --- a/src/uu/sort/src/merge.rs +++ b/src/uu/sort/src/merge.rs @@ -288,7 +288,7 @@ impl<'a> FileMerger<'a> { file_number: file.file_number, }); - file.current_chunk.with_contents(|contents| { + file.current_chunk.with_dependent(|_, contents| { let current_line = &contents.lines[file.line_idx]; if settings.unique { if let Some(prev) = &prev { From bf7f3783d1b2d075e93eb60bc32fb8ed8ddbff46 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 19 Jun 2023 19:10:53 +0200 Subject: [PATCH 15/88] yes: allow --version Test: tests/help/help-version-getopt.sh --- src/uu/yes/src/yes.rs | 3 ++- tests/by-util/test_yes.rs | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/uu/yes/src/yes.rs b/src/uu/yes/src/yes.rs index fd5124064..72c19b872 100644 --- a/src/uu/yes/src/yes.rs +++ b/src/uu/yes/src/yes.rs @@ -9,7 +9,7 @@ // cSpell:ignore strs -use clap::{builder::ValueParser, Arg, ArgAction, Command}; +use clap::{builder::ValueParser, crate_version, Arg, ArgAction, Command}; use std::error::Error; use std::ffi::OsString; use std::io::{self, Write}; @@ -44,6 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) + .version(crate_version!()) .about(ABOUT) .override_usage(format_usage(USAGE)) .arg( diff --git a/tests/by-util/test_yes.rs b/tests/by-util/test_yes.rs index 89a68e7e1..a674f8245 100644 --- a/tests/by-util/test_yes.rs +++ b/tests/by-util/test_yes.rs @@ -35,6 +35,11 @@ fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails().code_is(1); } +#[test] +fn test_version() { + new_ucmd!().arg("--version").succeeds(); +} + #[test] fn test_simple() { run(NO_ARGS, b"y\ny\ny\ny\n"); From e70d7d3b90c66596ab54b573c55f10a407bcdb2f Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 19 Jun 2023 22:32:49 +0200 Subject: [PATCH 16/88] Hack the tests/help/help-version-getopt.sh tests: * "hostid BEFORE --help" doesn't fail for GNU. we fail. we are probably doing better * "hostid BEFORE --help AFTER " same for this --- util/build-gnu.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 13fef7bb9..e3a523e34 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -232,3 +232,8 @@ sed -i -e "s/Try 'mv --help' for more information/For more information, try '--h sed -i -E "s|^([^#]*2_31.*)$|#\1|g" tests/misc/printf-cov.pl sed -i -e "s/du: invalid -t argument/du: invalid --threshold argument/" -e "s/du: option requires an argument/error: a value is required for '--threshold ' but none was supplied/" -e "/Try 'du --help' for more information./d" tests/du/threshold.sh + +# disable two kind of tests: +# "hostid BEFORE --help" doesn't fail for GNU. we fail. we are probably doing better +# "hostid BEFORE --help AFTER " same for this +sed -i -e "s/env \$prog \$BEFORE \$opt > out2/env \$prog \$BEFORE \$opt > out2 #/" -e "s/env \$prog \$BEFORE \$opt AFTER > out3/env \$prog \$BEFORE \$opt AFTER > out3 #/" -e "s/compare exp out2/compare exp out2 #/" -e "s/compare exp out3/compare exp out3 #/" tests/help/help-version-getopt.sh From e990f87edcac67e9df7f75d67a1c6c5fdce6548f Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 20 Jun 2023 15:23:54 +0200 Subject: [PATCH 17/88] touch: rename CURRENT to TIMESTAMP --- src/uu/touch/src/touch.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 55663fdab..8a21a2f5c 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -29,7 +29,7 @@ pub mod options { pub mod sources { pub static DATE: &str = "date"; pub static REFERENCE: &str = "reference"; - pub static CURRENT: &str = "current"; + pub static TIMESTAMP: &str = "timestamp"; } pub static HELP: &str = "help"; pub static ACCESS: &str = "access"; @@ -120,12 +120,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { (timestamp, timestamp) } (None, None) => { - let timestamp = - if let Some(current) = matches.get_one::(options::sources::CURRENT) { - parse_timestamp(current)? - } else { - local_dt_to_filetime(time::OffsetDateTime::now_local().unwrap()) - }; + let timestamp = if let Some(ts) = matches.get_one::(options::sources::TIMESTAMP) + { + parse_timestamp(ts)? + } else { + local_dt_to_filetime(time::OffsetDateTime::now_local().unwrap()) + }; (timestamp, timestamp) } }; @@ -243,7 +243,7 @@ pub fn uu_app() -> Command { .action(ArgAction::SetTrue), ) .arg( - Arg::new(options::sources::CURRENT) + Arg::new(options::sources::TIMESTAMP) .short('t') .help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time") .value_name("STAMP"), @@ -255,7 +255,7 @@ pub fn uu_app() -> Command { .allow_hyphen_values(true) .help("parse argument and use it instead of current time") .value_name("STRING") - .conflicts_with(options::sources::CURRENT), + .conflicts_with(options::sources::TIMESTAMP), ) .arg( Arg::new(options::MODIFICATION) @@ -288,7 +288,7 @@ pub fn uu_app() -> Command { .value_name("FILE") .value_parser(ValueParser::os_string()) .value_hint(clap::ValueHint::AnyPath) - .conflicts_with(options::sources::CURRENT), + .conflicts_with(options::sources::TIMESTAMP), ) .arg( Arg::new(options::TIME) @@ -311,7 +311,7 @@ pub fn uu_app() -> Command { .group( ArgGroup::new(options::SOURCES) .args([ - options::sources::CURRENT, + options::sources::TIMESTAMP, options::sources::DATE, options::sources::REFERENCE, ]) From 98ef87af867cca01ea13f08e09eac147f15bc2ae Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 20 Jun 2023 15:28:32 +0200 Subject: [PATCH 18/88] touch: cleanup "spell-checker:ignore" line --- 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 8a21a2f5c..4efea56c4 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 subsecond humantime +// spell-checker:ignore (ToDO) filetime datetime MMDDhhmm lpszfilepath mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME YYYYMMDDHHMMS subsecond humantime use clap::builder::ValueParser; use clap::{crate_version, Arg, ArgAction, ArgGroup, Command}; From 01af46e914e20936ae2c68ee4c06891233fdd0a0 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 20 Jun 2023 15:45:55 +0200 Subject: [PATCH 19/88] Use misc instead of test Co-authored-by: Daniel Hofstetter --- util/build-gnu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index e3a523e34..2b7e5c0bf 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -236,4 +236,4 @@ sed -i -e "s/du: invalid -t argument/du: invalid --threshold argument/" -e "s/du # disable two kind of tests: # "hostid BEFORE --help" doesn't fail for GNU. we fail. we are probably doing better # "hostid BEFORE --help AFTER " same for this -sed -i -e "s/env \$prog \$BEFORE \$opt > out2/env \$prog \$BEFORE \$opt > out2 #/" -e "s/env \$prog \$BEFORE \$opt AFTER > out3/env \$prog \$BEFORE \$opt AFTER > out3 #/" -e "s/compare exp out2/compare exp out2 #/" -e "s/compare exp out3/compare exp out3 #/" tests/help/help-version-getopt.sh +sed -i -e "s/env \$prog \$BEFORE \$opt > out2/env \$prog \$BEFORE \$opt > out2 #/" -e "s/env \$prog \$BEFORE \$opt AFTER > out3/env \$prog \$BEFORE \$opt AFTER > out3 #/" -e "s/compare exp out2/compare exp out2 #/" -e "s/compare exp out3/compare exp out3 #/" tests/misc/help-version-getopt.sh From c3f2ac6f044e1d00cb440214c7ddb5d5bdeea505 Mon Sep 17 00:00:00 2001 From: yt2b Date: Tue, 20 Jun 2023 23:20:22 +0900 Subject: [PATCH 20/88] yes: add --version option --- src/uu/yes/src/yes.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/uu/yes/src/yes.rs b/src/uu/yes/src/yes.rs index fd5124064..72c19b872 100644 --- a/src/uu/yes/src/yes.rs +++ b/src/uu/yes/src/yes.rs @@ -9,7 +9,7 @@ // cSpell:ignore strs -use clap::{builder::ValueParser, Arg, ArgAction, Command}; +use clap::{builder::ValueParser, crate_version, Arg, ArgAction, Command}; use std::error::Error; use std::ffi::OsString; use std::io::{self, Write}; @@ -44,6 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) + .version(crate_version!()) .about(ABOUT) .override_usage(format_usage(USAGE)) .arg( From a3fe70f7b2669202b70fa70c7df2a983230db8f0 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 20 Jun 2023 23:14:54 +0200 Subject: [PATCH 21/88] try to fix ignore intermittent --- .github/workflows/GnuTests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index 372bf0717..eb3e22a80 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -205,7 +205,7 @@ jobs: path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' # https://github.com/uutils/coreutils/issues/4294 # https://github.com/uutils/coreutils/issues/4295 - IGNORE_INTERMITTENT='${path_UUTILS}/.github/workflows/ignore-intermittent.txt' + IGNORE_INTERMITTENT="${path_UUTILS}/.github/workflows/ignore-intermittent.txt" mkdir -p ${{ steps.vars.outputs.path_reference }} From 98d242de7e880ae52667e651aa3e9cef8c9cee08 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 22 Jun 2023 10:04:37 +0200 Subject: [PATCH 22/88] nl: fix typo in nl.md --- src/uu/nl/nl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/nl/nl.md b/src/uu/nl/nl.md index b64b9f627..d7cfc698f 100644 --- a/src/uu/nl/nl.md +++ b/src/uu/nl/nl.md @@ -1,4 +1,4 @@ -#nl +# nl ``` nl [OPTION]... [FILE]... From c32139784a33619344179ff85e9f18cf4c2c32eb Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 22 Jun 2023 14:30:53 +0200 Subject: [PATCH 23/88] nl: implement Default for Settings --- src/uu/nl/src/nl.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/uu/nl/src/nl.rs b/src/uu/nl/src/nl.rs index 44fdec8c7..d3e90bc75 100644 --- a/src/uu/nl/src/nl.rs +++ b/src/uu/nl/src/nl.rs @@ -42,6 +42,24 @@ pub struct Settings { number_separator: String, } +impl Default for Settings { + fn default() -> Self { + Self { + header_numbering: NumberingStyle::NumberForNone, + body_numbering: NumberingStyle::NumberForAll, + footer_numbering: NumberingStyle::NumberForNone, + section_delimiter: ['\\', ':'], + starting_line_number: 1, + line_increment: 1, + join_blank_lines: 1, + number_width: 6, + number_format: NumberFormat::Right, + renumber: true, + number_separator: String::from("\t"), + } + } +} + // NumberingStyle stores which lines are to be numbered. // The possible options are: // 1. Number all lines @@ -87,20 +105,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; - // A mutable settings object, initialized with the defaults. - let mut settings = Settings { - header_numbering: NumberingStyle::NumberForNone, - body_numbering: NumberingStyle::NumberForAll, - footer_numbering: NumberingStyle::NumberForNone, - section_delimiter: ['\\', ':'], - starting_line_number: 1, - line_increment: 1, - join_blank_lines: 1, - number_width: 6, - number_format: NumberFormat::Right, - renumber: true, - number_separator: String::from("\t"), - }; + let mut settings = Settings::default(); // Update the settings from the command line options, and terminate the // program if some options could not successfully be parsed. From d00134640bb19cc91f706e511c16ef31c14502d7 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 22 Jun 2023 14:33:32 +0200 Subject: [PATCH 24/88] nl: use "const" instead of "static" --- src/uu/nl/src/nl.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/nl/src/nl.rs b/src/uu/nl/src/nl.rs index d3e90bc75..809ff2650 100644 --- a/src/uu/nl/src/nl.rs +++ b/src/uu/nl/src/nl.rs @@ -18,8 +18,8 @@ use uucore::{format_usage, help_about, help_usage}; mod helper; -static ABOUT: &str = help_about!("nl.md"); -static USAGE: &str = help_usage!("nl.md"); +const ABOUT: &str = help_about!("nl.md"); +const USAGE: &str = help_usage!("nl.md"); // Settings store options used by nl to produce its output. pub struct Settings { From 0010fece35cf81274474c00b97ed9d7cb4095bc8 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 22 Jun 2023 14:35:04 +0200 Subject: [PATCH 25/88] nl: remove "spell-checker:ignore" line --- src/uu/nl/src/nl.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/uu/nl/src/nl.rs b/src/uu/nl/src/nl.rs index 809ff2650..7e18d7588 100644 --- a/src/uu/nl/src/nl.rs +++ b/src/uu/nl/src/nl.rs @@ -6,8 +6,6 @@ // * file that was distributed with this source code. // * -// spell-checker:ignore (ToDO) corasick memchr - use clap::{crate_version, Arg, ArgAction, Command}; use std::fs::File; use std::io::{stdin, BufRead, BufReader, Read}; From 0144a3c78fc8f86767fc67ff19b1e5b7a33de471 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:43:21 +0000 Subject: [PATCH 26/88] fix(deps): update rust crate itertools to 0.11.0 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/uucore/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e39978ca..25414fb03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1275,9 +1275,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] diff --git a/Cargo.toml b/Cargo.toml index e92f6719e..c49b1c432 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -286,7 +286,7 @@ glob = "0.3.1" half = "2.2" indicatif = "0.17" is-terminal = "0.4.7" -itertools = "0.10.5" +itertools = "0.11.0" libc = "0.2.146" lscolors = { version = "0.14.0", default-features = false, features = [ "nu-ansi-term", diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 7fa4aa344..8fd5769c9 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -25,7 +25,7 @@ dunce = "1.0.4" wild = "2.1" glob = "0.3.1" # * optional -itertools = { version = "0.10.5", optional = true } +itertools = { version = "0.11.0", optional = true } thiserror = { workspace = true, optional = true } time = { workspace = true, optional = true, features = [ "formatting", From d57a5eb6a3c5f9f01b54f49d4961dc649763494f Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sat, 24 Jun 2023 07:07:38 +0200 Subject: [PATCH 27/88] seq: remove two chars in seq.md --- src/uu/seq/seq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/seq/seq.md b/src/uu/seq/seq.md index 065404e20..8e67391e4 100644 --- a/src/uu/seq/seq.md +++ b/src/uu/seq/seq.md @@ -5,5 +5,5 @@ Display numbers from FIRST to LAST, in steps of INCREMENT. ``` seq [OPTION]... LAST seq [OPTION]... FIRST LAST -seq [OPTION]... FIRST INCREMENT LAST"; +seq [OPTION]... FIRST INCREMENT LAST ``` From 9324a52a5692319e97293b310e65041b7b9337ee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 24 Jun 2023 08:25:07 +0000 Subject: [PATCH 28/88] chore(deps): update rust crate phf_codegen to 0.11.2 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25414fb03..1e4265dc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1702,9 +1702,9 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" dependencies = [ "phf_generator", "phf_shared", diff --git a/Cargo.toml b/Cargo.toml index c49b1c432..21c455f0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -303,7 +303,7 @@ onig = { version = "~6.4", default-features = false } ouroboros = "0.15.6" parse_datetime = "0.4.0" phf = "0.11.1" -phf_codegen = "0.11.1" +phf_codegen = "0.11.2" platform-info = "2.0.1" quick-error = "2.0.1" rand = { version = "0.8", features = ["small_rng"] } From a02b3354e6fdba967e71a1cc2807fc7ccd1c9b88 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 24 Jun 2023 11:23:11 +0000 Subject: [PATCH 29/88] chore(deps): update rust crate phf to 0.11.2 --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e4265dc7..240c14bc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1693,9 +1693,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "phf" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_shared", ] @@ -1722,9 +1722,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] diff --git a/Cargo.toml b/Cargo.toml index 21c455f0a..d975bace9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -302,7 +302,7 @@ once_cell = "1.18.0" onig = { version = "~6.4", default-features = false } ouroboros = "0.15.6" parse_datetime = "0.4.0" -phf = "0.11.1" +phf = "0.11.2" phf_codegen = "0.11.2" platform-info = "2.0.1" quick-error = "2.0.1" From ddcdda44db9ebbd8a8c73f6a167b0b76a7236915 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 25 Jun 2023 00:18:33 +0200 Subject: [PATCH 30/88] Remove the auto capitalization of error message --- src/uucore/src/lib/mods/error.rs | 11 +---------- tests/by-util/test_cp.rs | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index e564c7bb5..f0f62569d 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -396,7 +396,7 @@ impl Display for UIoError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { use std::io::ErrorKind::*; - let mut message; + let message; let message = if self.inner.raw_os_error().is_some() { // These are errors that come directly from the OS. // We want to normalize their messages across systems, @@ -424,7 +424,6 @@ impl Display for UIoError { // (https://github.com/rust-lang/rust/issues/86442) // are stabilized, we should add them to the match statement. message = strip_errno(&self.inner); - capitalize(&mut message); &message } } @@ -435,7 +434,6 @@ impl Display for UIoError { // a file that was not found. // There are also errors with entirely custom messages. message = self.inner.to_string(); - capitalize(&mut message); &message }; if let Some(ctx) = &self.context { @@ -446,13 +444,6 @@ impl Display for UIoError { } } -/// Capitalize the first character of an ASCII string. -fn capitalize(text: &mut str) { - if let Some(first) = text.get_mut(..1) { - first.make_ascii_uppercase(); - } -} - /// Strip the trailing " (os error XX)" from io error strings. pub fn strip_errno(err: &std::io::Error) -> String { let mut msg = err.to_string(); diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index fa5845eac..5289489ea 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -2724,7 +2724,7 @@ fn test_copy_dir_preserve_permissions_inaccessible_file() { ucmd.args(&["-p", "-R", "d1", "d2"]) .fails() .code_is(1) - .stderr_only("cp: cannot open 'd1/f' for reading: Permission denied\n"); + .stderr_only("cp: cannot open 'd1/f' for reading: permission denied\n"); assert!(at.dir_exists("d2")); assert!(!at.file_exists("d2/f")); From 2f1b710752864bad86acf97a97bc5291efcfcce0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 25 Jun 2023 12:12:26 +0000 Subject: [PATCH 31/88] chore(deps): update vmactions/freebsd-vm action to v0.3.1 --- .github/workflows/freebsd.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index 9507b3a56..095ec3230 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -35,7 +35,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.3 - name: Prepare, build and test - uses: vmactions/freebsd-vm@v0.3.0 + uses: vmactions/freebsd-vm@v0.3.1 with: usesh: true # We need jq to run show-utils.sh and bash to use inline shell string replacement @@ -125,7 +125,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.3 - name: Prepare, build and test - uses: vmactions/freebsd-vm@v0.3.0 + uses: vmactions/freebsd-vm@v0.3.1 with: usesh: true # sync: sshfs From ae90bad6cf0baeec5441b594cdebdd357b0cdce3 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sun, 25 Jun 2023 16:53:50 +0200 Subject: [PATCH 32/88] docs: add seq to extensions; add some backticks --- docs/src/extensions.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/src/extensions.md b/docs/src/extensions.md index 281d8ef2e..428ae84ca 100644 --- a/docs/src/extensions.md +++ b/docs/src/extensions.md @@ -61,7 +61,11 @@ feature is adopted from [FreeBSD](https://www.freebsd.org/cgi/man.cgi?cut). ## `fmt` -`fmt` has additional flags for prefixes: `-P/--skip-prefix`, `-x/--exact-prefix`, and -`-X/--exact-skip-prefix`. With `-m/--preserve-headers`, an attempt is made to detect and preserve -mail headers in the input. `-q/--quick` breaks lines more quickly. And `-T/--tab-width` defines the +`fmt` has additional flags for prefixes: `-P`/`--skip-prefix`, `-x`/`--exact-prefix`, and +`-X`/`--exact-skip-prefix`. With `-m`/`--preserve-headers`, an attempt is made to detect and preserve +mail headers in the input. `-q`/`--quick` breaks lines more quickly. And `-T`/`--tab-width` defines the number of spaces representing a tab when determining the line length. + +## `seq` + +`seq` provides `-t`/`--terminator` to set the terminator character. From 824097d22469d07e658597182a110a618d545763 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 25 Jun 2023 19:09:01 +0000 Subject: [PATCH 33/88] fix(deps): update rust crate libc to 0.2.147 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/uucore/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 240c14bc5..b50c79e02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1340,9 +1340,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" diff --git a/Cargo.toml b/Cargo.toml index d975bace9..6ec760a27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -287,7 +287,7 @@ half = "2.2" indicatif = "0.17" is-terminal = "0.4.7" itertools = "0.11.0" -libc = "0.2.146" +libc = "0.2.147" lscolors = { version = "0.14.0", default-features = false, features = [ "nu-ansi-term", ] } diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 8fd5769c9..19054811c 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -36,7 +36,7 @@ time = { workspace = true, optional = true, features = [ data-encoding = { version = "2.4", optional = true } data-encoding-macro = { version = "0.1.13", optional = true } z85 = { version = "3.0.5", optional = true } -libc = { version = "0.2.146", optional = true } +libc = { version = "0.2.147", optional = true } once_cell = { workspace = true } os_display = "0.1.3" From 0ba972b2139cc90317e5c560dd3c2e44beb5d3ac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 25 Jun 2023 19:15:50 +0000 Subject: [PATCH 34/88] chore(deps): update rust crate self_cell to 1.0.1 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0d0f11e0..5c095a916 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2025,9 +2025,9 @@ checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" [[package]] name = "self_cell" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3926e239738d36060909ffe6f511502f92149a45a1fade7fe031cb2d33e88b" +checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6" [[package]] name = "selinux" diff --git a/Cargo.toml b/Cargo.toml index 609bd3e57..3be87fad8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -313,7 +313,7 @@ regex = "1.8.4" rstest = "0.17.0" rust-ini = "0.19.0" same-file = "1.0.6" -self_cell = "1.0.0" +self_cell = "1.0.1" selinux = "0.4" signal-hook = "0.3.15" smallvec = { version = "1.10", features = ["union"] } From b34e7f7bf6b7fe851a7579e92aa6be37fc95e9be Mon Sep 17 00:00:00 2001 From: John Shin Date: Tue, 20 Jun 2023 11:28:05 -0700 Subject: [PATCH 35/88] du: directories have apparent size of 0 --- src/uu/du/src/du.rs | 4 +- tests/by-util/test_du.rs | 117 +++++++++++++-------------------------- tests/common/util.rs | 11 ++++ 3 files changed, 52 insertions(+), 80 deletions(-) diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index 3325ca1f5..db385c720 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -145,7 +145,7 @@ impl Stat { return Ok(Self { path: path.to_path_buf(), is_dir: metadata.is_dir(), - size: metadata.len(), + size: if path.is_dir() { 0 } else { metadata.len() }, blocks: metadata.blocks(), inodes: 1, inode: Some(file_info), @@ -162,7 +162,7 @@ impl Stat { Ok(Self { path: path.to_path_buf(), is_dir: metadata.is_dir(), - size: metadata.len(), + size: if path.is_dir() { 0 } else { metadata.len() }, blocks: size_on_disk / 1024 * 2, inode: file_info, inodes: 1, diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 699746f03..892b5cfb1 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -580,97 +580,58 @@ fn test_du_invalid_threshold() { #[test] fn test_du_apparent_size() { - let ts = TestScenario::new(util_name!()); - let result = ts.ucmd().arg("--apparent-size").succeeds(); + let (at, mut ucmd) = at_and_ucmd!(); - #[cfg(any(target_os = "linux", target_os = "android"))] + at.mkdir_all("a/b"); + + at.write("a/b/file1", "foo"); + at.write("a/b/file2", "foobar"); + + let result = ucmd.args(&["--apparent-size", "--all", "a"]).succeeds(); + + #[cfg(not(target_os = "windows"))] { - let result_reference = unwrap_or_return!(expected_result(&ts, &["--apparent-size"])); - assert_eq!(result.stdout_str(), result_reference.stdout_str()); + result.stdout_contains_line("1\ta/b/file2"); + result.stdout_contains_line("1\ta/b/file1"); + result.stdout_contains_line("1\ta/b"); + result.stdout_contains_line("1\ta"); } - #[cfg(not(any(target_os = "linux", target_os = "android")))] - _du_apparent_size(result.stdout_str()); -} - -#[cfg(target_os = "windows")] -fn _du_apparent_size(s: &str) { - assert_eq!( - s, - "1\t.\\subdir\\deeper\\deeper_dir -1\t.\\subdir\\deeper -6\t.\\subdir\\links -6\t.\\subdir -6\t. -" - ); -} -#[cfg(target_vendor = "apple")] -fn _du_apparent_size(s: &str) { - assert_eq!( - s, - "1\t./subdir/deeper/deeper_dir -1\t./subdir/deeper -6\t./subdir/links -6\t./subdir -6\t. -" - ); -} -#[cfg(target_os = "freebsd")] -fn _du_apparent_size(s: &str) { - assert_eq!( - s, - "1\t./subdir/deeper/deeper_dir -2\t./subdir/deeper -6\t./subdir/links -8\t./subdir -8\t. -" - ); -} -#[cfg(all( - not(target_vendor = "apple"), - not(target_os = "windows"), - not(target_os = "freebsd") -))] -fn _du_apparent_size(s: &str) { - assert_eq!( - s, - "5\t./subdir/deeper/deeper_dir -9\t./subdir/deeper -10\t./subdir/links -22\t./subdir -26\t. -" - ); + #[cfg(target_os = "windows")] + { + result.stdout_contains_line("1\ta\\b\\file2"); + result.stdout_contains_line("1\ta\\b\\file1"); + result.stdout_contains_line("1\ta\\b"); + result.stdout_contains_line("1\ta"); + } } #[test] fn test_du_bytes() { - let ts = TestScenario::new(util_name!()); - let result = ts.ucmd().arg("--bytes").succeeds(); + let (at, mut ucmd) = at_and_ucmd!(); - #[cfg(any(target_os = "linux", target_os = "android"))] + at.mkdir_all("a/b"); + + at.write("a/b/file1", "foo"); + at.write("a/b/file2", "foobar"); + + let result = ucmd.args(&["--bytes", "--all", "a"]).succeeds(); + + #[cfg(not(target_os = "windows"))] { - let result_reference = unwrap_or_return!(expected_result(&ts, &["--bytes"])); - assert_eq!(result.stdout_str(), result_reference.stdout_str()); + result.stdout_contains_line("6\ta/b/file2"); + result.stdout_contains_line("3\ta/b/file1"); + result.stdout_contains_line("9\ta/b"); + result.stdout_contains_line("9\ta"); } #[cfg(target_os = "windows")] - result.stdout_contains("5145\t.\\subdir\n"); - #[cfg(target_vendor = "apple")] - result.stdout_contains("5625\t./subdir\n"); - #[cfg(target_os = "freebsd")] - result.stdout_contains("7193\t./subdir\n"); - #[cfg(all( - not(target_vendor = "apple"), - not(target_os = "windows"), - not(target_os = "freebsd"), - not(target_os = "linux"), - not(target_os = "android"), - ))] - result.stdout_contains("21529\t./subdir\n"); + { + result.stdout_contains_line("6\ta\\b\\file2"); + result.stdout_contains_line("3\ta\\b\\file1"); + result.stdout_contains_line("9\ta\\b"); + result.stdout_contains_line("9\ta"); + } } #[test] diff --git a/tests/common/util.rs b/tests/common/util.rs index 0898a4ad7..995312f08 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -659,6 +659,17 @@ impl CmdResult { self } + #[track_caller] + pub fn stdout_contains_line>(&self, cmp: T) -> &Self { + assert!( + self.stdout_str().lines().any(|line| line == cmp.as_ref()), + "'{}' does not contain line '{}'", + self.stdout_str(), + cmp.as_ref() + ); + self + } + #[track_caller] pub fn stderr_contains>(&self, cmp: T) -> &Self { assert!( From c64f3ccbdd2810fbd6d85b0573772c20efe20d31 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 04:29:30 +0000 Subject: [PATCH 36/88] chore(deps): update rust crate fundu to 1.1.0 --- Cargo.lock | 13 +++++++++++-- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0d0f11e0..3055d7394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -969,9 +969,18 @@ dependencies = [ [[package]] name = "fundu" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47af3b646bdd738395be2db903fc11a5923b5e206016b8d4ad6db890bcae9bd5" +checksum = "d579dcb632d86591bdd7fc445e705b96cb2a7fb5488d918d956f392b6148e898" +dependencies = [ + "fundu-core", +] + +[[package]] +name = "fundu-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a363b75dd1e4b5bd2cdc305c47399c524cae24638b368b66b1a4c2a36482801f" [[package]] name = "futures" diff --git a/Cargo.toml b/Cargo.toml index 609bd3e57..cd52536f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -280,7 +280,7 @@ filetime = "0.2" fnv = "1.0.7" fs_extra = "1.3.0" fts-sys = "0.2" -fundu = "1.0.0" +fundu = "1.1.0" gcd = "2.3" glob = "0.3.1" half = "2.2" From 80c7ed9732562633a63aea8d0705b7ffe9a99bf8 Mon Sep 17 00:00:00 2001 From: Guillaume Ranquet Date: Thu, 8 Jun 2023 11:26:21 +0200 Subject: [PATCH 37/88] ls: force fetching metadata when called with -L -Z The metadata are not used but it permits to check the symlink is valid. We then return 1 on invalid symlinks when ls is invoked with ls -L -Z Signed-off-by: Guillaume Ranquet --- src/uu/ls/src/ls.rs | 14 ++++++++++++++ tests/by-util/test_ls.rs | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 7db591cf3..342c52cba 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -3008,6 +3008,20 @@ fn display_inode(metadata: &Metadata) -> String { #[allow(unused_variables)] fn get_security_context(config: &Config, p_buf: &Path, must_dereference: bool) -> String { let substitute_string = "?".to_string(); + // If we must dereference, ensure that the symlink is actually valid even if the system + // does not support SELinux. + // Conforms to the GNU coreutils where a dangling symlink results in exit code 1. + if must_dereference { + match get_metadata(p_buf, must_dereference) { + Err(err) => { + // The Path couldn't be dereferenced, so return early and set exit code 1 + // to indicate a minor error + show!(LsError::IOErrorContext(err, p_buf.to_path_buf(), false)); + return substitute_string; + } + Ok(md) => (), + } + } if config.selinux_supported { #[cfg(feature = "selinux")] { diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 1266a7cab..ad2c6424f 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -3137,6 +3137,16 @@ fn test_ls_dangling_symlinks() { .stderr_contains("No such file or directory") .stdout_contains(if cfg!(windows) { "dangle" } else { "? dangle" }); + scene + .ucmd() + .arg("-LZ") + .arg("temp_dir") + .fails() + .code_is(1) + .stderr_contains("cannot access") + .stderr_contains("No such file or directory") + .stdout_contains(if cfg!(windows) { "dangle" } else { "? dangle" }); + scene .ucmd() .arg("-Ll") From c05dbfa3b4f813019c2c668ace7fbc2fbf806c93 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Mon, 26 Jun 2023 16:21:59 +0200 Subject: [PATCH 38/88] seq: rename "--widths" to "--equal-width" for compatibility with GNU seq --- src/uu/seq/src/seq.rs | 14 +++++++------- tests/by-util/test_seq.rs | 11 +++++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/uu/seq/src/seq.rs b/src/uu/seq/src/seq.rs index 97382ed1b..4562ddb7d 100644 --- a/src/uu/seq/src/seq.rs +++ b/src/uu/seq/src/seq.rs @@ -31,7 +31,7 @@ const USAGE: &str = help_usage!("seq.md"); const OPT_SEPARATOR: &str = "separator"; const OPT_TERMINATOR: &str = "terminator"; -const OPT_WIDTHS: &str = "widths"; +const OPT_EQUAL_WIDTH: &str = "equal-width"; const OPT_FORMAT: &str = "format"; const ARG_NUMBERS: &str = "numbers"; @@ -40,7 +40,7 @@ const ARG_NUMBERS: &str = "numbers"; struct SeqOptions<'a> { separator: String, terminator: String, - widths: bool, + equal_width: bool, format: Option<&'a str>, } @@ -74,7 +74,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map(|s| s.as_str()) .unwrap_or("\n") .to_string(), - widths: matches.get_flag(OPT_WIDTHS), + equal_width: matches.get_flag(OPT_EQUAL_WIDTH), format: matches.get_one::(OPT_FORMAT).map(|s| s.as_str()), }; @@ -123,7 +123,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { (first, increment, last), &options.separator, &options.terminator, - options.widths, + options.equal_width, padding, options.format, ) @@ -137,7 +137,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { largest_dec, &options.separator, &options.terminator, - options.widths, + options.equal_width, padding, options.format, ), @@ -170,9 +170,9 @@ pub fn uu_app() -> Command { .help("Terminator character (defaults to \\n)"), ) .arg( - Arg::new(OPT_WIDTHS) + Arg::new(OPT_EQUAL_WIDTH) .short('w') - .long("widths") + .long("equal-width") .help("Equalize widths of all numbers by padding with zeros") .action(ArgAction::SetTrue), ) diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index 63015b24a..02509b3b5 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -208,10 +208,13 @@ fn test_separator_and_terminator() { #[test] fn test_equalize_widths() { - new_ucmd!() - .args(&["-w", "5", "10"]) - .run() - .stdout_is("05\n06\n07\n08\n09\n10\n"); + let args = ["-w", "--equal-width"]; + for arg in args { + new_ucmd!() + .args(&[arg, "5", "10"]) + .run() + .stdout_is("05\n06\n07\n08\n09\n10\n"); + } } #[test] From 479340306ee339705dd8c15ebf549bf2a5d7ce24 Mon Sep 17 00:00:00 2001 From: Ideflop <94184575+Ideflop@users.noreply.github.com> Date: Mon, 5 Jun 2023 18:48:45 +0200 Subject: [PATCH 39/88] more: implement arguments -u/--plain and -F/--from-line --- src/uu/more/src/more.rs | 78 +++++++++++++++++++++++++------------- tests/by-util/test_more.rs | 8 ++++ 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index a43489566..43c5c5163 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -50,10 +50,11 @@ pub mod options { pub const FILES: &str = "files"; } -const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n"; +const MULTI_FILE_TOP_PROMPT: &str = "\r::::::::::::::\n\r{}\n\r::::::::::::::\n"; struct Options { clean_print: bool, + from_line: usize, lines: Option, print_over: bool, silent: bool, @@ -72,8 +73,13 @@ impl Options { (None, Some(number)) if number > 0 => Some(number + 1), (_, _) => None, }; + let from_line = match matches.get_one::(options::FROM_LINE).copied() { + Some(number) if number > 1 => number - 1, + _ => 0, + }; Self { clean_print: matches.get_flag(options::CLEAN_PRINT), + from_line, lines, print_over: matches.get_flag(options::PRINT_OVER), silent: matches.get_flag(options::SILENT), @@ -90,7 +96,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Err(e) => return Err(e.into()), }; - let options = Options::from(&matches); + let mut options = Options::from(&matches); let mut buff = String::new(); @@ -115,9 +121,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { format!("cannot open {}: No such file or directory", file.quote()), )); } - if length > 1 { - buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", file.to_str().unwrap())); - } let opened_file = match File::open(file) { Err(why) => { terminal::disable_raw_mode().unwrap(); @@ -130,14 +133,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; let mut reader = BufReader::new(opened_file); reader.read_to_string(&mut buff).unwrap(); - more(&buff, &mut stdout, next_file.copied(), &options)?; + more( + &buff, + &mut stdout, + length > 1, + file.to_str(), + next_file.copied(), + &mut options, + )?; buff.clear(); } reset_term(&mut stdout); } else if !std::io::stdin().is_terminal() { stdin().read_to_string(&mut buff).unwrap(); let mut stdout = setup_term(); - more(&buff, &mut stdout, None, &options)?; + more(&buff, &mut stdout, false, None, None, &mut options)?; reset_term(&mut stdout); } else { return Err(UUsageError::new(1, "bad usage")); @@ -179,6 +189,22 @@ pub fn uu_app() -> Command { .help("Squeeze multiple blank lines into one") .action(ArgAction::SetTrue), ) + .arg( + Arg::new(options::PLAIN) + .short('u') + .long(options::PLAIN) + .action(ArgAction::SetTrue) + .hide(true), + ) + .arg( + Arg::new(options::FROM_LINE) + .short('F') + .long(options::FROM_LINE) + .num_args(1) + .value_name("number") + .value_parser(value_parser!(usize)) + .help("Display file beginning from line number"), + ) .arg( Arg::new(options::LINES) .short('n') @@ -191,7 +217,6 @@ pub fn uu_app() -> Command { .arg( Arg::new(options::NUMBER) .long(options::NUMBER) - .required(false) .num_args(1) .value_parser(value_parser!(u16).range(0..)) .help("Same as --lines"), @@ -210,21 +235,6 @@ pub fn uu_app() -> Command { .long(options::NO_PAUSE) .help("Suppress pause after form feed"), ) - .arg( - Arg::new(options::PLAIN) - .short('u') - .long(options::PLAIN) - .help("Suppress underlining and bold"), - ) - .arg( - Arg::new(options::FROM_LINE) - .short('F') - .allow_hyphen_values(true) - .required(false) - .takes_value(true) - .value_name("number") - .help("Display file beginning from line number"), - ) .arg( Arg::new(options::PATTERN) .short('P') @@ -273,8 +283,10 @@ fn reset_term(_: &mut usize) {} fn more( buff: &str, stdout: &mut Stdout, + multiple_file: bool, + file: Option<&str>, next_file: Option<&str>, - options: &Options, + options: &mut Options, ) -> UResult<()> { let (cols, mut rows) = terminal::size().unwrap(); if let Some(number) = options.lines { @@ -284,7 +296,22 @@ fn more( let lines = break_buff(buff, usize::from(cols)); let mut pager = Pager::new(rows, lines, next_file, options); + + if multiple_file { + execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap(); + stdout.write_all( + MULTI_FILE_TOP_PROMPT + .replace("{}", file.unwrap_or_default()) + .as_bytes(), + )?; + pager.content_rows -= 3; + } pager.draw(stdout, None); + if multiple_file { + options.from_line = 0; + pager.content_rows += 3; + } + if pager.should_close() { return Ok(()); } @@ -406,7 +433,7 @@ impl<'a> Pager<'a> { fn new(rows: u16, lines: Vec, next_file: Option<&'a str>, options: &Options) -> Self { let line_count = lines.len(); Self { - upper_mark: 0, + upper_mark: options.from_line, content_rows: rows.saturating_sub(1), lines, next_file, @@ -535,7 +562,6 @@ impl<'a> Pager<'a> { }; let status = format!("--More--({status_inner})"); - let banner = match (self.silent, wrong_key) { (true, Some(key)) => format!( "{status} [Unknown key: '{key}'. Press 'h' for instructions. (unimplemented)]" diff --git a/tests/by-util/test_more.rs b/tests/by-util/test_more.rs index 95a4818b5..15388bbf6 100644 --- a/tests/by-util/test_more.rs +++ b/tests/by-util/test_more.rs @@ -21,9 +21,15 @@ fn test_valid_arg() { new_ucmd!().arg("-s").succeeds(); new_ucmd!().arg("--squeeze").succeeds(); + new_ucmd!().arg("-u").succeeds(); + new_ucmd!().arg("--plain").succeeds(); + new_ucmd!().arg("-n").arg("10").succeeds(); new_ucmd!().arg("--lines").arg("0").succeeds(); new_ucmd!().arg("--number").arg("0").succeeds(); + + new_ucmd!().arg("-F").arg("10").succeeds(); + new_ucmd!().arg("--from-line").arg("0").succeeds(); } } @@ -34,6 +40,8 @@ fn test_invalid_arg() { new_ucmd!().arg("--lines").arg("-10").fails(); new_ucmd!().arg("--number").arg("-10").fails(); + + new_ucmd!().arg("--from-line").arg("-10").fails(); } } From 77f8201fb8ab48e8f290c564e0c3dfe68b2a7687 Mon Sep 17 00:00:00 2001 From: Ideflop <94184575+Ideflop@users.noreply.github.com> Date: Mon, 5 Jun 2023 18:55:44 +0200 Subject: [PATCH 40/88] more: fix bug not displaying next file message and not stopping at end of file --- src/uu/more/src/more.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index 43c5c5163..c488ba8af 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -312,7 +312,7 @@ fn more( pager.content_rows += 3; } - if pager.should_close() { + if pager.should_close() && next_file.is_none() { return Ok(()); } @@ -499,10 +499,10 @@ impl<'a> Pager<'a> { } fn draw(&mut self, stdout: &mut std::io::Stdout, wrong_key: Option) { + self.draw_lines(stdout); let lower_mark = self .line_count .min(self.upper_mark.saturating_add(self.content_rows.into())); - self.draw_lines(stdout); self.draw_prompt(stdout, lower_mark, wrong_key); stdout.flush().unwrap(); } From c4c3a354f84ff9786453b1d7ae5cda2e328ddcf4 Mon Sep 17 00:00:00 2001 From: Ideflop <94184575+Ideflop@users.noreply.github.com> Date: Tue, 6 Jun 2023 22:03:44 +0200 Subject: [PATCH 41/88] tests/more: test argument --from-line --- tests/by-util/test_more.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/by-util/test_more.rs b/tests/by-util/test_more.rs index 15388bbf6..d94a92185 100644 --- a/tests/by-util/test_more.rs +++ b/tests/by-util/test_more.rs @@ -45,6 +45,40 @@ fn test_invalid_arg() { } } +#[test] +fn test_argument_from_file() { + if std::io::stdout().is_terminal() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + let file = "test_file"; + + at.write(file, "1\n2"); + + // output all lines + scene + .ucmd() + .arg("-F") + .arg("0") + .arg(file) + .succeeds() + .no_stderr() + .stdout_contains("1") + .stdout_contains("2"); + + // output only the second line + scene + .ucmd() + .arg("-F") + .arg("2") + .arg(file) + .succeeds() + .no_stderr() + .stdout_contains("2") + .stdout_does_not_contain("1"); + } +} + #[test] fn test_more_dir_arg() { // Run the test only if there's a valid terminal, else do nothing From 01f70768d99e47a290568edaf165472a118fa39c Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 27 Jun 2023 14:57:06 +0200 Subject: [PATCH 42/88] cp: fix "unused variable" warnings on Windows --- tests/by-util/test_cp.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 5289489ea..3a00870c5 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1110,12 +1110,12 @@ fn test_cp_parents_with_permissions_copy_file() { at.mkdir_all("p1/p2"); at.touch(file); - let p1_mode = 0o0777; - let p2_mode = 0o0711; - let file_mode = 0o0702; - #[cfg(unix)] { + let p1_mode = 0o0777; + let p2_mode = 0o0711; + let file_mode = 0o0702; + at.set_mode("p1", p1_mode); at.set_mode("p1/p2", p2_mode); at.set_mode(file, file_mode); @@ -1151,12 +1151,12 @@ fn test_cp_parents_with_permissions_copy_dir() { at.mkdir_all(dir2); at.touch(file); - let p1_mode = 0o0777; - let p2_mode = 0o0711; - let file_mode = 0o0702; - #[cfg(unix)] { + let p1_mode = 0o0777; + let p2_mode = 0o0711; + let file_mode = 0o0702; + at.set_mode("p1", p1_mode); at.set_mode("p1/p2", p2_mode); at.set_mode(file, file_mode); @@ -3134,6 +3134,8 @@ fn test_cp_debug_sparse_auto() { .arg("a") .arg("b") .succeeds(); + + #[cfg(any(target_os = "linux", target_os = "macos"))] let stdout_str = result.stdout_str(); #[cfg(target_os = "macos")] From c99d81a05b1db27531686589d0635191f7a8c5f5 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 27 Jun 2023 15:05:27 +0200 Subject: [PATCH 43/88] du: fix "unused import" warning on Windows --- tests/by-util/test_du.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 892b5cfb1..d365bd87e 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -6,6 +6,7 @@ // spell-checker:ignore (paths) sublink subwords azerty azeaze xcwww azeaz amaz azea qzerty tazerty tsublink #[cfg(not(windows))] use regex::Regex; +#[cfg(not(windows))] use std::io::Write; #[cfg(any(target_os = "linux", target_os = "android"))] From 732dbb3f125ffa8540bba3a6de5e66f39c681fa3 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 27 Jun 2023 16:46:50 +0200 Subject: [PATCH 44/88] cp: fix "unused variable" warning on Windows --- tests/by-util/test_cp.rs | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 3a00870c5..3074513de 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -3127,8 +3127,9 @@ fn test_cp_debug_sparse_auto() { let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; at.touch("a"); - let result = ts - .ucmd() + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] + ts.ucmd() .arg("--debug") .arg("--sparse=auto") .arg("a") @@ -3136,18 +3137,29 @@ fn test_cp_debug_sparse_auto() { .succeeds(); #[cfg(any(target_os = "linux", target_os = "macos"))] - let stdout_str = result.stdout_str(); - - #[cfg(target_os = "macos")] - if !stdout_str - .contains("copy offload: unknown, reflink: unsupported, sparse detection: unsupported") { - panic!("Failure: stdout was \n{stdout_str}"); - } + let result = ts + .ucmd() + .arg("--debug") + .arg("--sparse=auto") + .arg("a") + .arg("b") + .succeeds(); - #[cfg(target_os = "linux")] - if !stdout_str.contains("copy offload: unknown, reflink: unsupported, sparse detection: no") { - panic!("Failure: stdout was \n{stdout_str}"); + let stdout_str = result.stdout_str(); + + #[cfg(target_os = "macos")] + if !stdout_str + .contains("copy offload: unknown, reflink: unsupported, sparse detection: unsupported") + { + panic!("Failure: stdout was \n{stdout_str}"); + } + + #[cfg(target_os = "linux")] + if !stdout_str.contains("copy offload: unknown, reflink: unsupported, sparse detection: no") + { + panic!("Failure: stdout was \n{stdout_str}"); + } } } From 2d76a3b88e8922a8f7c4cc76cbab38bbafa1b155 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 28 Jun 2023 14:43:35 +0200 Subject: [PATCH 45/88] df: disable failing tests on Windows --- tests/by-util/test_df.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index a5100e471..926d1be5d 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -258,7 +258,7 @@ fn test_type_option() { } #[test] -#[cfg(not(target_os = "freebsd"))] // FIXME: fix this test for FreeBSD +#[cfg(not(any(target_os = "freebsd", target_os = "windows")))] // FIXME: fix test for FreeBSD & Win fn test_type_option_with_file() { let fs_type = new_ucmd!() .args(&["--output=fstype", "."]) @@ -806,7 +806,7 @@ fn test_output_file_all_filesystems() { } #[test] -#[cfg(not(target_os = "freebsd"))] // FIXME: fix this test for FreeBSD +#[cfg(not(any(target_os = "freebsd", target_os = "windows")))] // FIXME: fix test for FreeBSD & Win fn test_output_file_specific_files() { // Create three files. let (at, mut ucmd) = at_and_ucmd!(); @@ -825,7 +825,7 @@ fn test_output_file_specific_files() { } #[test] -#[cfg(not(target_os = "freebsd"))] // FIXME: fix this test for FreeBSD +#[cfg(not(any(target_os = "freebsd", target_os = "windows")))] // FIXME: fix test for FreeBSD & Win fn test_file_column_width_if_filename_contains_unicode_chars() { let (at, mut ucmd) = at_and_ucmd!(); at.touch("äöü.txt"); @@ -848,7 +848,7 @@ fn test_output_field_no_more_than_once() { } #[test] -#[cfg(not(target_os = "freebsd"))] // FIXME: fix this test for FreeBSD +#[cfg(not(any(target_os = "freebsd", target_os = "windows")))] // FIXME: fix test for FreeBSD & Win fn test_nonexistent_file() { new_ucmd!() .arg("does-not-exist") From 24aff229da4adba9e9ab5ed05e536f57d9a7ee3a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 23 Jun 2023 23:58:38 +0200 Subject: [PATCH 46/88] Add a function to detect if file is likely to be the simple backup file --- src/uucore/src/lib/mods/backup_control.rs | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/uucore/src/lib/mods/backup_control.rs b/src/uucore/src/lib/mods/backup_control.rs index 2d161c43f..9998c7560 100644 --- a/src/uucore/src/lib/mods/backup_control.rs +++ b/src/uucore/src/lib/mods/backup_control.rs @@ -438,6 +438,32 @@ fn existing_backup_path(path: &Path, suffix: &str) -> PathBuf { } } +/// Returns true if the source file is likely to be the simple backup file for the target file. +/// +/// # Arguments +/// +/// * `source` - A Path reference that holds the source (backup) file path. +/// * `target` - A Path reference that holds the target file path. +/// * `suffix` - Str that holds the backup suffix. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// use uucore::backup_control::source_is_target_backup; +/// let source = Path::new("data.txt~"); +/// let target = Path::new("data.txt"); +/// let suffix = String::from("~"); +/// +/// assert_eq!(source_is_target_backup(&source, &target, &suffix), true); +/// ``` +/// +pub fn source_is_target_backup(source: &Path, target: &Path, suffix: &str) -> bool { + let source_filename = source.to_string_lossy(); + let target_backup_filename = format!("{}{suffix}", target.to_string_lossy()); + source_filename == target_backup_filename +} + // // Tests for this module // @@ -626,4 +652,30 @@ mod tests { let result = determine_backup_suffix(&matches); assert_eq!(result, "-v"); } + #[test] + fn test_source_is_target_backup() { + let source = Path::new("data.txt.bak"); + let target = Path::new("data.txt"); + let suffix = String::from(".bak"); + + assert!(source_is_target_backup(&source, &target, &suffix)); + } + + #[test] + fn test_source_is_not_target_backup() { + let source = Path::new("data.txt"); + let target = Path::new("backup.txt"); + let suffix = String::from(".bak"); + + assert!(!source_is_target_backup(&source, &target, &suffix)); + } + + #[test] + fn test_source_is_target_backup_with_tilde_suffix() { + let source = Path::new("example~"); + let target = Path::new("example"); + let suffix = String::from("~"); + + assert!(source_is_target_backup(&source, &target, &suffix)); + } } From 40c598852b7a3e6f7bca8ac2dbe4e1ffc662c3ca Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 24 Jun 2023 00:06:54 +0200 Subject: [PATCH 47/88] mv: add the check with --b=simple and when the source is a backup --- src/uu/mv/src/mv.rs | 13 ++++++++++++- tests/by-util/test_mv.rs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index 6289e79f9..32214b302 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -22,7 +22,7 @@ use std::os::unix; #[cfg(windows)] use std::os::windows; use std::path::{Path, PathBuf}; -use uucore::backup_control::{self, BackupMode}; +use uucore::backup_control::{self, source_is_target_backup, BackupMode}; use uucore::display::Quotable; use uucore::error::{set_exit_code, FromIo, UError, UResult, USimpleError, UUsageError}; use uucore::fs::{are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file}; @@ -251,6 +251,17 @@ fn parse_paths(files: &[OsString], b: &Behavior) -> Vec { } fn handle_two_paths(source: &Path, target: &Path, b: &Behavior) -> UResult<()> { + if b.backup == BackupMode::SimpleBackup && source_is_target_backup(source, target, &b.suffix) { + return Err(io::Error::new( + io::ErrorKind::NotFound, + format!( + "backing up {} might destroy source; {} not moved", + target.quote(), + source.quote() + ), + ) + .into()); + } if source.symlink_metadata().is_err() { return Err(MvError::NoSuchFile(source.quote().to_string()).into()); } diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index 0c292c50d..ceaa4ba22 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -510,6 +510,22 @@ fn test_mv_same_hardlink_backup_simple() { .succeeds(); } +#[test] +#[cfg(all(unix, not(target_os = "android")))] +fn test_mv_same_hardlink_backup_simple_destroy() { + let (at, mut ucmd) = at_and_ucmd!(); + let file_a = "test_mv_same_file_a~"; + let file_b = "test_mv_same_file_a"; + at.touch(file_a); + at.touch(file_b); + + ucmd.arg(file_a) + .arg(file_b) + .arg("--b=simple") + .fails() + .stderr_contains("backing up 'test_mv_same_file_a' might destroy source"); +} + #[test] fn test_mv_same_file_not_dot_dir() { let (at, mut ucmd) = at_and_ucmd!(); From 14e5f89a0e0426f49e4bd2f8006e94687968a4c2 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 28 Jun 2023 23:04:50 +0200 Subject: [PATCH 48/88] Move memmap2 in the root workpace --- Cargo.toml | 3 ++- src/uu/tac/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4d7619142..ed9971d95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ # coreutils (uutils) # * see the repository LICENSE, README, and CONTRIBUTING files for more information -# spell-checker:ignore (libs) libselinux gethostid procfs bigdecimal kqueue fundu mangen datetime uuhelp +# spell-checker:ignore (libs) libselinux gethostid procfs bigdecimal kqueue fundu mangen datetime uuhelp memmap [package] name = "coreutils" @@ -292,6 +292,7 @@ lscolors = { version = "0.14.0", default-features = false, features = [ "nu-ansi-term", ] } memchr = "2" +memmap2 = "0.7" nix = { version = "0.26", default-features = false } nom = "7.1.3" notify = { version = "=6.0.1", features = ["macos_kqueue"] } diff --git a/src/uu/tac/Cargo.toml b/src/uu/tac/Cargo.toml index 4455ebe13..32682facd 100644 --- a/src/uu/tac/Cargo.toml +++ b/src/uu/tac/Cargo.toml @@ -18,7 +18,7 @@ path = "src/tac.rs" [dependencies] memchr = { workspace = true } -memmap2 = "0.7" +memmap2 = { workspace = true } regex = { workspace = true } clap = { workspace = true } uucore = { workspace = true } From 5a1829e897a8ffdfec411883b45fced6a56afedd Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 29 Jun 2023 10:18:50 +0200 Subject: [PATCH 49/88] Bump proc-macro2 from 1.0.47 to 1.0.63 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6bfc3fbf..fa23c1ace 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1763,9 +1763,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] From a7f95d5a23826ad5bcdd4d2b8fbbb0b622295010 Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Wed, 28 Jun 2023 21:38:13 -0700 Subject: [PATCH 50/88] hashsum: use file_stem() instead of file_name() This program matches the binary name to determine which algorithm to use. On Windows, `file_name()` was matching against a string with `.exe`, causing binaries like `sha256sum.exe` to not properly detect the algorithm. By using `file_stem()`, we exclude the `.exe` from matching, achieving similar and correct behavior on Windows. --- src/uu/hashsum/src/hashsum.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 7b571efcd..cc1b050fd 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -306,7 +306,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { // if there is no program name for some reason, default to "hashsum" let program = args.next().unwrap_or_else(|| OsString::from(NAME)); let binary_name = Path::new(&program) - .file_name() + .file_stem() .unwrap_or_else(|| OsStr::new(NAME)) .to_string_lossy(); From 9bf1fb58387454bc608b605eee4fac253a1b43fb Mon Sep 17 00:00:00 2001 From: Joseph Jon Booker Date: Wed, 28 Jun 2023 23:10:45 -0500 Subject: [PATCH 51/88] util/build-gnu.sh reword error w/o gnu coreutils For a new contributor, the message given by `utils/build-gnu.sh` is fairly confusing - it starts with several lines of noise (showing variables that are set in the script) followed by an error about missing "GNU" and a `git` command string. This commit changes the script to explicitly instruct the user to run the `git clone` command. Since the GNU coreutils repository is probably missing for new developers, this error is shown if the repository is missing without including VARIABLE=value lines that are not actionable yet. --- util/build-gnu.sh | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 2b7e5c0bf..88f4eda98 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -11,28 +11,31 @@ ME="${0}" ME_dir="$(dirname -- "$(readlink -fm -- "${ME}")")" REPO_main_dir="$(dirname -- "${ME_dir}")" -echo "ME='${ME}'" -echo "ME_dir='${ME_dir}'" -echo "REPO_main_dir='${REPO_main_dir}'" - ### * config (from environment with fallback defaults); note: GNU is expected to be a sibling repo directory path_UUTILS=${path_UUTILS:-${REPO_main_dir}} path_GNU="$(readlink -fm -- "${path_GNU:-${path_UUTILS}/../gnu}")" -echo "path_UUTILS='${path_UUTILS}'" -echo "path_GNU='${path_GNU}'" - ### if test ! -d "${path_GNU}"; then - echo "Could not find GNU (expected at '${path_GNU}')" + echo "Could not find GNU coreutils (expected at '${path_GNU}')" + echo "Run the following to download into the expected path:" echo "git clone --recurse-submodules https://github.com/coreutils/coreutils.git \"${path_GNU}\"" exit 1 fi ### +echo "ME='${ME}'" +echo "ME_dir='${ME_dir}'" +echo "REPO_main_dir='${REPO_main_dir}'" + +echo "path_UUTILS='${path_UUTILS}'" +echo "path_GNU='${path_GNU}'" + +### + UU_MAKE_PROFILE=${UU_MAKE_PROFILE:-release} echo "UU_MAKE_PROFILE='${UU_MAKE_PROFILE}'" From 863f91eca9cbcd1847c5af1b42a2e4288e4e07f4 Mon Sep 17 00:00:00 2001 From: crapStone Date: Thu, 29 Jun 2023 15:34:19 +0000 Subject: [PATCH 52/88] fix typos some arguments had the wrong case --- src/uu/dd/dd.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/dd/dd.md b/src/uu/dd/dd.md index b60fc14fa..504910884 100644 --- a/src/uu/dd/dd.md +++ b/src/uu/dd/dd.md @@ -13,7 +13,7 @@ Copy, and optionally convert, a file system resource ### Operands -- `Bs=BYTES` : read and write up to BYTES bytes at a time (default: 512); +- `bs=BYTES` : read and write up to BYTES bytes at a time (default: 512); overwrites `ibs` and `obs`. - `cbs=BYTES` : the 'conversion block size' in bytes. Applies to the `conv=block`, and `conv=unblock` operations. @@ -114,7 +114,7 @@ Copy, and optionally convert, a file system resource ### General Flags -- `Direct` : use direct I/O for data. +- `direct` : use direct I/O for data. - `directory` : fail unless the given input (if used as an iflag) or output (if used as an oflag) is a directory. - `dsync` : use synchronized I/O for data. From 4cdff3ba89ad4247ccd8e66bb307962a0155f0ae Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 30 Jun 2023 10:31:47 +0200 Subject: [PATCH 53/88] docs: add "ls --long" to extensions --- docs/src/extensions.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/extensions.md b/docs/src/extensions.md index 428ae84ca..ae3d974fe 100644 --- a/docs/src/extensions.md +++ b/docs/src/extensions.md @@ -69,3 +69,8 @@ number of spaces representing a tab when determining the line length. ## `seq` `seq` provides `-t`/`--terminator` to set the terminator character. + +## `ls` + +GNU `ls` provides two ways to use a long listing format: `-l` and `--format=long`. We support a +third way: `--long`. From 42bf580f132cd4951b31837f02d2d2a4849e8ecc Mon Sep 17 00:00:00 2001 From: sbentmar Date: Sat, 1 Jul 2023 17:08:12 +0200 Subject: [PATCH 54/88] numfmt: add --invalid option (#4249) * numfmt: add invalid option * numfmt: return code 0 if ignore or warn * numfmt: implement all --invalid modes * numfmt: validate stdout and stderr * numfmt: remove unnecessary code * numfmt: apply formatting * numfmt: fix clippy issues * numfmt: fix failing test cases * numfmt: fix formatting * numfmt: fix bug when handling broken pipe * numfmt: fix bug where extra newline was added * numfmt: add test cases for edge cases * numfmt: simplify error handling * numfmt: remove redundant if * numfmt: add newline between functions * numfmt: fix failing test cases * numfmt: add support for arg numbers using --invalid * numfmt: simplify error handling in value handlers * numfmt: fix merge conflict and align prints * numfmt: fix clippy suggestion * numfmt: replace "valid" with "invalid" in tests * numfmt: move INVALID to respect alph. order * numfmt: move printlns outside of match to avoid duplication Co-authored-by: Sylvestre Ledru * numfmt: remove empty line --------- Co-authored-by: Daniel Hofstetter Co-authored-by: Sylvestre Ledru --- src/uu/numfmt/src/numfmt.rs | 146 ++++++++++++++++++++++++++++++----- src/uu/numfmt/src/options.rs | 41 ++++++++++ tests/by-util/test_numfmt.rs | 75 +++++++++++++++++- 3 files changed, 241 insertions(+), 21 deletions(-) diff --git a/src/uu/numfmt/src/numfmt.rs b/src/uu/numfmt/src/numfmt.rs index f1fd4b115..112d68746 100644 --- a/src/uu/numfmt/src/numfmt.rs +++ b/src/uu/numfmt/src/numfmt.rs @@ -11,11 +11,13 @@ use crate::options::*; use crate::units::{Result, Unit}; use clap::{crate_version, parser::ValueSource, Arg, ArgAction, ArgMatches, Command}; use std::io::{BufRead, Write}; +use std::str::FromStr; + use units::{IEC_BASES, SI_BASES}; use uucore::display::Quotable; -use uucore::error::UResult; +use uucore::error::{UError, UResult}; use uucore::ranges::Range; -use uucore::{format_usage, help_about, help_section, help_usage}; +use uucore::{format_usage, help_about, help_section, help_usage, show, show_error}; pub mod errors; pub mod format; @@ -28,12 +30,8 @@ const USAGE: &str = help_usage!("numfmt.md"); fn handle_args<'a>(args: impl Iterator, options: &NumfmtOptions) -> UResult<()> { for l in args { - match format_and_print(l, options) { - Ok(_) => Ok(()), - Err(e) => Err(NumfmtError::FormattingError(e.to_string())), - }?; + format_and_handle_validation(l, options)?; } - Ok(()) } @@ -41,23 +39,41 @@ fn handle_buffer(input: R, options: &NumfmtOptions) -> UResult<()> where R: BufRead, { - let mut lines = input.lines(); - for (idx, line) in lines.by_ref().enumerate() { - match line { - Ok(l) if idx < options.header => { - println!("{l}"); + for (idx, line_result) in input.lines().by_ref().enumerate() { + match line_result { + Ok(line) if idx < options.header => { + println!("{line}"); Ok(()) } - Ok(l) => match format_and_print(&l, options) { - Ok(_) => Ok(()), - Err(e) => Err(NumfmtError::FormattingError(e.to_string())), - }, - Err(e) => Err(NumfmtError::IoError(e.to_string())), + Ok(line) => format_and_handle_validation(line.as_ref(), options), + Err(err) => return Err(Box::new(NumfmtError::IoError(err.to_string()))), }?; } Ok(()) } +fn format_and_handle_validation(input_line: &str, options: &NumfmtOptions) -> UResult<()> { + let handled_line = format_and_print(input_line, options); + + if let Err(error_message) = handled_line { + match options.invalid { + InvalidModes::Abort => { + return Err(Box::new(NumfmtError::FormattingError(error_message))); + } + InvalidModes::Fail => { + show!(NumfmtError::FormattingError(error_message)); + } + InvalidModes::Warn => { + show_error!("{}", error_message); + } + InvalidModes::Ignore => {} + }; + println!("{}", input_line); + } + + Ok(()) +} + fn parse_unit(s: &str) -> Result { match s { "auto" => Ok(Unit::Auto), @@ -201,6 +217,9 @@ fn parse_options(args: &ArgMatches) -> Result { .get_one::(options::SUFFIX) .map(|s| s.to_owned()); + let invalid = + InvalidModes::from_str(args.get_one::(options::INVALID).unwrap()).unwrap(); + Ok(NumfmtOptions { transform, padding, @@ -210,6 +229,7 @@ fn parse_options(args: &ArgMatches) -> Result { round, suffix, format, + invalid, }) } @@ -357,6 +377,17 @@ pub fn uu_app() -> Command { ) .value_name("SUFFIX"), ) + .arg( + Arg::new(options::INVALID) + .long(options::INVALID) + .help( + "set the failure mode for invalid input; \ + valid options are abort, fail, warn or ignore", + ) + .default_value("abort") + .value_parser(["abort", "fail", "warn", "ignore"]) + .value_name("INVALID"), + ) .arg( Arg::new(options::NUMBER) .hide(true) @@ -366,9 +397,11 @@ pub fn uu_app() -> Command { #[cfg(test)] mod tests { + use uucore::error::get_exit_code; + use super::{ - handle_buffer, parse_unit_size, parse_unit_size_suffix, FormatOptions, NumfmtOptions, - Range, RoundMethod, TransformOptions, Unit, + handle_args, handle_buffer, parse_unit_size, parse_unit_size_suffix, FormatOptions, + InvalidModes, NumfmtOptions, Range, RoundMethod, TransformOptions, Unit, }; use std::io::{BufReader, Error, ErrorKind, Read}; struct MockBuffer {} @@ -394,6 +427,7 @@ mod tests { round: RoundMethod::Nearest, suffix: None, format: FormatOptions::default(), + invalid: InvalidModes::Abort, } } @@ -409,6 +443,20 @@ mod tests { assert_eq!(result.code(), 1); } + #[test] + fn broken_buffer_returns_io_error_after_header() { + let mock_buffer = MockBuffer {}; + let mut options = get_valid_options(); + options.header = 0; + let result = handle_buffer(BufReader::new(mock_buffer), &options) + .expect_err("returned Ok after receiving IO error"); + let result_debug = format!("{:?}", result); + let result_display = format!("{}", result); + assert_eq!(result_debug, "IoError(\"broken pipe\")"); + assert_eq!(result_display, "broken pipe"); + assert_eq!(result.code(), 1); + } + #[test] fn non_numeric_returns_formatting_error() { let input_value = b"135\nhello"; @@ -431,6 +479,66 @@ mod tests { assert!(result.is_ok(), "did not return Ok for valid input"); } + #[test] + fn warn_returns_ok_for_invalid_input() { + let input_value = b"5\n4Q\n"; + let mut options = get_valid_options(); + options.invalid = InvalidModes::Warn; + let result = handle_buffer(BufReader::new(&input_value[..]), &options); + assert!(result.is_ok(), "did not return Ok for invalid input"); + } + + #[test] + fn ignore_returns_ok_for_invalid_input() { + let input_value = b"5\n4Q\n"; + let mut options = get_valid_options(); + options.invalid = InvalidModes::Ignore; + let result = handle_buffer(BufReader::new(&input_value[..]), &options); + assert!(result.is_ok(), "did not return Ok for invalid input"); + } + + #[test] + fn buffer_fail_returns_status_2_for_invalid_input() { + let input_value = b"5\n4Q\n"; + let mut options = get_valid_options(); + options.invalid = InvalidModes::Fail; + handle_buffer(BufReader::new(&input_value[..]), &options).unwrap(); + assert!( + get_exit_code() == 2, + "should set exit code 2 for formatting errors" + ); + } + + #[test] + fn abort_returns_status_2_for_invalid_input() { + let input_value = b"5\n4Q\n"; + let mut options = get_valid_options(); + options.invalid = InvalidModes::Abort; + let result = handle_buffer(BufReader::new(&input_value[..]), &options); + assert!(result.is_err(), "did not return err for invalid input"); + } + + #[test] + fn args_fail_returns_status_2_for_invalid_input() { + let input_value = ["5", "4Q"].into_iter(); + let mut options = get_valid_options(); + options.invalid = InvalidModes::Fail; + handle_args(input_value, &options).unwrap(); + assert!( + get_exit_code() == 2, + "should set exit code 2 for formatting errors" + ); + } + + #[test] + fn args_warn_returns_status_0_for_invalid_input() { + let input_value = ["5", "4Q"].into_iter(); + let mut options = get_valid_options(); + options.invalid = InvalidModes::Warn; + let result = handle_args(input_value, &options); + assert!(result.is_ok(), "did not return ok for invalid input"); + } + #[test] fn test_parse_unit_size() { assert_eq!(1, parse_unit_size("1").unwrap()); diff --git a/src/uu/numfmt/src/options.rs b/src/uu/numfmt/src/options.rs index b70cf87e4..bef4a8ce3 100644 --- a/src/uu/numfmt/src/options.rs +++ b/src/uu/numfmt/src/options.rs @@ -13,6 +13,7 @@ pub const FROM_UNIT: &str = "from-unit"; pub const FROM_UNIT_DEFAULT: &str = "1"; pub const HEADER: &str = "header"; pub const HEADER_DEFAULT: &str = "1"; +pub const INVALID: &str = "invalid"; pub const NUMBER: &str = "NUMBER"; pub const PADDING: &str = "padding"; pub const ROUND: &str = "round"; @@ -29,6 +30,14 @@ pub struct TransformOptions { pub to_unit: usize, } +#[derive(Debug, PartialEq, Eq)] +pub enum InvalidModes { + Abort, + Fail, + Warn, + Ignore, +} + pub struct NumfmtOptions { pub transform: TransformOptions, pub padding: isize, @@ -38,6 +47,7 @@ pub struct NumfmtOptions { pub round: RoundMethod, pub suffix: Option, pub format: FormatOptions, + pub invalid: InvalidModes, } #[derive(Clone, Copy)] @@ -227,6 +237,20 @@ impl FromStr for FormatOptions { } } +impl FromStr for InvalidModes { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "abort" => Ok(Self::Abort), + "fail" => Ok(Self::Fail), + "warn" => Ok(Self::Warn), + "ignore" => Ok(Self::Ignore), + unknown => Err(format!("Unknown invalid mode: {unknown}")), + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -336,4 +360,21 @@ mod tests { assert_eq!(expected_options, "%0'0'0'f".parse().unwrap()); assert_eq!(expected_options, "%'0'0'0f".parse().unwrap()); } + + #[test] + fn test_set_invalid_mode() { + assert_eq!(Ok(InvalidModes::Abort), InvalidModes::from_str("abort")); + assert_eq!(Ok(InvalidModes::Abort), InvalidModes::from_str("ABORT")); + + assert_eq!(Ok(InvalidModes::Fail), InvalidModes::from_str("fail")); + assert_eq!(Ok(InvalidModes::Fail), InvalidModes::from_str("FAIL")); + + assert_eq!(Ok(InvalidModes::Ignore), InvalidModes::from_str("ignore")); + assert_eq!(Ok(InvalidModes::Ignore), InvalidModes::from_str("IGNORE")); + + assert_eq!(Ok(InvalidModes::Warn), InvalidModes::from_str("warn")); + assert_eq!(Ok(InvalidModes::Warn), InvalidModes::from_str("WARN")); + + assert!(InvalidModes::from_str("something unknown").is_err()); + } } diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index fbfe68427..561752db3 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -666,8 +666,79 @@ fn test_invalid_stdin_number_in_middle_of_input() { } #[test] -fn test_invalid_argument_number_returns_status_2() { - new_ucmd!().args(&["hello"]).fails().code_is(2); +fn test_invalid_stdin_number_with_warn_returns_status_0() { + new_ucmd!() + .args(&["--invalid=warn"]) + .pipe_in("4Q") + .succeeds() + .stdout_is("4Q\n") + .stderr_is("numfmt: invalid suffix in input: '4Q'\n"); +} + +#[test] +fn test_invalid_stdin_number_with_ignore_returns_status_0() { + new_ucmd!() + .args(&["--invalid=ignore"]) + .pipe_in("4Q") + .succeeds() + .stdout_only("4Q\n"); +} + +#[test] +fn test_invalid_stdin_number_with_abort_returns_status_2() { + new_ucmd!() + .args(&["--invalid=abort"]) + .pipe_in("4Q") + .fails() + .code_is(2) + .stderr_only("numfmt: invalid suffix in input: '4Q'\n"); +} + +#[test] +fn test_invalid_stdin_number_with_fail_returns_status_2() { + new_ucmd!() + .args(&["--invalid=fail"]) + .pipe_in("4Q") + .fails() + .code_is(2) + .stdout_is("4Q\n") + .stderr_is("numfmt: invalid suffix in input: '4Q'\n"); +} + +#[test] +fn test_invalid_arg_number_with_warn_returns_status_0() { + new_ucmd!() + .args(&["--invalid=warn", "4Q"]) + .succeeds() + .stdout_is("4Q\n") + .stderr_is("numfmt: invalid suffix in input: '4Q'\n"); +} + +#[test] +fn test_invalid_arg_number_with_ignore_returns_status_0() { + new_ucmd!() + .args(&["--invalid=ignore", "4Q"]) + .succeeds() + .stdout_only("4Q\n"); +} + +#[test] +fn test_invalid_arg_number_with_abort_returns_status_2() { + new_ucmd!() + .args(&["--invalid=abort", "4Q"]) + .fails() + .code_is(2) + .stderr_only("numfmt: invalid suffix in input: '4Q'\n"); +} + +#[test] +fn test_invalid_arg_number_with_fail_returns_status_2() { + new_ucmd!() + .args(&["--invalid=fail", "4Q"]) + .fails() + .code_is(2) + .stdout_is("4Q\n") + .stderr_is("numfmt: invalid suffix in input: '4Q'\n"); } #[test] From ba509a1489b5ae6f9ec1505083327eaf0db5b541 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Mon, 3 Jul 2023 09:24:37 +0200 Subject: [PATCH 55/88] cp: use mkdir_all() instead of mkdir() in test --- tests/by-util/test_cp.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 3074513de..2bfd8231c 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -2345,12 +2345,8 @@ fn test_dir_recursive_copy() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - at.mkdir("parent1"); - at.mkdir("parent2"); - at.mkdir("parent1/child"); - at.mkdir("parent2/child1"); - at.mkdir("parent2/child1/child2"); - at.mkdir("parent2/child1/child2/child3"); + at.mkdir_all("parent1/child"); + at.mkdir_all("parent2/child1/child2/child3"); // case-1: copy parent1 -> parent1: should fail scene From 5a667db43daee79fd67c329f0dd808d6bbbf8357 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Mon, 3 Jul 2023 13:20:48 +0200 Subject: [PATCH 56/88] tail: clean up some small things in input parsing --- src/uu/tail/src/args.rs | 5 +++-- src/uu/tail/src/paths.rs | 9 ++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/uu/tail/src/args.rs b/src/uu/tail/src/args.rs index eff332230..487e366e6 100644 --- a/src/uu/tail/src/args.rs +++ b/src/uu/tail/src/args.rs @@ -7,7 +7,7 @@ use crate::paths::Input; use crate::{parse, platform, Quotable}; -use clap::crate_version; +use clap::{crate_version, value_parser}; use clap::{Arg, ArgAction, ArgMatches, Command}; use fundu::DurationParser; use is_terminal::IsTerminal; @@ -283,7 +283,7 @@ impl Settings { } settings.inputs = matches - .get_raw(options::ARG_FILES) + .get_many::(options::ARG_FILES) .map(|v| v.map(Input::from).collect()) .unwrap_or_else(|| vec![Input::default()]); @@ -584,6 +584,7 @@ pub fn uu_app() -> Command { Arg::new(options::ARG_FILES) .action(ArgAction::Append) .num_args(1..) + .value_parser(value_parser!(OsString)) .value_hint(clap::ValueHint::FilePath), ) } diff --git a/src/uu/tail/src/paths.rs b/src/uu/tail/src/paths.rs index cce3270a8..5ed654037 100644 --- a/src/uu/tail/src/paths.rs +++ b/src/uu/tail/src/paths.rs @@ -10,10 +10,7 @@ use std::ffi::OsStr; use std::fs::{File, Metadata}; use std::io::{Seek, SeekFrom}; #[cfg(unix)] -use std::os::unix::{ - fs::{FileTypeExt, MetadataExt}, - prelude::OsStrExt, -}; +use std::os::unix::fs::{FileTypeExt, MetadataExt}; use std::path::{Path, PathBuf}; use uucore::error::UResult; @@ -26,9 +23,7 @@ pub enum InputKind { #[cfg(unix)] impl From<&OsStr> for InputKind { fn from(value: &OsStr) -> Self { - const DASH: [u8; 1] = [b'-']; - - if value.as_bytes() == DASH { + if value == OsStr::new("-") { Self::Stdin } else { Self::File(PathBuf::from(value)) From 9aef5ac35b974e1f081fd4d5d0e29a4e41fd58c5 Mon Sep 17 00:00:00 2001 From: Roy Ivy III Date: Sun, 11 Jun 2023 10:35:32 -0500 Subject: [PATCH 57/88] deps ~ change from 'humantime_to_duration' to 'parse_datetime' --- Cargo.toml | 2 +- src/uu/touch/Cargo.toml | 5 ++--- src/uu/touch/src/touch.rs | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed9971d95..2828c00df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ # coreutils (uutils) # * see the repository LICENSE, README, and CONTRIBUTING files for more information -# spell-checker:ignore (libs) libselinux gethostid procfs bigdecimal kqueue fundu mangen datetime uuhelp memmap +# spell-checker:ignore (libs) bigdecimal datetime fundu gethostid kqueue libselinux mangen memmap procfs uuhelp [package] name = "coreutils" diff --git a/src/uu/touch/Cargo.toml b/src/uu/touch/Cargo.toml index f90725197..4e27027a2 100644 --- a/src/uu/touch/Cargo.toml +++ b/src/uu/touch/Cargo.toml @@ -1,4 +1,4 @@ -# spell-checker:ignore humantime +# spell-checker:ignore datetime [package] name = "uu_touch" version = "0.0.19" @@ -18,8 +18,7 @@ path = "src/touch.rs" [dependencies] filetime = { workspace = true } clap = { workspace = true } -# TODO: use workspace dependency (0.3) when switching from time to chrono -humantime_to_duration = "0.2.1" +parse_datetime = { workspace = true } time = { workspace = true, features = [ "parsing", "formatting", diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index 4efea56c4..d3d4a08c5 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -84,7 +84,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { ) { (Some(reference), Some(date)) => { let (atime, mtime) = stat(Path::new(reference), !matches.get_flag(options::NO_DEREF))?; - if let Ok(offset) = humantime_to_duration::from_str(date) { + if let Ok(offset) = parse_datetime::from_str(date) { let mut seconds = offset.whole_seconds(); let mut nanos = offset.subsec_nanoseconds(); if nanos < 0 { @@ -445,7 +445,7 @@ fn parse_date(s: &str) -> UResult { } } - if let Ok(duration) = humantime_to_duration::from_str(s) { + if let Ok(duration) = parse_datetime::from_str(s) { let now_local = time::OffsetDateTime::now_local().unwrap(); let diff = now_local.checked_add(duration).unwrap(); return Ok(local_dt_to_filetime(diff)); From af64bde92b5f29cc1cb6519e29aae821b6afcf23 Mon Sep 17 00:00:00 2001 From: Roy Ivy III Date: Sun, 11 Jun 2023 19:45:06 -0500 Subject: [PATCH 58/88] fix/touch ~ time crate usage errors --- src/uu/touch/src/touch.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index d3d4a08c5..f4784f155 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -85,12 +85,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { (Some(reference), Some(date)) => { let (atime, mtime) = stat(Path::new(reference), !matches.get_flag(options::NO_DEREF))?; if let Ok(offset) = parse_datetime::from_str(date) { - let mut seconds = offset.whole_seconds(); - let mut nanos = offset.subsec_nanoseconds(); - if nanos < 0 { - nanos += 1_000_000_000; - seconds -= 1; - } + let seconds = offset.num_seconds(); + let nanos = offset.num_nanoseconds().unwrap_or(0) % 1_000_000_000; let ref_atime_secs = atime.unix_seconds(); let ref_atime_nanos = atime.nanoseconds(); @@ -447,7 +443,11 @@ fn parse_date(s: &str) -> UResult { if let Ok(duration) = parse_datetime::from_str(s) { let now_local = time::OffsetDateTime::now_local().unwrap(); - let diff = now_local.checked_add(duration).unwrap(); + let diff = now_local + .checked_add(time::Duration::nanoseconds( + duration.num_nanoseconds().unwrap(), + )) + .unwrap(); return Ok(local_dt_to_filetime(diff)); } From e491bbdbed1e0ad45a97ec423780713557c4bb6d Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 3 Jul 2023 08:51:23 +0200 Subject: [PATCH 59/88] cp: allow multiple usages of -R/-r Closes: #5027 works for all other rm args --- src/uu/cp/src/cp.rs | 1 + tests/by-util/test_cp.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 60ef54095..de9dd1c91 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -383,6 +383,7 @@ pub fn uu_app() -> Command { backup_control::BACKUP_CONTROL_LONG_HELP )) .infer_long_args(true) + .args_override_self(true) .arg( Arg::new(options::TARGET_DIRECTORY) .short('t') diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 3074513de..4e6993679 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -158,6 +158,20 @@ fn test_cp_recurse() { assert_eq!(at.read(TEST_COPY_TO_FOLDER_NEW_FILE), "Hello, World!\n"); } +#[test] +#[cfg(not(target_os = "macos"))] +fn test_cp_recurse_several() { + let (at, mut ucmd) = at_and_ucmd!(); + ucmd.arg("-r") + .arg("-r") + .arg(TEST_COPY_FROM_FOLDER) + .arg(TEST_COPY_TO_FOLDER_NEW) + .succeeds(); + + // Check the content of the destination file that was copied. + assert_eq!(at.read(TEST_COPY_TO_FOLDER_NEW_FILE), "Hello, World!\n"); +} + #[test] fn test_cp_with_dirs_t() { let (at, mut ucmd) = at_and_ucmd!(); From e6ec1490aac2c7df5eed59791126e61c97070549 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Mon, 3 Jul 2023 14:28:39 +0200 Subject: [PATCH 60/88] touch: use parse_datetime in Cargo.lock --- Cargo.lock | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa23c1ace..77afc4470 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1172,16 +1172,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "humantime_to_duration" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714764645f21cc70c4c151d7798dd158409641f37ad820bed65224aae403cbed" -dependencies = [ - "regex", - "time", -] - [[package]] name = "iana-time-zone" version = "0.1.53" @@ -3237,7 +3227,7 @@ version = "0.0.19" dependencies = [ "clap", "filetime", - "humantime_to_duration", + "parse_datetime", "time", "uucore", "windows-sys 0.48.0", From d033db35739d8bf2170aeab6128f8d8374b0919b Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 3 Jul 2023 22:56:32 +0200 Subject: [PATCH 61/88] split: reject some invalid values Matches what is done in tests/split/fail.sh (still doesn't work) --- src/uu/split/src/split.rs | 39 +++++++++++++++++++++++++------------ tests/by-util/test_split.rs | 33 +++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/uu/split/src/split.rs b/src/uu/split/src/split.rs index 6e29e6f4b..8f6821de1 100644 --- a/src/uu/split/src/split.rs +++ b/src/uu/split/src/split.rs @@ -267,7 +267,11 @@ impl NumberType { let num_chunks = n_str .parse() .map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?; - Ok(Self::Bytes(num_chunks)) + if num_chunks > 0 { + Ok(Self::Bytes(num_chunks)) + } else { + Err(NumberTypeError::NumberOfChunks(s.to_string())) + } } ["l", n_str] => { let num_chunks = n_str @@ -357,6 +361,20 @@ impl fmt::Display for StrategyError { impl Strategy { /// Parse a strategy from the command-line arguments. fn from(matches: &ArgMatches) -> Result { + fn get_and_parse( + matches: &ArgMatches, + option: &str, + strategy: fn(u64) -> Strategy, + error: fn(ParseSizeError) -> StrategyError, + ) -> Result { + let s = matches.get_one::(option).unwrap(); + let n = parse_size(&s).map_err(error)?; + if n > 0 { + Ok(strategy(n)) + } else { + Err(error(ParseSizeError::ParseFailure(s.to_string()))) + } + } // Check that the user is not specifying more than one strategy. // // Note: right now, this exact behavior cannot be handled by @@ -370,20 +388,17 @@ impl Strategy { ) { (false, false, false, false) => Ok(Self::Lines(1000)), (true, false, false, false) => { - let s = matches.get_one::(OPT_LINES).unwrap(); - let n = parse_size(s).map_err(StrategyError::Lines)?; - Ok(Self::Lines(n)) + get_and_parse(matches, OPT_LINES, Self::Lines, StrategyError::Lines) } (false, true, false, false) => { - let s = matches.get_one::(OPT_BYTES).unwrap(); - let n = parse_size(s).map_err(StrategyError::Bytes)?; - Ok(Self::Bytes(n)) - } - (false, false, true, false) => { - let s = matches.get_one::(OPT_LINE_BYTES).unwrap(); - let n = parse_size(s).map_err(StrategyError::Bytes)?; - Ok(Self::LineBytes(n)) + get_and_parse(matches, OPT_BYTES, Self::Bytes, StrategyError::Bytes) } + (false, false, true, false) => get_and_parse( + matches, + OPT_LINE_BYTES, + Self::LineBytes, + StrategyError::Bytes, + ), (false, false, false, true) => { let s = matches.get_one::(OPT_NUMBER).unwrap(); let number_type = NumberType::from(s).map_err(StrategyError::NumberType)?; diff --git a/tests/by-util/test_split.rs b/tests/by-util/test_split.rs index 1395a4fa2..35e5ebb05 100644 --- a/tests/by-util/test_split.rs +++ b/tests/by-util/test_split.rs @@ -758,3 +758,36 @@ fn test_round_robin() { assert_eq!(file_read("xaa"), "1\n3\n5\n"); assert_eq!(file_read("xab"), "2\n4\n"); } + +#[test] +fn test_split_invalid_input() { + // Test if stdout/stderr for '--lines' option is correct + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("file"); + + scene + .ucmd() + .args(&["--lines", "0", "file"]) + .fails() + .no_stdout() + .stderr_contains("split: invalid number of lines: 0"); + scene + .ucmd() + .args(&["-C", "0", "file"]) + .fails() + .no_stdout() + .stderr_contains("split: invalid number of bytes: 0"); + scene + .ucmd() + .args(&["-b", "0", "file"]) + .fails() + .no_stdout() + .stderr_contains("split: invalid number of bytes: 0"); + scene + .ucmd() + .args(&["-n", "0", "file"]) + .fails() + .no_stdout() + .stderr_contains("split: invalid number of chunks: 0"); +} From 18e5c5b5f7f2dddc8b20419d863c2c8786b441f4 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 4 Jul 2023 07:02:18 +0200 Subject: [PATCH 62/88] numfmt: remove duplicate info from help output --- src/uu/numfmt/src/numfmt.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/uu/numfmt/src/numfmt.rs b/src/uu/numfmt/src/numfmt.rs index 112d68746..b0a5670d4 100644 --- a/src/uu/numfmt/src/numfmt.rs +++ b/src/uu/numfmt/src/numfmt.rs @@ -360,10 +360,7 @@ pub fn uu_app() -> Command { .arg( Arg::new(options::ROUND) .long(options::ROUND) - .help( - "use METHOD for rounding when scaling; METHOD can be: up,\ - down, from-zero, towards-zero, nearest", - ) + .help("use METHOD for rounding when scaling") .value_name("METHOD") .default_value("from-zero") .value_parser(["up", "down", "from-zero", "towards-zero", "nearest"]), @@ -380,10 +377,7 @@ pub fn uu_app() -> Command { .arg( Arg::new(options::INVALID) .long(options::INVALID) - .help( - "set the failure mode for invalid input; \ - valid options are abort, fail, warn or ignore", - ) + .help("set the failure mode for invalid input") .default_value("abort") .value_parser(["abort", "fail", "warn", "ignore"]) .value_name("INVALID"), From 8e2401c8ee13b3f16d5903d3a8aa8c4eeaafa912 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 07:39:59 +0000 Subject: [PATCH 63/88] chore(deps): update rust crate rlimit to 0.10.0 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77afc4470..8390e592e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1909,9 +1909,9 @@ checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rlimit" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a29d87a652dc4d43c586328706bb5cdff211f3f39a530f240b53f7221dab8e" +checksum = "9b5b8be0bc0ef630d24f8fa836b3a3463479b2343b29f9a8fa905c71a8c7b69b" dependencies = [ "libc", ] diff --git a/Cargo.toml b/Cargo.toml index 2828c00df..daa44eb6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -496,7 +496,7 @@ rstest = "0.17.0" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies] procfs = { version = "0.15", default-features = false } -rlimit = "0.9.1" +rlimit = "0.10.0" [target.'cfg(unix)'.dev-dependencies] nix = { workspace = true, features = ["process", "signal", "user"] } From fee5225cb6be6b03d6b9f854fcc55a91f8c95441 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 4 Jul 2023 10:37:10 +0200 Subject: [PATCH 64/88] nl: make --no-renumber a flag --- src/uu/nl/src/helper.rs | 2 +- src/uu/nl/src/nl.rs | 3 ++- tests/by-util/test_nl.rs | 7 +++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/uu/nl/src/helper.rs b/src/uu/nl/src/helper.rs index a62936d75..dc2e9dfd8 100644 --- a/src/uu/nl/src/helper.rs +++ b/src/uu/nl/src/helper.rs @@ -29,7 +29,7 @@ fn parse_style(chars: &[char]) -> Result { pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) -> Vec { // This vector holds error messages encountered. let mut errs: Vec = vec![]; - settings.renumber = !opts.contains_id(options::NO_RENUMBER); + settings.renumber = opts.get_flag(options::NO_RENUMBER); match opts.get_one::(options::NUMBER_SEPARATOR) { None => {} Some(val) => { diff --git a/src/uu/nl/src/nl.rs b/src/uu/nl/src/nl.rs index 7e18d7588..2e9bf92a0 100644 --- a/src/uu/nl/src/nl.rs +++ b/src/uu/nl/src/nl.rs @@ -213,7 +213,8 @@ pub fn uu_app() -> Command { Arg::new(options::NO_RENUMBER) .short('p') .long(options::NO_RENUMBER) - .help("do not reset line numbers at logical pages"), + .help("do not reset line numbers at logical pages") + .action(ArgAction::SetFalse), ) .arg( Arg::new(options::NUMBER_SEPARATOR) diff --git a/tests/by-util/test_nl.rs b/tests/by-util/test_nl.rs index 7317d8cca..39c076d43 100644 --- a/tests/by-util/test_nl.rs +++ b/tests/by-util/test_nl.rs @@ -71,3 +71,10 @@ fn test_sections_and_styles() { } // spell-checker:enable } + +#[test] +fn test_no_renumber() { + for arg in ["-p", "--no-renumber"] { + new_ucmd!().arg(arg).succeeds(); + } +} From 66afeef84adf47066f00c76e6516e46b982f74cf Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 4 Jul 2023 16:40:58 +0200 Subject: [PATCH 65/88] Bump hermit-abi and num_cpus hermit-abi from 0.3.1 -> 0.3.2 num_cpus from 1.14.0 -> 1.16.0 --- Cargo.lock | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8390e592e..8b4104e93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1136,18 +1136,9 @@ checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -1243,7 +1234,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys 0.48.0", ] @@ -1254,7 +1245,7 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "io-lifetimes", "rustix 0.37.19", "windows-sys 0.48.0", @@ -1537,11 +1528,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", ] From 9ac31e057df99c181e6609c966ce2de0b79bec5b Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 4 Jul 2023 16:42:25 +0200 Subject: [PATCH 66/88] deny.toml: remove hermit-abi from skip list --- deny.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/deny.toml b/deny.toml index 780de3c8c..c52b321dd 100644 --- a/deny.toml +++ b/deny.toml @@ -59,8 +59,6 @@ highlight = "all" # introduces it. # spell-checker: disable skip = [ - # is-terminal - { name = "hermit-abi", version = "0.3.1" }, # procfs { name = "rustix", version = "0.36.14" }, # rustix From 264d29a1695f95228d90f794d78d3e6a0631cb18 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 4 Jul 2023 18:45:11 +0200 Subject: [PATCH 67/88] fix the clippy warning --- src/uu/split/src/split.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/split/src/split.rs b/src/uu/split/src/split.rs index 8f6821de1..f1be0c47d 100644 --- a/src/uu/split/src/split.rs +++ b/src/uu/split/src/split.rs @@ -368,7 +368,7 @@ impl Strategy { error: fn(ParseSizeError) -> StrategyError, ) -> Result { let s = matches.get_one::(option).unwrap(); - let n = parse_size(&s).map_err(error)?; + let n = parse_size(s).map_err(error)?; if n > 0 { Ok(strategy(n)) } else { From e9405250f49a5a649c860e0d62039ad28310cf53 Mon Sep 17 00:00:00 2001 From: John Shin Date: Mon, 26 Jun 2023 16:27:09 -0700 Subject: [PATCH 68/88] uucore: leading zeros are ignored in version compare --- src/uucore/src/lib/mods/version_cmp.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/uucore/src/lib/mods/version_cmp.rs b/src/uucore/src/lib/mods/version_cmp.rs index 99b8c8b40..2bbaffd25 100644 --- a/src/uucore/src/lib/mods/version_cmp.rs +++ b/src/uucore/src/lib/mods/version_cmp.rs @@ -141,8 +141,7 @@ pub fn version_cmp(mut a: &str, mut b: &str) -> Ordering { b = &b[b_numerical_end..]; if a.is_empty() && b.is_empty() { - // Default to the lexical comparison. - return str_cmp; + return std::cmp::Ordering::Equal; } } } @@ -229,14 +228,14 @@ mod tests { // Leading zeroes assert_eq!( version_cmp("012", "12"), - Ordering::Less, - "A single leading zero can make a difference" + Ordering::Equal, + "A single leading zero does not make a difference" ); assert_eq!( version_cmp("000800", "0000800"), - Ordering::Greater, - "Leading number of zeroes is used even if both non-zero number of zeros" + Ordering::Equal, + "Multiple leading zeros do not make a difference" ); // Numbers and other characters combined @@ -280,14 +279,8 @@ mod tests { assert_eq!( version_cmp("aa10aa0022", "aa010aa022"), - Ordering::Greater, - "The leading zeroes of the first number has priority." - ); - - assert_eq!( - version_cmp("aa10aa0022", "aa10aa022"), - Ordering::Less, - "The leading zeroes of other numbers than the first are used." + Ordering::Equal, + "Test multiple numeric values with leading zeros" ); assert_eq!( @@ -307,7 +300,7 @@ mod tests { assert_eq!( version_cmp("aa2000000000000000000000bb", "aa002000000000000000000000bb"), - Ordering::Greater, + Ordering::Equal, "Leading zeroes for numbers larger than u64::MAX are \ handled correctly without crashing" ); From b42a5b87412e91a4e3a42fb01bbe9326c0d9e2ed Mon Sep 17 00:00:00 2001 From: John Shin Date: Mon, 26 Jun 2023 16:45:57 -0700 Subject: [PATCH 69/88] ls: update test result for version compare --- tests/by-util/test_ls.rs | 49 ++++------------------------------------ 1 file changed, 4 insertions(+), 45 deletions(-) diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index ad2c6424f..f376cf53d 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -2312,56 +2312,15 @@ fn test_ls_version_sort() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; for filename in [ - "a2", - "b1", - "b20", - "a1.4", - "a1.40", - "b3", - "b11", - "b20b", - "b20a", - "a100", - "a1.13", - "aa", - "a1", - "aaa", - "a1.00000040", - "abab", - "ab", - "a01.40", - "a001.001", - "a01.0000001", - "a01.001", - "a001.01", + "a2", "b1", "b20", "a1.4", "b3", "b11", "b20b", "b20a", "a100", "a1.13", "aa", "a1", "aaa", + "abab", "ab", "a01.40", "a001.001", ] { at.touch(filename); } let mut expected = vec![ - "a1", - "a001.001", - "a001.01", - "a01.0000001", - "a01.001", - "a1.4", - "a1.13", - "a01.40", - "a1.00000040", - "a1.40", - "a2", - "a100", - "aa", - "aaa", - "ab", - "abab", - "b1", - "b3", - "b11", - "b20", - "b20a", - "b20b", - "", // because of '\n' at the end of the output + "a1", "a001.001", "a1.4", "a1.13", "a01.40", "a2", "a100", "aa", "aaa", "ab", "abab", "b1", + "b3", "b11", "b20", "b20a", "b20b", "", // because of '\n' at the end of the output ]; let result = scene.ucmd().arg("-1v").succeeds(); From 844cbdc5a46ef7d5b645306b8677227b3a523e8d Mon Sep 17 00:00:00 2001 From: John Shin Date: Tue, 27 Jun 2023 12:15:58 -0700 Subject: [PATCH 70/88] sort: add tests for stable and unstable sort --- src/uucore/src/lib/mods/version_cmp.rs | 8 +++----- tests/by-util/test_sort.rs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/uucore/src/lib/mods/version_cmp.rs b/src/uucore/src/lib/mods/version_cmp.rs index 2bbaffd25..828b7f2a6 100644 --- a/src/uucore/src/lib/mods/version_cmp.rs +++ b/src/uucore/src/lib/mods/version_cmp.rs @@ -106,7 +106,7 @@ pub fn version_cmp(mut a: &str, mut b: &str) -> Ordering { // 1. Compare leading non-numerical part // 2. Compare leading numerical part // 3. Repeat - loop { + while !a.is_empty() || !b.is_empty() { let a_numerical_start = a.find(|c: char| c.is_ascii_digit()).unwrap_or(a.len()); let b_numerical_start = b.find(|c: char| c.is_ascii_digit()).unwrap_or(b.len()); @@ -139,11 +139,9 @@ pub fn version_cmp(mut a: &str, mut b: &str) -> Ordering { a = &a[a_numerical_end..]; b = &b[b_numerical_end..]; - - if a.is_empty() && b.is_empty() { - return std::cmp::Ordering::Equal; - } } + + Ordering::Equal } #[cfg(test)] diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index e66a405ab..0c8af8969 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -134,6 +134,25 @@ fn test_version_empty_lines() { test_helper("version-empty-lines", &["-V", "--version-sort"]); } +#[test] +fn test_version_sort_unstable() { + new_ucmd!() + .arg("--sort=version") + .pipe_in("0.1\n0.02\n0.2\n0.002\n0.3\n") + .succeeds() + .stdout_is("0.1\n0.002\n0.02\n0.2\n0.3\n"); +} + +#[test] +fn test_version_sort_stable() { + new_ucmd!() + .arg("--stable") + .arg("--sort=version") + .pipe_in("0.1\n0.02\n0.2\n0.002\n0.3\n") + .succeeds() + .stdout_is("0.1\n0.02\n0.2\n0.002\n0.3\n"); +} + #[test] fn test_human_numeric_whitespace() { test_helper( From 51a4fa0c49e8197e2b0e8a8f92e55e3c673f492a Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 5 Jul 2023 10:14:12 +0200 Subject: [PATCH 71/88] Bump iana-time-zone-haiku from 0.1.1 to 0.1.2 --- Cargo.lock | 89 +++--------------------------------------------------- 1 file changed, 5 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b4104e93..d7c6391de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,9 +233,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.77" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cexpr" @@ -324,16 +324,6 @@ dependencies = [ "roff", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "colorchoice" version = "1.0.0" @@ -730,50 +720,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" -[[package]] -name = "cxx" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "data-encoding" version = "2.4.0" @@ -1179,12 +1125,11 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -1332,15 +1277,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "link-cplusplus" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" -dependencies = [ - "cc", -] - [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -2007,12 +1943,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" - [[package]] name = "self_cell" version = "1.0.1" @@ -2223,15 +2153,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - [[package]] name = "terminal_size" version = "0.2.6" From 2947c00e4c97367314ecd9b49e5837af043626a5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jul 2023 10:30:04 +0000 Subject: [PATCH 72/88] chore(deps): update rust crate bigdecimal to 0.4 --- Cargo.lock | 11 +++++++++-- Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7c6391de..0a5947364 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,10 +121,11 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bigdecimal" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" +checksum = "5274a6b6e0ee020148397245b973e30163b7bffbc6d473613f850cb99888581e" dependencies = [ + "libm", "num-bigint", "num-integer", "num-traits", @@ -1277,6 +1278,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "linux-raw-sys" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index daa44eb6a..0737bcd38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -257,7 +257,7 @@ feat_os_windows_legacy = [ test = ["uu_test"] [workspace.dependencies] -bigdecimal = "0.3" +bigdecimal = "0.4" binary-heap-plus = "0.5.0" bstr = "1.5" bytecount = "0.6.3" From 357dd5fd8893520852e5781ebcdd6cc7e5e69f70 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 5 Jul 2023 16:00:16 +0200 Subject: [PATCH 73/88] initial oranda setup --- .gitignore | 1 + README.md | 11 +++++++++++ docs/src/oranda.css | 4 ++++ oranda.json | 13 +++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 docs/src/oranda.css create mode 100644 oranda.json diff --git a/.gitignore b/.gitignore index 77e8f717e..ed4e54ec5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ target/ /busybox/ /.vscode/ /.vs/ +/public/ *~ .*.swp .*.swo diff --git a/README.md b/README.md index 5a9f968ae..76d30bf61 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ +
![uutils logo](docs/src/logo.svg) @@ -19,11 +20,14 @@ --- +
uutils coreutils is a cross-platform reimplementation of the GNU coreutils in [Rust](http://www.rust-lang.org). While all programs have been implemented, some options might be missing or different behavior might be experienced. +
+ To install it: ```shell @@ -31,6 +35,8 @@ cargo install coreutils ~/.cargo/bin/coreutils ``` +
+ ## Goals @@ -42,6 +48,8 @@ uutils aims to work on as many platforms as possible, to be able to use the same utils on Linux, Mac, Windows and other platforms. This ensures, for example, that scripts can be easily transferred between platforms. +
+ ## Documentation uutils has both user and developer documentation available: @@ -52,6 +60,7 @@ uutils has both user and developer documentation available: Both can also be generated locally, the instructions for that can be found in the [coreutils docs](https://github.com/uutils/uutils.github.io) repository. + ## Requirements @@ -301,6 +310,8 @@ See for the main meta bugs ![Evolution over time](https://github.com/uutils/coreutils-tracking/blob/main/gnu-results.png?raw=true) +
+ ## Contributing To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md). diff --git a/docs/src/oranda.css b/docs/src/oranda.css new file mode 100644 index 000000000..5581cc0c5 --- /dev/null +++ b/docs/src/oranda.css @@ -0,0 +1,4 @@ +.logo { + display: block; + height: 170px; +} diff --git a/oranda.json b/oranda.json new file mode 100644 index 000000000..b0a93c19a --- /dev/null +++ b/oranda.json @@ -0,0 +1,13 @@ +{ + "project": { + "name": "uutils coreutils" + }, + "components": { + "changelog": true + }, + "styles": { + "theme": "light", + "logo": "docs/src/logo.svg", + "additional_css": ["docs/src/oranda.css"] + } +} From 389741eda3d821ce5ab603a82b0eef0689c33b35 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jul 2023 18:14:40 +0000 Subject: [PATCH 74/88] chore(deps): update rust crate bstr to 1.6 --- Cargo.lock | 9 ++++----- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a5947364..cba85bf58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,12 +204,11 @@ dependencies = [ [[package]] name = "bstr" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "once_cell", "regex-automata", "serde", ] @@ -1831,9 +1830,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56" [[package]] name = "regex-syntax" diff --git a/Cargo.toml b/Cargo.toml index 0737bcd38..28a8cd5a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -259,7 +259,7 @@ test = ["uu_test"] [workspace.dependencies] bigdecimal = "0.4" binary-heap-plus = "0.5.0" -bstr = "1.5" +bstr = "1.6" bytecount = "0.6.3" byteorder = "1.4.3" chrono = { version = "^0.4.26", default-features = false, features = [ From c6be1c10ba8e6cf6d49d0ab882cd9e2511fe8f06 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jul 2023 22:57:39 +0000 Subject: [PATCH 75/88] chore(deps): update rust crate smallvec to 1.11 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a5947364..6217f2655 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2088,9 +2088,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "smawk" diff --git a/Cargo.toml b/Cargo.toml index 0737bcd38..001c522e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -317,7 +317,7 @@ same-file = "1.0.6" self_cell = "1.0.1" selinux = "0.4" signal-hook = "0.3.15" -smallvec = { version = "1.10", features = ["union"] } +smallvec = { version = "1.11", features = ["union"] } tempfile = "3.6.0" term_grid = "0.1.5" terminal_size = "0.2.6" From eb3164002a30cef4e7b8338f0d5a2b7e30059722 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 05:41:42 +0000 Subject: [PATCH 76/88] chore(deps): update rust crate regex to 1.9.0 --- Cargo.lock | 14 ++++++++++---- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cba85bf58..78ab1c0a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1819,12 +1819,13 @@ checksum = "f1bfbf25d7eb88ddcbb1ec3d755d0634da8f7657b2cb8b74089121409ab8228f" [[package]] name = "regex" -version = "1.8.4" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484" dependencies = [ "aho-corasick 1.0.1", "memchr", + "regex-automata", "regex-syntax", ] @@ -1833,12 +1834,17 @@ name = "regex-automata" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56" +dependencies = [ + "aho-corasick 1.0.1", + "memchr", + "regex-syntax", +] [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" [[package]] name = "rlimit" diff --git a/Cargo.toml b/Cargo.toml index 28a8cd5a5..123f1f9ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -310,7 +310,7 @@ rand = { version = "0.8", features = ["small_rng"] } rand_core = "0.6" rayon = "1.7" redox_syscall = "0.3" -regex = "1.8.4" +regex = "1.9.0" rstest = "0.17.0" rust-ini = "0.19.0" same-file = "1.0.6" From 725f226941543ae4effc9207ca433069859d872b Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 6 Jul 2023 15:07:10 +0200 Subject: [PATCH 77/88] Bump syn from 1.0.103 to 1.0.109 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e23c6732..390ed531a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2133,9 +2133,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", From 24c74d0f573a508cf82204fa55fd909d47eab693 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 6 Jul 2023 15:10:22 +0200 Subject: [PATCH 78/88] deny.toml: add syn to skip list --- deny.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deny.toml b/deny.toml index c52b321dd..46d35ad03 100644 --- a/deny.toml +++ b/deny.toml @@ -87,6 +87,8 @@ skip = [ { name = "aho-corasick", version = "0.7.19" }, # ordered-multimap (via rust-ini) { name = "hashbrown", version = "0.13.2" }, + # various crates + { name = "syn", version = "1.0.109" }, ] # spell-checker: enable From 8089909448449854dba1f9647e254c77e68be05c Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 6 Jul 2023 15:14:38 +0200 Subject: [PATCH 79/88] Cargo.toml: use "workspace = true" for rstest --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e857e5fed..417c7f920 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -492,7 +492,7 @@ uucore = { workspace = true, features = ["entries", "process", "signals"] } walkdir = { workspace = true } is-terminal = { workspace = true } hex-literal = "0.4.1" -rstest = "0.17.0" +rstest = { workspace = true } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies] procfs = { version = "0.15", default-features = false } From 3edea14ae8f964ed29d47259ffaca5715b06e9b2 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 7 Jul 2023 10:54:47 +0200 Subject: [PATCH 80/88] docs: add "du" to extensions --- docs/src/extensions.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/extensions.md b/docs/src/extensions.md index ae3d974fe..eeb00ff35 100644 --- a/docs/src/extensions.md +++ b/docs/src/extensions.md @@ -74,3 +74,7 @@ number of spaces representing a tab when determining the line length. GNU `ls` provides two ways to use a long listing format: `-l` and `--format=long`. We support a third way: `--long`. + +## `du` + +`du` allows `birth` and `creation` as values for the `--time` argument to show the creation time. From 90a763137c6330c1c9df52932ed1eb466e21e945 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jul 2023 11:36:30 +0000 Subject: [PATCH 81/88] chore(deps): update rust crate rstest to 0.18.1 --- Cargo.lock | 54 +++++++++++++++++++++++++++++++++++++----------------- Cargo.toml | 2 +- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 390ed531a..e512643dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,7 +158,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 1.0.109", "which", ] @@ -562,7 +562,7 @@ dependencies = [ "lazy_static", "proc-macro2", "regex", - "syn", + "syn 1.0.109", "unicode-xid", ] @@ -574,7 +574,7 @@ checksum = "76071bb9c8c4dd2b5eb209907deab7b031323cf1be3dfdc6ec5d37f4f187d8a1" dependencies = [ "lazy_static", "proc-macro2", - "syn", + "syn 1.0.109", ] [[package]] @@ -589,7 +589,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -701,7 +701,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -743,7 +743,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" dependencies = [ "data-encoding", - "syn", + "syn 1.0.109", ] [[package]] @@ -984,7 +984,7 @@ checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1725,9 +1725,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -1846,6 +1846,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" +[[package]] +name = "relative-path" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" + [[package]] name = "rlimit" version = "0.10.0" @@ -1863,9 +1869,9 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rstest" -version = "0.17.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962" +checksum = "2b96577ca10cb3eade7b337eb46520108a67ca2818a24d0b63f41fd62bc9651c" dependencies = [ "futures", "futures-timer", @@ -1875,15 +1881,18 @@ dependencies = [ [[package]] name = "rstest_macros" -version = "0.17.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8" +checksum = "225e674cf31712b8bb15fdbca3ec0c1b9d825c5a24407ff2b7e005fb6a29ba03" dependencies = [ "cfg-if", + "glob", "proc-macro2", "quote", + "regex", + "relative-path", "rustc_version", - "syn", + "syn 2.0.23", "unicode-ident", ] @@ -2142,6 +2151,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tempfile" version = "3.6.0" @@ -2204,7 +2224,7 @@ checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -3400,7 +3420,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -3422,7 +3442,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 417c7f920..cb814602f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -311,7 +311,7 @@ rand_core = "0.6" rayon = "1.7" redox_syscall = "0.3" regex = "1.9.0" -rstest = "0.17.0" +rstest = "0.18.1" rust-ini = "0.19.0" same-file = "1.0.6" self_cell = "1.0.1" From 4f24d81e86b19c5870e12190f5c4474c80ab83bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jul 2023 18:29:31 +0000 Subject: [PATCH 82/88] chore(deps): update rust crate regex to 1.9.1 --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e512643dc..4abfb1fdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1819,9 +1819,9 @@ checksum = "f1bfbf25d7eb88ddcbb1ec3d755d0634da8f7657b2cb8b74089121409ab8228f" [[package]] name = "regex" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick 1.0.1", "memchr", @@ -1831,9 +1831,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56" +checksum = "e9aaecc05d5c4b5f7da074b9a0d1a0867e71fd36e7fc0482d8bcfe8e8fc56290" dependencies = [ "aho-corasick 1.0.1", "memchr", diff --git a/Cargo.toml b/Cargo.toml index cb814602f..f6b4e19d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -310,7 +310,7 @@ rand = { version = "0.8", features = ["small_rng"] } rand_core = "0.6" rayon = "1.7" redox_syscall = "0.3" -regex = "1.9.0" +regex = "1.9.1" rstest = "0.18.1" rust-ini = "0.19.0" same-file = "1.0.6" From 79b44597315a3046d736a44c155ab66537077578 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 8 Jul 2023 00:32:32 +0200 Subject: [PATCH 83/88] add oranda to the spell ignore --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76d30bf61..4929224d1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ - +
From 85b9b61dd8a44e92ced13505c8faf4882061a1d1 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Sat, 8 Jul 2023 01:35:58 +0300 Subject: [PATCH 84/88] stty: Finish '--save' support Argument parsing for this exists, but the option doesn't change output in any way. Finish the support. Closes #3862 --- src/uu/stty/src/stty.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/uu/stty/src/stty.rs b/src/uu/stty/src/stty.rs index e09662471..6b77f175a 100644 --- a/src/uu/stty/src/stty.rs +++ b/src/uu/stty/src/stty.rs @@ -244,12 +244,30 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> { Ok(()) } +fn print_in_save_format(termios: &Termios) { + print!( + "{:x}:{:x}:{:x}:{:x}", + termios.input_flags.bits(), + termios.output_flags.bits(), + termios.control_flags.bits(), + termios.local_flags.bits() + ); + for cc in termios.control_chars { + print!(":{cc:x}"); + } + println!(); +} + fn print_settings(termios: &Termios, opts: &Options) -> nix::Result<()> { - print_terminal_size(termios, opts)?; - print_flags(termios, opts, CONTROL_FLAGS); - print_flags(termios, opts, INPUT_FLAGS); - print_flags(termios, opts, OUTPUT_FLAGS); - print_flags(termios, opts, LOCAL_FLAGS); + if opts.save { + print_in_save_format(termios); + } else { + print_terminal_size(termios, opts)?; + print_flags(termios, opts, CONTROL_FLAGS); + print_flags(termios, opts, INPUT_FLAGS); + print_flags(termios, opts, OUTPUT_FLAGS); + print_flags(termios, opts, LOCAL_FLAGS); + } Ok(()) } From 6f5416bddb15ca77756e402d49bdfd5ac14c1bae Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sat, 8 Jul 2023 06:33:27 +0200 Subject: [PATCH 85/88] cspell: ignore oranda.json --- .vscode/cSpell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/cSpell.json b/.vscode/cSpell.json index edac1c21e..6ceb038c2 100644 --- a/.vscode/cSpell.json +++ b/.vscode/cSpell.json @@ -19,6 +19,7 @@ // files to ignore (globs supported) "ignorePaths": [ "Cargo.lock", + "oranda.json", "target/**", "tests/**/fixtures/**", "src/uu/dd/test-resources/**", From bde9030e4e62e5c2ff04388a2e0839d1245c044a Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Sat, 8 Jul 2023 00:20:35 +0300 Subject: [PATCH 86/88] stty: Support setting baud rate Part of #3859. --- src/uu/stty/src/stty.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/uu/stty/src/stty.rs b/src/uu/stty/src/stty.rs index e09662471..faff9d49c 100644 --- a/src/uu/stty/src/stty.rs +++ b/src/uu/stty/src/stty.rs @@ -3,14 +3,15 @@ // * For the full copyright and license information, please view the LICENSE file // * that was distributed with this source code. -// spell-checker:ignore clocal tcgetattr tcsetattr tcsanow tiocgwinsz tiocswinsz cfgetospeed ushort +// spell-checker:ignore clocal tcgetattr tcsetattr tcsanow tiocgwinsz tiocswinsz cfgetospeed cfsetospeed ushort mod flags; use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use nix::libc::{c_ushort, O_NONBLOCK, TIOCGWINSZ, TIOCSWINSZ}; use nix::sys::termios::{ - cfgetospeed, tcgetattr, tcsetattr, ControlFlags, InputFlags, LocalFlags, OutputFlags, Termios, + cfgetospeed, cfsetospeed, tcgetattr, tcsetattr, ControlFlags, InputFlags, LocalFlags, + OutputFlags, Termios, }; use nix::{ioctl_read_bad, ioctl_write_ptr_bad}; use std::io::{self, stdout}; @@ -290,6 +291,8 @@ fn print_flags(termios: &Termios, opts: &Options, flags: &[Flag< /// The value inside the `Break` variant of the `ControlFlow` indicates whether /// the setting has been applied. fn apply_setting(termios: &mut Termios, s: &str) -> ControlFlow { + apply_baud_rate_flag(termios, s)?; + let (remove, name) = match s.strip_prefix('-') { Some(s) => (true, s), None => (false, s), @@ -332,6 +335,39 @@ fn apply_flag( ControlFlow::Continue(()) } +fn apply_baud_rate_flag(termios: &mut Termios, input: &str) -> ControlFlow { + // BSDs use a u32 for the baud rate, so any decimal number applies. + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + if let Ok(n) = input.parse::() { + cfsetospeed(termios, n).expect("Failed to set baud rate"); + return ControlFlow::Break(true); + } + + // Other platforms use an enum. + #[cfg(not(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )))] + for (text, baud_rate) in BAUD_RATES { + if *text == input { + cfsetospeed(termios, *baud_rate).expect("Failed to set baud rate"); + return ControlFlow::Break(true); + } + } + ControlFlow::Continue(()) +} + pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) From bdd8729cc289e713f90db39d55050fc567166258 Mon Sep 17 00:00:00 2001 From: Piotr Kwiecinski Date: Sat, 8 Jul 2023 12:49:20 +0200 Subject: [PATCH 87/88] fix: fixpr.yml unrecognized named-value: 'steps' simplify passing variables to github output fix warning with add-and-commit action --- .github/workflows/FixPR.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/FixPR.yml b/.github/workflows/FixPR.yml index e1729b173..97b0be34a 100644 --- a/.github/workflows/FixPR.yml +++ b/.github/workflows/FixPR.yml @@ -31,12 +31,12 @@ jobs: id: vars shell: bash run: | - ## VARs setup - outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # surface MSRV from CICD workflow RUST_MIN_SRV=$(grep -P "^\s+RUST_MIN_SRV:" .github/workflows/CICD.yml | grep -Po "(?<=\x22)\d+[.]\d+(?:[.]\d+)?(?=\x22)" ) - outputs RUST_MIN_SRV - - uses: dtolnay/rust-toolchain@${{ steps.vars.outputs.RUST_MIN_SRV }} + echo "RUST_MIN_SRV=${RUST_MIN_SRV}" >> $GITHUB_OUTPUT + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ steps.vars.outputs.RUST_MIN_SRV }} - uses: Swatinem/rust-cache@v2 - name: Ensure updated 'Cargo.lock' shell: bash @@ -67,7 +67,7 @@ jobs: - name: Commit any changes (to '${{ env.BRANCH_TARGET }}') uses: EndBug/add-and-commit@v9 with: - branch: ${{ env.BRANCH_TARGET }} + new_branch: ${{ env.BRANCH_TARGET }} default_author: github_actions message: "maint ~ refresh 'Cargo.lock'" add: Cargo.lock @@ -90,13 +90,11 @@ jobs: id: vars shell: bash run: | - ## VARs setup - outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # target-specific options # * CARGO_FEATURES_OPTION CARGO_FEATURES_OPTION='' ; if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi - outputs CARGO_FEATURES_OPTION + echo "CARGO_FEATURES_OPTION=${CARGO_FEATURES_OPTION}" >> $GITHUB_OUTPUT - uses: dtolnay/rust-toolchain@master with: toolchain: stable @@ -114,7 +112,7 @@ jobs: - name: Commit any changes (to '${{ env.BRANCH_TARGET }}') uses: EndBug/add-and-commit@v9 with: - branch: ${{ env.BRANCH_TARGET }} + new_branch: ${{ env.BRANCH_TARGET }} default_author: github_actions message: "maint ~ rustfmt (`cargo fmt`)" env: From 6f91371e613a4a835286c8f5e7c6b7ba0ba659bd Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sat, 8 Jul 2023 16:13:35 +0200 Subject: [PATCH 88/88] touch: accept "modify" & "mtime" for --time arg --- src/uu/touch/src/touch.rs | 2 +- tests/by-util/test_touch.rs | 44 ++++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index f4784f155..230a6bb70 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -295,7 +295,7 @@ pub fn uu_app() -> Command { equivalent to -m", ) .value_name("WORD") - .value_parser(["access", "atime", "use"]), + .value_parser(["access", "atime", "use", "modify", "mtime"]), ) .arg( Arg::new(ARG_FILES) diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 0e4eade3d..cd2a70bdb 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -204,19 +204,23 @@ fn test_touch_set_cymdhms_time() { #[test] fn test_touch_set_only_atime() { - let (at, mut ucmd) = at_and_ucmd!(); + let atime_args = ["-a", "--time=access", "--time=atime", "--time=use"]; let file = "test_touch_set_only_atime"; - ucmd.args(&["-t", "201501011234", "-a", file]) - .succeeds() - .no_stderr(); + for atime_arg in atime_args { + let (at, mut ucmd) = at_and_ucmd!(); - assert!(at.file_exists(file)); + ucmd.args(&["-t", "201501011234", atime_arg, file]) + .succeeds() + .no_stderr(); - let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000"); - let (atime, mtime) = get_file_times(&at, file); - assert!(atime != mtime); - assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45240); + assert!(at.file_exists(file)); + + let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000"); + let (atime, mtime) = get_file_times(&at, file); + assert!(atime != mtime); + assert_eq!(atime.unix_seconds() - start_of_year.unix_seconds(), 45240); + } } #[test] @@ -301,19 +305,23 @@ fn test_touch_set_both_time_and_date() { #[test] fn test_touch_set_only_mtime() { - let (at, mut ucmd) = at_and_ucmd!(); + let mtime_args = ["-m", "--time=modify", "--time=mtime"]; let file = "test_touch_set_only_mtime"; - ucmd.args(&["-t", "201501011234", "-m", file]) - .succeeds() - .no_stderr(); + for mtime_arg in mtime_args { + let (at, mut ucmd) = at_and_ucmd!(); - assert!(at.file_exists(file)); + ucmd.args(&["-t", "201501011234", mtime_arg, file]) + .succeeds() + .no_stderr(); - let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000"); - let (atime, mtime) = get_file_times(&at, file); - assert!(atime != mtime); - assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45240); + assert!(at.file_exists(file)); + + let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000"); + let (atime, mtime) = get_file_times(&at, file); + assert!(atime != mtime); + assert_eq!(mtime.unix_seconds() - start_of_year.unix_seconds(), 45240); + } } #[test]