From abc5cfb9508c4d139b39bff335c4aa6a288a7886 Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Tue, 14 Feb 2023 00:21:16 -0800 Subject: [PATCH 01/40] coreutils: fixed panic when multi-call binary has empty or non-UTF-8 name The multi-call `coreutils` binary starts by trying to convert its invocation path into a UTF-8 string, panicking if this doesn't work. This patch makes `coreutils` exit gracefully in this case. --- src/bin/coreutils.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/bin/coreutils.rs b/src/bin/coreutils.rs index 08c0774ba..75e64e17b 100644 --- a/src/bin/coreutils.rs +++ b/src/bin/coreutils.rs @@ -41,8 +41,8 @@ fn binary_path(args: &mut impl Iterator) -> PathBuf { } } -fn name(binary_path: &Path) -> &str { - binary_path.file_stem().unwrap().to_str().unwrap() +fn name(binary_path: &Path) -> Option<&str> { + binary_path.file_stem()?.to_str() } fn main() { @@ -52,7 +52,10 @@ fn main() { let mut args = uucore::args_os(); let binary = binary_path(&mut args); - let binary_as_util = name(&binary); + let binary_as_util = name(&binary).unwrap_or_else(|| { + usage(&utils, ""); + process::exit(0); + }); // binary name equals util name? if let Some(&(uumain, _)) = utils.get(binary_as_util) { From af4ce911c8315e3f339ea809ccf04b65ef834075 Mon Sep 17 00:00:00 2001 From: ZauJulio Date: Thu, 16 Feb 2023 17:48:23 -0300 Subject: [PATCH 02/40] mktemp: fix PrefixContainsDirSeparator verification --- src/uu/mktemp/src/mktemp.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 390c77bfa..fed946577 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -281,7 +281,11 @@ impl Params { .join(prefix_from_template) .display() .to_string(); - if options.treat_as_template && prefix.contains(MAIN_SEPARATOR) { + + // Check that the prefix is valid. + let prefix_of_template = Path::new(prefix_from_template).display().to_string(); + + if options.treat_as_template && prefix_of_template.contains(MAIN_SEPARATOR) { return Err(MkTempError::PrefixContainsDirSeparator(options.template)); } if tmpdir.is_some() && Path::new(prefix_from_template).is_absolute() { From 9e2c543cd40c6b237097f17ae66141e8fc9d4413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Za=C3=BA=20J=C3=BAlio?= Date: Thu, 16 Feb 2023 18:43:32 -0300 Subject: [PATCH 03/40] mktemp: prefix prefix_of_template use to_string_lossy Co-authored-by: Terts Diepraam --- src/uu/mktemp/src/mktemp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index fed946577..1764b8e84 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -283,7 +283,7 @@ impl Params { .to_string(); // Check that the prefix is valid. - let prefix_of_template = Path::new(prefix_from_template).display().to_string(); + let prefix_of_template = Path::new(prefix_from_template).to_string_lossy(); if options.treat_as_template && prefix_of_template.contains(MAIN_SEPARATOR) { return Err(MkTempError::PrefixContainsDirSeparator(options.template)); From 3d2f3fc5b155a1ba9161e921ffbdf763f671712f Mon Sep 17 00:00:00 2001 From: ZauJulio Date: Wed, 22 Feb 2023 20:22:16 -0300 Subject: [PATCH 04/40] mktemp: add test to . in template prefix --- tests/by-util/test_mktemp.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index d6926c41b..6d4a7fb6f 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -21,6 +21,7 @@ static TEST_TEMPLATE6: &str = "tempXXXlate"; // spell-checker:disable-line static TEST_TEMPLATE7: &str = "XXXtemplate"; // spell-checker:disable-line #[cfg(unix)] static TEST_TEMPLATE8: &str = "tempXXXl/ate"; +static TEST_TEMPLATE9: &str = "a.XXXX"; #[cfg(windows)] static TEST_TEMPLATE8: &str = "tempXXXl\\ate"; @@ -569,6 +570,14 @@ fn test_template_path_separator() { )); } +/// Test that a prefix with a point is valid. +#[test] +fn test_prefix_template_separator() { + new_ucmd!() + .args(&["-t", TEST_TEMPLATE9]) + .succeeds(); +} + /// Test that a suffix with a path separator is invalid. #[test] fn test_suffix_path_separator() { From dc1fd027a6ca0f609cf9ba3eb63c6bc75ec9c011 Mon Sep 17 00:00:00 2001 From: ZauJulio Date: Sat, 25 Feb 2023 18:35:35 -0300 Subject: [PATCH 05/40] mktemp: fix fmt of test_prefix_template_separator --- tests/by-util/test_mktemp.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index dc09204b6..081e4da1b 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -575,9 +575,7 @@ fn test_template_path_separator() { /// Test that a prefix with a point is valid. #[test] fn test_prefix_template_separator() { - new_ucmd!() - .args(&["-t", TEST_TEMPLATE9]) - .succeeds(); + new_ucmd!().args(&["-t", TEST_TEMPLATE9]).succeeds(); } /// Test that a suffix with a path separator is invalid. From a87bc9f9291fe707900f3434a8bdc7803366eb44 Mon Sep 17 00:00:00 2001 From: ZauJulio Date: Mon, 27 Feb 2023 01:13:16 -0300 Subject: [PATCH 06/40] mktemp: remove unnecessary convertion for path -> str just use prefix_from_template --- src/uu/mktemp/src/mktemp.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 1764b8e84..5d4308958 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -281,11 +281,7 @@ impl Params { .join(prefix_from_template) .display() .to_string(); - - // Check that the prefix is valid. - let prefix_of_template = Path::new(prefix_from_template).to_string_lossy(); - - if options.treat_as_template && prefix_of_template.contains(MAIN_SEPARATOR) { + if options.treat_as_template && prefix_from_template.contains(MAIN_SEPARATOR) { return Err(MkTempError::PrefixContainsDirSeparator(options.template)); } if tmpdir.is_some() && Path::new(prefix_from_template).is_absolute() { From 9b4fb0cb6eb46b3e3cba1d318e317b821dfa9328 Mon Sep 17 00:00:00 2001 From: ZauJulio Date: Tue, 28 Feb 2023 12:38:18 -0300 Subject: [PATCH 07/40] mktemp: add tests UNIX and POSIX to check path in prefix --- tests/by-util/test_mktemp.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index 081e4da1b..7c3d62150 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -578,6 +578,26 @@ fn test_prefix_template_separator() { new_ucmd!().args(&["-t", TEST_TEMPLATE9]).succeeds(); } +#[test] +fn test_prefix_template_with_path_separator() { + #[cfg(not(windows))] + new_ucmd!() + .args(&["-t", "a/XXX"]) + .fails() + .stderr_only(format!( + "mktemp: invalid template, {}, contains directory separator\n", + "a/XXX".quote() + )); + #[cfg(windows)] + new_ucmd!() + .args(&["-t", r"a\XXX"]) + .fails() + .stderr_only(format!( + "mktemp: invalid template, {}, contains directory separator\n", + r"a\XXX".quote() + )); +} + /// Test that a suffix with a path separator is invalid. #[test] fn test_suffix_path_separator() { From e9bd69e0519c380663a0cda9abffb75209679acb Mon Sep 17 00:00:00 2001 From: ZauJulio Date: Wed, 1 Mar 2023 15:45:41 -0300 Subject: [PATCH 08/40] mktemp: fix test_prefix_template_separator adding -p param --- tests/by-util/test_mktemp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index 7c3d62150..b6e3b2076 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -21,9 +21,9 @@ static TEST_TEMPLATE6: &str = "tempXXXlate"; // spell-checker:disable-line static TEST_TEMPLATE7: &str = "XXXtemplate"; // spell-checker:disable-line #[cfg(unix)] static TEST_TEMPLATE8: &str = "tempXXXl/ate"; -static TEST_TEMPLATE9: &str = "a.XXXX"; #[cfg(windows)] static TEST_TEMPLATE8: &str = "tempXXXl\\ate"; +static TEST_TEMPLATE9: &str = "a.XXXX"; #[cfg(not(windows))] const TMPDIR: &str = "TMPDIR"; @@ -575,7 +575,7 @@ fn test_template_path_separator() { /// Test that a prefix with a point is valid. #[test] fn test_prefix_template_separator() { - new_ucmd!().args(&["-t", TEST_TEMPLATE9]).succeeds(); + new_ucmd!().args(&["-p", ".", "-t", TEST_TEMPLATE9]).succeeds(); } #[test] From b94a0d2ebea6e151ad52f32f96b8ea9f09bb5a4d Mon Sep 17 00:00:00 2001 From: ZauJulio Date: Thu, 2 Mar 2023 15:30:55 -0300 Subject: [PATCH 09/40] mktemp: fix test fmt --- tests/by-util/test_mktemp.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index b6e3b2076..8d615899c 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -575,7 +575,9 @@ fn test_template_path_separator() { /// Test that a prefix with a point is valid. #[test] fn test_prefix_template_separator() { - new_ucmd!().args(&["-p", ".", "-t", TEST_TEMPLATE9]).succeeds(); + new_ucmd!() + .args(&["-p", ".", "-t", TEST_TEMPLATE9]) + .succeeds(); } #[test] From 1e43cb1c1ec634173ca9ad6fb195939096ed19f8 Mon Sep 17 00:00:00 2001 From: Miles Liu Date: Mon, 17 Apr 2023 14:24:57 +0800 Subject: [PATCH 10/40] CI: warn if the size of the binary increases by more than 5% --- .github/workflows/CICD.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index add337f66..e13f1774a 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -591,6 +591,44 @@ jobs: --arg size "$SIZE" \ --arg multisize "$SIZE_MULTI" \ '{($date): { sha: $sha, size: $size, multisize: $multisize, }}' > size-result.json + - name: Download the previous individual size result + uses: dawidd6/action-download-artifact@v2 + with: + workflow: CICD.yml + name: individual-size-result + repo: uutils/coreutils + path: dl + - name: Download the previous size result + uses: dawidd6/action-download-artifact@v2 + with: + workflow: CICD.yml + name: size-result + repo: uutils/coreutils + path: dl + - name: Check uutil release sizes + shell: bash + run: | + check() { + # Warn if the size increases by more than 5% + threshold='1.05' + ratio=$(jq -n "$2 / $3") + echo "$1: size=$2, previous_size=$3, ratio=$ratio, threshold=$threshold" + if [[ "$(jq -n "$ratio > $threshold")" == 'true' ]]; then + echo "::warning file=$4::Size of $1 increases by more than 5%" + fi + } + ## Check individual size result + while read -r name previous_size; do + size=$(cat individual-size-result.json | jq -r ".[] | .sizes | .\"$name\"") + check "\`$name\` binary" "$size" "$previous_size" 'individual-size-result.json' + done < <(cat dl/individual-size-result.json | jq -r '.[] | .sizes | to_entries[] | "\(.key) \(.value)"') + ## Check size result + size=$(cat size-result.json | jq -r '.[] | .size') + previous_size=$(cat dl/size-result.json | jq -r '.[] | .size') + check 'multiple binaries' "$size" "$previous_size" 'size-result.json' + multisize=$(cat size-result.json | jq -r '.[] | .multisize') + previous_multisize=$(cat dl/size-result.json | jq -r '.[] | .multisize') + check 'multicall binary' "$multisize" "$previous_multisize" 'size-result.json' - name: Upload the individual size result uses: actions/upload-artifact@v3 with: From 804274dbf46cd62615dbc3033d90524cbd83745a Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 25 Apr 2023 11:33:48 +0200 Subject: [PATCH 11/40] mv: adapt -n behavior to GNU mv 9.3 --- src/uu/mv/src/mv.rs | 7 ++++++- tests/by-util/test_mv.rs | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index d0a1a766f..e234ac857 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -419,7 +419,12 @@ fn rename( } match b.overwrite { - OverwriteMode::NoClobber => return Ok(()), + OverwriteMode::NoClobber => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("not replacing {}", to.quote()), + )); + } OverwriteMode::Interactive => { if !prompt_yes!("overwrite {}?", to.quote()) { return Err(io::Error::new(io::ErrorKind::Other, "")); diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index 034234107..43a09c52e 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -232,8 +232,9 @@ fn test_mv_no_clobber() { ucmd.arg("-n") .arg(file_a) .arg(file_b) - .succeeds() - .no_stderr(); + .fails() + .code_is(1) + .stderr_only(format!("mv: not replacing '{file_b}'\n")); assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); From eba000ddcc991bb168c80b8f7b60d8c51c745558 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 25 Apr 2023 05:14:09 -0700 Subject: [PATCH 12/40] Use `expected_result` in test_ls to avoid spurious failures As the existing comment says, the expected output here is dependent on the platform, so use the `expected_result` utility to avoid hard-coding specific results for each platform. This fixes spurious failures on my machine. --- tests/by-util/test_ls.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 1a189a25a..0779a2885 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -1,6 +1,6 @@ // spell-checker:ignore (words) READMECAREFULLY birthtime doesntexist oneline somebackup lrwx somefile somegroup somehiddenbackup somehiddenfile tabsize aaaaaaaa bbbb cccc dddddddd ncccc -#[cfg(feature = "feat_selinux")] +#[cfg(any(unix, feature = "feat_selinux"))] use crate::common::util::expected_result; use crate::common::util::TestScenario; #[cfg(all(unix, feature = "chmod"))] @@ -1776,9 +1776,15 @@ fn test_ls_order_time() { at.open("test-4").metadata().unwrap().accessed().unwrap(); // It seems to be dependent on the platform whether the access time is actually set - #[cfg(all(unix, not(target_os = "android")))] - result.stdout_only("test-3\ntest-4\ntest-2\ntest-1\n"); - #[cfg(any(windows, target_os = "android"))] + #[cfg(unix)] + { + let expected = unwrap_or_return!(expected_result(&scene, &["-t", arg])); + at.open("test-3").metadata().unwrap().accessed().unwrap(); + at.open("test-4").metadata().unwrap().accessed().unwrap(); + + result.stdout_only(expected.stdout_str()); + } + #[cfg(windows)] result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n"); } From 98dd31c00d5a7e5be5991b8fdd8437ce8c395543 Mon Sep 17 00:00:00 2001 From: m11o Date: Tue, 25 Apr 2023 22:00:22 +0900 Subject: [PATCH 13/40] split: move help strings to markdown file --- src/uu/split/split.md | 11 +++++++++++ src/uu/split/src/split.rs | 12 +++++------- 2 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 src/uu/split/split.md diff --git a/src/uu/split/split.md b/src/uu/split/split.md new file mode 100644 index 000000000..d43b77159 --- /dev/null +++ b/src/uu/split/split.md @@ -0,0 +1,11 @@ +# split + +``` +split [OPTION]... [INPUT [PREFIX]] +``` + +Create output files containing consecutive or interleaved sections of input + +## After Help + +Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is -, read standard input. diff --git a/src/uu/split/src/split.rs b/src/uu/split/src/split.rs index d737c8513..f09a6517f 100644 --- a/src/uu/split/src/split.rs +++ b/src/uu/split/src/split.rs @@ -23,7 +23,7 @@ use std::io::{stdin, BufRead, BufReader, BufWriter, ErrorKind, Read, Write}; use std::path::Path; use uucore::display::Quotable; use uucore::error::{FromIo, UIoError, UResult, USimpleError, UUsageError}; -use uucore::format_usage; +use uucore::{format_usage, help_about, help_usage, help_section}; use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::uio_error; @@ -47,11 +47,9 @@ static OPT_ELIDE_EMPTY_FILES: &str = "elide-empty-files"; static ARG_INPUT: &str = "input"; static ARG_PREFIX: &str = "prefix"; -const USAGE: &str = "{} [OPTION]... [INPUT [PREFIX]]"; -const AFTER_HELP: &str = "\ - Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default \ - size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is \ - -, read standard input."; +const ABOUT: &str = help_about!("split.md"); +const USAGE: &str = help_usage!("split.md"); +const AFTER_HELP: &str = help_section!("after help", "split.md"); #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { @@ -66,7 +64,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) - .about("Create output files containing consecutive or interleaved sections of input") + .about(ABOUT) .after_help(AFTER_HELP) .override_usage(format_usage(USAGE)) .infer_long_args(true) From 869614d343cde2d4c8a3aa03f63e56a2954ea520 Mon Sep 17 00:00:00 2001 From: m11o Date: Tue, 25 Apr 2023 22:01:10 +0900 Subject: [PATCH 14/40] fix cargo fmt --- 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 f09a6517f..2bf62e39e 100644 --- a/src/uu/split/src/split.rs +++ b/src/uu/split/src/split.rs @@ -23,9 +23,9 @@ use std::io::{stdin, BufRead, BufReader, BufWriter, ErrorKind, Read, Write}; use std::path::Path; use uucore::display::Quotable; use uucore::error::{FromIo, UIoError, UResult, USimpleError, UUsageError}; -use uucore::{format_usage, help_about, help_usage, help_section}; use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::uio_error; +use uucore::{format_usage, help_about, help_section, help_usage}; static OPT_BYTES: &str = "bytes"; static OPT_LINE_BYTES: &str = "line-bytes"; From 0b84aa52f327b4290296ef63724bfc868e30417e Mon Sep 17 00:00:00 2001 From: m11o Date: Tue, 25 Apr 2023 22:26:47 +0900 Subject: [PATCH 15/40] fix check-spell --- src/uu/split/split.md | 2 ++ src/uu/split/src/split.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/uu/split/split.md b/src/uu/split/split.md index d43b77159..d3a481fd3 100644 --- a/src/uu/split/split.md +++ b/src/uu/split/split.md @@ -1,3 +1,5 @@ + + # split ``` diff --git a/src/uu/split/src/split.rs b/src/uu/split/src/split.rs index 2bf62e39e..6e29e6f4b 100644 --- a/src/uu/split/src/split.rs +++ b/src/uu/split/src/split.rs @@ -5,7 +5,7 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -// spell-checker:ignore (ToDO) PREFIXaa PREFIXab nbbbb ncccc +// spell-checker:ignore nbbbb ncccc mod filenames; mod number; From 12686c478e7eff788289227bfc70f9f9ffd192d1 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 25 Apr 2023 05:22:49 -0700 Subject: [PATCH 16/40] Avoid spurious failures in the presence of non-zero default nice Make `test_get_current_niceness` query the libc nice value instead of hard-coding a value of zero. This avoids a spurious failure on systems which have a non-zero default nice value. This fixes spurious failures on my machine. --- tests/by-util/test_nice.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/by-util/test_nice.rs b/tests/by-util/test_nice.rs index e2af88dfd..4e8d5a2ee 100644 --- a/tests/by-util/test_nice.rs +++ b/tests/by-util/test_nice.rs @@ -1,11 +1,14 @@ +// spell-checker:ignore libc's use crate::common::util::TestScenario; #[test] #[cfg(not(target_os = "android"))] fn test_get_current_niceness() { - // NOTE: this assumes the test suite is being run with a default niceness - // of 0, which may not necessarily be true - new_ucmd!().run().stdout_is("0\n"); + // Test that the nice command with no arguments returns the default nice + // value, which we determine by querying libc's `nice` in our own process. + new_ucmd!() + .run() + .stdout_is(format!("{}\n", unsafe { libc::nice(0) })); } #[test] From d4630c83b4aec9e3b122f2a486c4b99299d21ddd Mon Sep 17 00:00:00 2001 From: John Shin Date: Tue, 25 Apr 2023 21:27:52 -0700 Subject: [PATCH 17/40] mv: add 'renamed ' in the beginning when verbose flag is set --- src/uu/mv/src/mv.rs | 4 ++-- tests/by-util/test_mv.rs | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index d0a1a766f..b79c43ad3 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -455,12 +455,12 @@ fn rename( if b.verbose { let message = match backup_path { Some(path) => format!( - "{} -> {} (backup: {})", + "renamed {} -> {} (backup: {})", from.quote(), to.quote(), path.quote() ), - None => format!("{} -> {}", from.quote(), to.quote()), + None => format!("renamed {} -> {}", from.quote(), to.quote()), }; match multi_progress { diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index 034234107..e4064e68a 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -745,7 +745,9 @@ fn test_mv_backup_dir() { .arg(dir_a) .arg(dir_b) .succeeds() - .stdout_only(format!("'{dir_a}' -> '{dir_b}' (backup: '{dir_b}~')\n")); + .stdout_only(format!( + "renamed '{dir_a}' -> '{dir_b}' (backup: '{dir_b}~')\n" + )); assert!(!at.dir_exists(dir_a)); assert!(at.dir_exists(dir_b)); @@ -817,7 +819,7 @@ fn test_mv_verbose() { .arg(file_a) .arg(file_b) .succeeds() - .stdout_only(format!("'{file_a}' -> '{file_b}'\n")); + .stdout_only(format!("renamed '{file_a}' -> '{file_b}'\n")); at.touch(file_a); scene @@ -826,7 +828,9 @@ fn test_mv_verbose() { .arg(file_a) .arg(file_b) .succeeds() - .stdout_only(format!("'{file_a}' -> '{file_b}' (backup: '{file_b}~')\n")); + .stdout_only(format!( + "renamed '{file_a}' -> '{file_b}' (backup: '{file_b}~')\n" + )); } #[test] From 31578ea18da3b65ac40b43883bf0ef487d15959b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Apr 2023 04:41:44 +0000 Subject: [PATCH 18/40] chore(deps): update davidanson/markdownlint-cli2-action action to v10 --- .github/workflows/CICD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 32fd30536..efbafcc7f 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -331,7 +331,7 @@ jobs: shell: bash run: | RUSTDOCFLAGS="-Dwarnings" cargo doc ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-deps --workspace --document-private-items - - uses: DavidAnson/markdownlint-cli2-action@v9 + - uses: DavidAnson/markdownlint-cli2-action@v10 with: command: fix globs: | From 583a247d9dab9c4afef34d70c4e3f6bac5890d85 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 26 Apr 2023 08:48:02 +0200 Subject: [PATCH 19/40] Improve the date md page --- src/uu/date/date-usage.mkd | 119 ++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 55 deletions(-) diff --git a/src/uu/date/date-usage.mkd b/src/uu/date/date-usage.mkd index 829001095..5489028e4 100644 --- a/src/uu/date/date-usage.mkd +++ b/src/uu/date/date-usage.mkd @@ -2,64 +2,65 @@ -``` text FORMAT controls the output. Interpreted sequences are: - %% a literal % - %a locale's abbreviated weekday name (e.g., Sun) - %A locale's full weekday name (e.g., Sunday) - %b locale's abbreviated month name (e.g., Jan) - %B locale's full month name (e.g., January) - %c locale's date and time (e.g., Thu Mar 3 23:05:25 2005) - %C century; like %Y, except omit last two digits (e.g., 20) - %d day of month (e.g., 01) - %D date; same as %m/%d/%y - %e day of month, space padded; same as %_d - %F full date; same as %Y-%m-%d - %g last two digits of year of ISO week number (see %G) - %G year of ISO week number (see %V); normally useful only with %V - %h same as %b - %H hour (00..23) - %I hour (01..12) - %j day of year (001..366) - %k hour, space padded ( 0..23); same as %_H - %l hour, space padded ( 1..12); same as %_I - %m month (01..12) - %M minute (00..59) - %n a newline - %N nanoseconds (000000000..999999999) - %p locale's equivalent of either AM or PM; blank if not known - %P like %p, but lower case - %q quarter of year (1..4) - %r locale's 12-hour clock time (e.g., 11:11:04 PM) - %R 24-hour hour and minute; same as %H:%M - %s seconds since 1970-01-01 00:00:00 UTC - %S second (00..60) - %t a tab - %T time; same as %H:%M:%S - %u day of week (1..7); 1 is Monday - %U week number of year, with Sunday as first day of week (00..53) - %V ISO week number, with Monday as first day of week (01..53) - %w day of week (0..6); 0 is Sunday - %W week number of year, with Monday as first day of week (00..53) - %x locale's date representation (e.g., 12/31/99) - %X locale's time representation (e.g., 23:13:48) - %y last two digits of year (00..99) - %Y year - %z +hhmm numeric time zone (e.g., -0400) - %:z +hh:mm numeric time zone (e.g., -04:00) - %::z +hh:mm:ss numeric time zone (e.g., -04:00:00) - %:::z numeric time zone with : to necessary precision (e.g., -04, +05:30) - %Z alphabetic time zone abbreviation (e.g., EDT) +| Sequence | Description | Example | +| -------- | -------------------------------------------------------------------- | ---------------------- | +| %% | a literal % | % | +| %a | locale's abbreviated weekday name | Sun | +| %A | locale's full weekday name | Sunday | +| %b | locale's abbreviated month name | Jan | +| %B | locale's full month name | January | +| %c | locale's date and time | Thu Mar 3 23:05:25 2005| +| %C | century; like %Y, except omit last two digits | 20 | +| %d | day of month | 01 | +| %D | date; same as %m/%d/%y | 12/31/99 | +| %e | day of month, space padded; same as %_d | 3 | +| %F | full date; same as %Y-%m-%d | 2005-03-03 | +| %g | last two digits of year of ISO week number (see %G) | 05 | +| %G | year of ISO week number (see %V); normally useful only with %V | 2005 | +| %h | same as %b | Jan | +| %H | hour (00..23) | 23 | +| %I | hour (01..12) | 11 | +| %j | day of year (001..366) | 062 | +| %k | hour, space padded ( 0..23); same as %_H | 3 | +| %l | hour, space padded ( 1..12); same as %_I | 9 | +| %m | month (01..12) | 03 | +| %M | minute (00..59) | 30 | +| %n | a newline | \n | +| %N | nanoseconds (000000000..999999999) | 123456789 | +| %p | locale's equivalent of either AM or PM; blank if not known | PM | +| %P | like %p, but lower case | pm | +| %q | quarter of year (1..4) | 1 | +| %r | locale's 12-hour clock time | 11:11:04 PM | +| %R | 24-hour hour and minute; same as %H:%M | 23:30 | +| %s | seconds since 1970-01-01 00:00:00 UTC | 1615432800 | +| %S | second (00..60) | 30 | +| %t | a tab | \t | +| %T | time; same as %H:%M:%S | 23:30:30 | +| %u | day of week (1..7); 1 is Monday | 4 | +| %U | week number of year, with Sunday as first day of week (00..53) | 10 | +| %V | ISO week number, with Monday as first day of week (01..53) | 12 | +| %w | day of week (0..6); 0 is Sunday | 4 | +| %W | week number of year, with Monday as first day of week (00..53) | 11 | +| %x | locale's date representation (e.g., 12/31/99) | 03/03/2005 | +| %X | locale's time representation (e.g., 23:13:48) | 23:30:30 | +| %y | last two digits of year (00..99) | 05 | +| %Y | year | 2005 | +| %z | +hhmm numeric time zone (e.g., -0400) | -0400 | +| %:z | +hh:mm numeric time zone (e.g., -04:00) | -04:00 | +| %::z | +hh:mm:ss numeric time zone (e.g., -04:00:00) | -04:00:00 | +| %:::z | numeric time zone with : to necessary precision (e.g., -04, +05:30) | -04 | +| %Z | alphabetic time zone abbreviation (e.g., EDT) | EDT | By default, date pads numeric fields with zeroes. The following optional flags may follow '%': - - (hyphen) do not pad the field - _ (underscore) pad with spaces - 0 (zero) pad with zeros - ^ use upper case if possible - # use opposite case if possible +* `-` (hyphen) do not pad the field +* `_` (underscore) pad with spaces +* `0` (zero) pad with zeros +* `^` use upper case if possible +* `#` use opposite case if possible After any flags comes an optional field width, as a decimal number; then an optional modifier, which is either @@ -68,11 +69,19 @@ O to use the locale's alternate numeric symbols if available. Examples: Convert seconds since the epoch (1970-01-01 UTC) to a date - $ date --date='@2147483647' + +``` +date --date='@2147483647' +``` Show the time on the west coast of the US (use tzselect(1) to find TZ) - $ TZ='America/Los_Angeles' date + +``` +TZ='America/Los_Angeles' date +``` Show the local time for 9AM next Friday on the west coast of the US - $ date --date='TZ="America/Los_Angeles" 09:00 next Fri' + +``` +date --date='TZ="America/Los_Angeles" 09:00 next Fri' ``` From 9b67ad05b842cc71d8dbc787a11c7c98bd9fc6c3 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 26 Apr 2023 10:38:39 +0200 Subject: [PATCH 20/40] build-gnu.sh: always update PATH in Makefile --- util/build-gnu.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 486cf3227..2e089dcf9 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -63,6 +63,8 @@ for binary in $(./build-aux/gen-lists-of-programs.sh --list-progs); do done if test -f gnu-built; then + # Change the PATH in the Makefile to test the uutils coreutils instead of the GNU coreutils + sed -i "s/^[[:blank:]]*PATH=.*/ PATH='${UU_BUILD_DIR//\//\\/}\$(PATH_SEPARATOR)'\"\$\$PATH\" \\\/" Makefile echo "GNU build already found. Skip" echo "'rm -f $(pwd)/gnu-built' to force the build" echo "Note: the customization of the tests will still happen" From eb45666bb64d1e0f37b6f7682cb0940ca759f3d8 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 26 Apr 2023 10:40:27 +0200 Subject: [PATCH 21/40] docs: mention UU_MAKE_PROFILE in CONTRIBUTING.md --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f66b2bba..7dc2565c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -217,6 +217,8 @@ To run uutils against the GNU test suite locally, run the following commands: ```shell bash util/build-gnu.sh +# Build uutils without release optimizations +UU_MAKE_PROFILE=debug bash util/build-gnu.sh bash util/run-gnu-test.sh # To run a single test: bash util/run-gnu-test.sh tests/touch/not-owner.sh # for example From aeeb3c90cf803dbf547424fad5154cb1d6345e83 Mon Sep 17 00:00:00 2001 From: John Shin Date: Wed, 26 Apr 2023 09:47:03 -0700 Subject: [PATCH 22/40] mv: check if --target is a directory --- src/uu/mv/src/error.rs | 4 +++- src/uu/mv/src/mv.rs | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/uu/mv/src/error.rs b/src/uu/mv/src/error.rs index 103c1116a..7810c3a95 100644 --- a/src/uu/mv/src/error.rs +++ b/src/uu/mv/src/error.rs @@ -15,6 +15,7 @@ pub enum MvError { DirectoryToNonDirectory(String), NonDirectoryToDirectory(String, String), NotADirectory(String), + TargetNotADirectory(String), } impl Error for MvError {} @@ -34,7 +35,8 @@ impl Display for MvError { Self::NonDirectoryToDirectory(s, t) => { write!(f, "cannot overwrite non-directory {t} with directory {s}") } - Self::NotADirectory(t) => write!(f, "target {t} is not a directory"), + Self::NotADirectory(t) => write!(f, "target {t}: Not a directory"), + Self::TargetNotADirectory(t) => write!(f, "target directory {t}: Not a directory"), } } } diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index d0a1a766f..53446dd8a 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -320,7 +320,12 @@ fn exec(files: &[OsString], b: &Behavior) -> UResult<()> { fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UResult<()> { if !target_dir.is_dir() { - return Err(MvError::NotADirectory(target_dir.quote().to_string()).into()); + match b.target_dir { + Some(_) => { + return Err(MvError::TargetNotADirectory(target_dir.quote().to_string()).into()) + } + None => return Err(MvError::NotADirectory(target_dir.quote().to_string()).into()), + } } let canonized_target_dir = target_dir From 825d240ef052f4d95b83c22783c76074a3db7233 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 26 Apr 2023 00:11:11 +0200 Subject: [PATCH 23/40] date -d supports - 1 year ago, 2 second, etc --- Cargo.lock | 2 ++ src/uu/date/Cargo.toml | 4 ++++ src/uu/date/src/date.rs | 21 ++++++++++++++++++--- tests/by-util/test_date.rs | 23 +++++++++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90af50e20..a74acc33a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2538,7 +2538,9 @@ version = "0.0.18" dependencies = [ "chrono", "clap", + "humantime_to_duration", "libc", + "time", "uucore", "windows-sys 0.45.0", ] diff --git a/src/uu/date/Cargo.toml b/src/uu/date/Cargo.toml index fab98f20d..923ca4aa7 100644 --- a/src/uu/date/Cargo.toml +++ b/src/uu/date/Cargo.toml @@ -1,3 +1,4 @@ +# spell-checker:ignore humantime [package] name = "uu_date" version = "0.0.18" @@ -16,8 +17,11 @@ path = "src/date.rs" [dependencies] chrono = { workspace=true } +#/ TODO: check if we can avoid chrono+time +time = { workspace=true } clap = { workspace=true } uucore = { workspace=true } +humantime_to_duration = { workspace=true } [target.'cfg(unix)'.dependencies] libc = { workspace=true } diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index ab874cb32..8b4338620 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -6,10 +6,10 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes +// spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes humantime use chrono::format::{Item, StrftimeItems}; -use chrono::{DateTime, FixedOffset, Local, Offset, Utc}; +use chrono::{DateTime, Duration as ChronoDuration, FixedOffset, Local, Offset, Utc}; #[cfg(windows)] use chrono::{Datelike, Timelike}; use clap::{crate_version, Arg, ArgAction, Command}; @@ -18,6 +18,7 @@ use libc::{clock_settime, timespec, CLOCK_REALTIME}; use std::fs::File; use std::io::{BufRead, BufReader}; use std::path::PathBuf; +use time::Duration; use uucore::display::Quotable; #[cfg(not(any(target_os = "redox")))] use uucore::error::FromIo; @@ -96,6 +97,7 @@ enum DateSource { Now, Custom(String), File(PathBuf), + Human(Duration), } enum Iso8601Format { @@ -168,7 +170,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; let date_source = if let Some(date) = matches.get_one::(OPT_DATE) { - DateSource::Custom(date.into()) + if let Ok(duration) = humantime_to_duration::from_str(date.as_str()) { + DateSource::Human(duration) + } else { + DateSource::Custom(date.into()) + } } else if let Some(file) = matches.get_one::(OPT_FILE) { DateSource::File(file.into()) } else { @@ -219,6 +225,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let iter = std::iter::once(date); Box::new(iter) } + DateSource::Human(ref input) => { + // Get the current DateTime and convert the input time::Duration to chrono::Duration + // for things like "1 year ago" + let current_time = DateTime::::from(Local::now()); + let input_chrono = ChronoDuration::seconds(input.as_seconds_f32() as i64) + + ChronoDuration::nanoseconds(input.subsec_nanoseconds() as i64); + let iter = std::iter::once(Ok(current_time + input_chrono)); + Box::new(iter) + } DateSource::File(ref path) => { if path.is_dir() { return Err(USimpleError::new( diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index a1bdda651..edad87bd6 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -334,6 +334,29 @@ fn test_invalid_format_string() { assert!(result.stderr_str().starts_with("date: invalid format ")); } +#[test] +fn test_date_string_human() { + let date_formats = vec![ + "1 year ago", + "1 year", + "2 months ago", + "15 days ago", + "1 week ago", + "5 hours ago", + "30 minutes ago", + "10 seconds", + ]; + let re = Regex::new(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}\n$").unwrap(); + for date_format in date_formats { + new_ucmd!() + .arg("-d") + .arg(date_format) + .arg("+%Y-%m-%d %S:%M") + .succeeds() + .stdout_matches(&re); + } +} + #[test] fn test_invalid_date_string() { new_ucmd!() From 111723aa84b4b1b5f6ae81f71cbc1770e581210f Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 26 Apr 2023 22:43:48 +0200 Subject: [PATCH 24/40] rename date-usage.mkd => date-usage.md --- src/uu/date/{date-usage.mkd => date-usage.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/uu/date/{date-usage.mkd => date-usage.md} (100%) diff --git a/src/uu/date/date-usage.mkd b/src/uu/date/date-usage.md similarity index 100% rename from src/uu/date/date-usage.mkd rename to src/uu/date/date-usage.md From 746331cc651e507b2edda362ca5f89cd5b87a6b8 Mon Sep 17 00:00:00 2001 From: Masahito Osako <43847020+m11o@users.noreply.github.com> Date: Thu, 27 Apr 2023 15:13:46 +0900 Subject: [PATCH 25/40] stdbuf: move help strings to markdown file (#4792) --- src/uu/stdbuf/src/stdbuf.rs | 20 ++++---------------- src/uu/stdbuf/stdbuf.md | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 src/uu/stdbuf/stdbuf.md diff --git a/src/uu/stdbuf/src/stdbuf.rs b/src/uu/stdbuf/src/stdbuf.rs index 2bfb6f908..e02dd28bc 100644 --- a/src/uu/stdbuf/src/stdbuf.rs +++ b/src/uu/stdbuf/src/stdbuf.rs @@ -17,23 +17,11 @@ use tempfile::tempdir; use tempfile::TempDir; use uucore::error::{FromIo, UResult, USimpleError, UUsageError}; use uucore::parse_size::parse_size; -use uucore::{crash, format_usage}; +use uucore::{crash, format_usage, help_about, help_section, help_usage}; -static ABOUT: &str = - "Run COMMAND, with modified buffering operations for its standard streams.\n\n\ - Mandatory arguments to long options are mandatory for short options too."; -const USAGE: &str = "{} OPTION... COMMAND"; -static LONG_HELP: &str = "If MODE is 'L' the corresponding stream will be line buffered.\n\ - This option is invalid with standard input.\n\n\ - If MODE is '0' the corresponding stream will be unbuffered.\n\n\ - Otherwise MODE is a number which may be followed by one of the following:\n\n\ - KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.\n\ - In this case the corresponding stream will be fully buffered with the buffer size set to \ - MODE bytes.\n\n\ - NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for e.g.) then \ - that will override corresponding settings changed by 'stdbuf'.\n\ - Also some filters (like 'dd' and 'cat' etc.) don't use streams for I/O, \ - and are thus unaffected by 'stdbuf' settings.\n"; +const ABOUT: &str = help_about!("stdbuf.md"); +const USAGE: &str = help_usage!("stdbuf.md"); +const LONG_HELP: &str = help_section!("after help", "stdbuf.md"); mod options { pub const INPUT: &str = "input"; diff --git a/src/uu/stdbuf/stdbuf.md b/src/uu/stdbuf/stdbuf.md new file mode 100644 index 000000000..e0062e627 --- /dev/null +++ b/src/uu/stdbuf/stdbuf.md @@ -0,0 +1,24 @@ +# stdbuf + +``` +stdbuf [OPTION]... COMMAND +``` + +Run `COMMAND`, with modified buffering operations for its standard streams. + +Mandatory arguments to long options are mandatory for short options too. + +## After Help + +If `MODE` is 'L' the corresponding stream will be line buffered. +This option is invalid with standard input. + +If `MODE` is '0' the corresponding stream will be unbuffered. + +Otherwise, `MODE` is a number which may be followed by one of the following: + +KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y. +In this case the corresponding stream will be fully buffered with the buffer size set to `MODE` bytes. + +NOTE: If `COMMAND` adjusts the buffering of its standard streams (`tee` does for e.g.) then that will override corresponding settings changed by `stdbuf`. +Also some filters (like `dd` and `cat` etc.) don't use streams for I/O, and are thus unaffected by `stdbuf` settings. From eb8f353a2ffb9671f729d9773173e7f890028b32 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Thu, 27 Apr 2023 09:17:39 +0200 Subject: [PATCH 26/40] date usage help: Remove the examples in the description table we have a new column with examples --- src/uu/date/date-usage.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/uu/date/date-usage.md b/src/uu/date/date-usage.md index 5489028e4..bf2dc469d 100644 --- a/src/uu/date/date-usage.md +++ b/src/uu/date/date-usage.md @@ -43,15 +43,15 @@ FORMAT controls the output. Interpreted sequences are: | %V | ISO week number, with Monday as first day of week (01..53) | 12 | | %w | day of week (0..6); 0 is Sunday | 4 | | %W | week number of year, with Monday as first day of week (00..53) | 11 | -| %x | locale's date representation (e.g., 12/31/99) | 03/03/2005 | -| %X | locale's time representation (e.g., 23:13:48) | 23:30:30 | +| %x | locale's date representation | 03/03/2005 | +| %X | locale's time representation | 23:30:30 | | %y | last two digits of year (00..99) | 05 | | %Y | year | 2005 | -| %z | +hhmm numeric time zone (e.g., -0400) | -0400 | -| %:z | +hh:mm numeric time zone (e.g., -04:00) | -04:00 | -| %::z | +hh:mm:ss numeric time zone (e.g., -04:00:00) | -04:00:00 | -| %:::z | numeric time zone with : to necessary precision (e.g., -04, +05:30) | -04 | -| %Z | alphabetic time zone abbreviation (e.g., EDT) | EDT | +| %z | +hhmm numeric time zone | -0400 | +| %:z | +hh:mm numeric time zone | -04:00 | +| %::z | +hh:mm:ss numeric time zone | -04:00:00 | +| %:::z | numeric time zone with : to necessary precision | -04, +05:30 | +| %Z | alphabetic time zone abbreviation | EDT | By default, date pads numeric fields with zeroes. The following optional flags may follow '%': From c49769865a1e9b894880a6904a20009dace84c50 Mon Sep 17 00:00:00 2001 From: m11o Date: Thu, 27 Apr 2023 22:14:52 +0900 Subject: [PATCH 27/40] stty: move help strings to markdown file --- src/uu/stty/src/stty.rs | 9 +++------ src/uu/stty/stty.md | 9 +++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 src/uu/stty/stty.md diff --git a/src/uu/stty/src/stty.rs b/src/uu/stty/src/stty.rs index 928c3f177..19340830d 100644 --- a/src/uu/stty/src/stty.rs +++ b/src/uu/stty/src/stty.rs @@ -18,7 +18,7 @@ use std::ops::ControlFlow; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; use uucore::error::{UResult, USimpleError}; -use uucore::format_usage; +use uucore::{format_usage, help_usage, help_about}; #[cfg(not(any( target_os = "freebsd", @@ -31,11 +31,8 @@ use uucore::format_usage; use flags::BAUD_RATES; use flags::{CONTROL_FLAGS, INPUT_FLAGS, LOCAL_FLAGS, OUTPUT_FLAGS}; -const USAGE: &str = "\ - {} [-F DEVICE | --file=DEVICE] [SETTING]... - {} [-F DEVICE | --file=DEVICE] [-a|--all] - {} [-F DEVICE | --file=DEVICE] [-g|--save]"; -const SUMMARY: &str = "Print or change terminal characteristics."; +const USAGE: &str = help_usage!("stty.md"); +const SUMMARY: &str = help_about!("stty.md"); #[derive(Clone, Copy, Debug)] pub struct Flag { diff --git a/src/uu/stty/stty.md b/src/uu/stty/stty.md new file mode 100644 index 000000000..6aa1decf5 --- /dev/null +++ b/src/uu/stty/stty.md @@ -0,0 +1,9 @@ +# stty + +``` +stty [-F DEVICE | --file=DEVICE] [SETTING]... +stty [-F DEVICE | --file=DEVICE] [-a|--all] +stty [-F DEVICE | --file=DEVICE] [-g|--save] +``` + +Print or change terminal characteristics. From 0391239273d1ec98c64330df84095ab4e5fb21f9 Mon Sep 17 00:00:00 2001 From: m11o Date: Thu, 27 Apr 2023 22:17:37 +0900 Subject: [PATCH 28/40] fix cargo fmt --- src/uu/stty/src/stty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/stty/src/stty.rs b/src/uu/stty/src/stty.rs index 19340830d..e09662471 100644 --- a/src/uu/stty/src/stty.rs +++ b/src/uu/stty/src/stty.rs @@ -18,7 +18,7 @@ use std::ops::ControlFlow; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; use uucore::error::{UResult, USimpleError}; -use uucore::{format_usage, help_usage, help_about}; +use uucore::{format_usage, help_about, help_usage}; #[cfg(not(any( target_os = "freebsd", From 467cbf30dee78ad967ae33513c6c0b7e5ea19134 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Wed, 26 Apr 2023 14:22:35 +0300 Subject: [PATCH 29/40] [tests/ls] Support user names containing dots - Fix regex's in tests for `ls -l` --- tests/by-util/test_ls.rs | 91 +++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 0779a2885..84efb9daa 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -1276,7 +1276,7 @@ fn test_ls_long_formats() { // Zero or one "." for indicating a file with security context // Regex for three names, so all of author, group and owner - let re_three = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z_A-Z]+ ){3}0").unwrap(); + let re_three = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z.A-Z]+ ){3}0").unwrap(); #[cfg(unix)] let re_three_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){3}0").unwrap(); @@ -1285,13 +1285,13 @@ fn test_ls_long_formats() { // - group and owner // - author and owner // - author and group - let re_two = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z_A-Z]+ ){2}0").unwrap(); + let re_two = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z.A-Z]+ ){2}0").unwrap(); #[cfg(unix)] let re_two_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){2}0").unwrap(); // Regex for one name: author, group or owner - let re_one = Regex::new(r"[xrw-]{9}\.? \d [-0-9_a-z_A-Z]+ 0").unwrap(); + let re_one = Regex::new(r"[xrw-]{9}\.? \d [-0-9_a-z.A-Z]+ 0").unwrap(); #[cfg(unix)] let re_one_num = Regex::new(r"[xrw-]{9}\.? \d \d+ 0").unwrap(); @@ -1640,88 +1640,103 @@ fn test_ls_styles() { at.touch("test"); let re_full = Regex::new( - r"[a-z-]* \d* \w* \w* \d* \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d* (\+|\-)\d{4} test\n", + r"[a-z-]* \d* [\w.]* [\w.]* \d* \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d* (\+|\-)\d{4} test\n", ) .unwrap(); let re_long = - Regex::new(r"[a-z-]* \d* \w* \w* \d* \d{4}-\d{2}-\d{2} \d{2}:\d{2} test\n").unwrap(); - let re_iso = Regex::new(r"[a-z-]* \d* \w* \w* \d* \d{2}-\d{2} \d{2}:\d{2} test\n").unwrap(); + Regex::new(r"[a-z-]* \d* [\w.]* [\w.]* \d* \d{4}-\d{2}-\d{2} \d{2}:\d{2} test\n").unwrap(); + let re_iso = + Regex::new(r"[a-z-]* \d* [\w.]* [\w.]* \d* \d{2}-\d{2} \d{2}:\d{2} test\n").unwrap(); let re_locale = - Regex::new(r"[a-z-]* \d* \w* \w* \d* [A-Z][a-z]{2} ( |\d)\d \d{2}:\d{2} test\n").unwrap(); - let re_custom_format = Regex::new(r"[a-z-]* \d* \w* \w* \d* \d{4}__\d{2} test\n").unwrap(); + Regex::new(r"[a-z-]* \d* [\w.]* [\w.]* \d* [A-Z][a-z]{2} ( |\d)\d \d{2}:\d{2} test\n") + .unwrap(); + let re_custom_format = + Regex::new(r"[a-z-]* \d* [\w.]* [\w.]* \d* \d{4}__\d{2} test\n").unwrap(); //full-iso - let result = scene + scene .ucmd() .arg("-l") .arg("--time-style=full-iso") - .succeeds(); - assert!(re_full.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_full); //long-iso - let result = scene + scene .ucmd() .arg("-l") .arg("--time-style=long-iso") - .succeeds(); - assert!(re_long.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_long); //iso - let result = scene.ucmd().arg("-l").arg("--time-style=iso").succeeds(); - assert!(re_iso.is_match(result.stdout_str())); + scene + .ucmd() + .arg("-l") + .arg("--time-style=iso") + .succeeds() + .stdout_matches(&re_iso); //locale - let result = scene.ucmd().arg("-l").arg("--time-style=locale").succeeds(); - assert!(re_locale.is_match(result.stdout_str())); + scene + .ucmd() + .arg("-l") + .arg("--time-style=locale") + .succeeds() + .stdout_matches(&re_locale); //+FORMAT - let result = scene + scene .ucmd() .arg("-l") .arg("--time-style=+%Y__%M") - .succeeds(); - assert!(re_custom_format.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_custom_format); // Also fails due to not having full clap support for time_styles scene.ucmd().arg("-l").arg("-time-style=invalid").fails(); //Overwrite options tests - let result = scene + scene .ucmd() .arg("-l") .arg("--time-style=long-iso") .arg("--time-style=iso") - .succeeds(); - assert!(re_iso.is_match(result.stdout_str())); - let result = scene + .succeeds() + .stdout_matches(&re_iso); + scene .ucmd() .arg("--time-style=iso") .arg("--full-time") - .succeeds(); - assert!(re_full.is_match(result.stdout_str())); - let result = scene + .succeeds() + .stdout_matches(&re_full); + scene .ucmd() .arg("--full-time") .arg("--time-style=iso") - .succeeds(); - assert!(re_iso.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_iso); - let result = scene + scene .ucmd() .arg("--full-time") .arg("--time-style=iso") .arg("--full-time") - .succeeds(); - assert!(re_full.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_full); - let result = scene + scene .ucmd() .arg("--full-time") .arg("-x") .arg("-l") - .succeeds(); - assert!(re_full.is_match(result.stdout_str())); + .succeeds() + .stdout_matches(&re_full); at.touch("test2"); - let result = scene.ucmd().arg("--full-time").arg("-x").succeeds(); - assert_eq!(result.stdout_str(), "test test2\n"); + scene + .ucmd() + .arg("--full-time") + .arg("-x") + .succeeds() + .stdout_is("test test2\n"); } #[test] From a93bccb5b93d1fb1adb5e032f95d9c4c25c72155 Mon Sep 17 00:00:00 2001 From: John Shin Date: Thu, 27 Apr 2023 15:35:21 -0700 Subject: [PATCH 30/40] mv: add tests for --target --- tests/by-util/test_mv.rs | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index 034234107..3b5aa3ee3 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -55,6 +55,63 @@ fn test_mv_move_file_into_dir() { assert!(at.file_exists(format!("{dir}/{file}"))); } +#[test] +fn test_mv_move_file_into_dir_with_target_arg() { + let (at, mut ucmd) = at_and_ucmd!(); + let dir = "test_mv_move_file_into_dir_with_target_arg_dir"; + let file = "test_mv_move_file_into_dir_with_target_arg_file"; + + at.mkdir(dir); + at.touch(file); + + ucmd.arg("--target") + .arg(dir) + .arg(file) + .succeeds() + .no_stderr(); + + assert!(at.file_exists(format!("{dir}/{file}"))) +} + +#[test] +fn test_mv_move_file_into_file_with_target_arg() { + let (at, mut ucmd) = at_and_ucmd!(); + let file1 = "test_mv_move_file_into_file_with_target_arg_file1"; + let file2 = "test_mv_move_file_into_file_with_target_arg_file2"; + + at.touch(file1); + at.touch(file2); + + ucmd.arg("--target") + .arg(file1) + .arg(file2) + .fails() + .stderr_is(format!("mv: target directory '{file1}': Not a directory\n")); + + assert!(at.file_exists(file1)) +} + +#[test] +fn test_mv_move_multiple_files_into_file() { + let (at, mut ucmd) = at_and_ucmd!(); + let file1 = "test_mv_move_multiple_files_into_file1"; + let file2 = "test_mv_move_multiple_files_into_file2"; + let file3 = "test_mv_move_multiple_files_into_file3"; + + at.touch(file1); + at.touch(file2); + at.touch(file3); + + ucmd.arg(file1) + .arg(file2) + .arg(file3) + .fails() + .stderr_is(format!("mv: target '{file3}': Not a directory\n")); + + assert!(at.file_exists(file1)); + assert!(at.file_exists(file2)); +} + #[test] fn test_mv_move_file_between_dirs() { let (at, mut ucmd) = at_and_ucmd!(); From 3ca1fa8dfd207dffa209ea464f6e56dbf27149da Mon Sep 17 00:00:00 2001 From: m11o Date: Fri, 28 Apr 2023 20:21:44 +0900 Subject: [PATCH 31/40] sum: move help strings to markdown file --- src/uu/sum/src/sum.rs | 7 +++---- src/uu/sum/sum.md | 9 +++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 src/uu/sum/sum.md diff --git a/src/uu/sum/src/sum.rs b/src/uu/sum/src/sum.rs index 1134f2444..0ea415b13 100644 --- a/src/uu/sum/src/sum.rs +++ b/src/uu/sum/src/sum.rs @@ -13,11 +13,10 @@ use std::io::{stdin, Read}; use std::path::Path; use uucore::display::Quotable; use uucore::error::{FromIo, UResult, USimpleError}; -use uucore::{format_usage, show}; +use uucore::{format_usage, help_about, help_usage, show}; -static USAGE: &str = "{} [OPTION]... [FILE]..."; -static ABOUT: &str = "Checksum and count the blocks in a file.\n\n\ - With no FILE, or when FILE is -, read standard input."; +const USAGE: &str = help_usage!("sum.md"); +const ABOUT: &str = help_about!("sum.md"); // This can be replaced with usize::div_ceil once it is stabilized. // This implementation approach is optimized for when `b` is a constant, diff --git a/src/uu/sum/sum.md b/src/uu/sum/sum.md new file mode 100644 index 000000000..ca3adb81f --- /dev/null +++ b/src/uu/sum/sum.md @@ -0,0 +1,9 @@ +# sum + +``` +sum [OPTION]... [FILE]..." +``` + +Checksum and count the blocks in a file. + +With no FILE, or when FILE is -, read standard input. From c254900db92b994e2e6b038d4869ba0610dd3c79 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 22 Jun 2022 09:37:16 +0200 Subject: [PATCH 32/40] paste: handle list ending with unescaped backslash --- src/uu/paste/src/paste.rs | 14 +++++++++++--- tests/by-util/test_paste.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/uu/paste/src/paste.rs b/src/uu/paste/src/paste.rs index d7a4d325c..c8d807635 100644 --- a/src/uu/paste/src/paste.rs +++ b/src/uu/paste/src/paste.rs @@ -12,7 +12,7 @@ use std::fmt::Display; use std::fs::File; use std::io::{stdin, stdout, BufRead, BufReader, Read, Write}; use std::path::Path; -use uucore::error::{FromIo, UResult}; +use uucore::error::{FromIo, UResult, USimpleError}; use uucore::{format_usage, help_about, help_usage}; const ABOUT: &str = help_about!("paste.md"); @@ -129,6 +129,16 @@ fn paste( files.push(file); } + if delimiters.ends_with('\\') && !delimiters.ends_with("\\\\") { + return Err(USimpleError::new( + 1, + format!( + "delimiter list ends with an unescaped backslash: {}", + delimiters + ), + )); + } + let delimiters: Vec = unescape(delimiters).chars().collect(); let mut delim_count = 0; let mut delim_length = 1; @@ -222,10 +232,8 @@ fn paste( } // Unescape all special characters -// TODO: this will need work to conform to GNU implementation fn unescape(s: &str) -> String { s.replace("\\n", "\n") .replace("\\t", "\t") .replace("\\\\", "\\") - .replace('\\', "") } diff --git a/tests/by-util/test_paste.rs b/tests/by-util/test_paste.rs index 2e119846e..fa7ead335 100644 --- a/tests/by-util/test_paste.rs +++ b/tests/by-util/test_paste.rs @@ -156,6 +156,37 @@ fn test_multi_stdin() { } } +#[test] +fn test_delimiter_list_ending_with_escaped_backslash() { + for d in ["-d", "--delimiters"] { + let (at, mut ucmd) = at_and_ucmd!(); + let mut ins = vec![]; + for (i, _in) in ["a\n", "b\n"].iter().enumerate() { + let file = format!("in{}", i); + at.write(&file, _in); + ins.push(file); + } + ucmd.args(&[d, "\\\\"]) + .args(&ins) + .succeeds() + .stdout_is("a\\b\n"); + } +} + +#[test] +fn test_delimiter_list_ending_with_unescaped_backslash() { + for d in ["-d", "--delimiters"] { + new_ucmd!() + .args(&[d, "\\"]) + .fails() + .stderr_contains("delimiter list ends with an unescaped backslash: \\"); + new_ucmd!() + .args(&[d, "_\\"]) + .fails() + .stderr_contains("delimiter list ends with an unescaped backslash: _\\"); + } +} + #[test] fn test_data() { for example in EXAMPLE_DATA { From 736a00a85f7e7bc5823327bc8b413d2bcdaf3957 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 28 Apr 2023 15:08:01 +0200 Subject: [PATCH 33/40] paste: ignore failing test on Windows --- tests/by-util/test_paste.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/by-util/test_paste.rs b/tests/by-util/test_paste.rs index fa7ead335..da92daa32 100644 --- a/tests/by-util/test_paste.rs +++ b/tests/by-util/test_paste.rs @@ -157,6 +157,8 @@ fn test_multi_stdin() { } #[test] +// TODO: make this test work on Windows +#[cfg(not(windows))] fn test_delimiter_list_ending_with_escaped_backslash() { for d in ["-d", "--delimiters"] { let (at, mut ucmd) = at_and_ucmd!(); From ee3da4284c8ad844498f6b3314054f5f9321925b Mon Sep 17 00:00:00 2001 From: John Shin Date: Fri, 28 Apr 2023 18:39:41 -0700 Subject: [PATCH 34/40] mv: update gnu error message to match the one generated by clap --- util/build-gnu.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 486cf3227..9364961dc 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -220,6 +220,9 @@ sed -i -Ez "s/\n([^\n#]*pad-3\.2[^\n]*)\n([^\n]*)\n([^\n]*)/\n# uutils\/numfmt s # Update the GNU error message to match the one generated by clap sed -i -e "s/\$prog: multiple field specifications/error: The argument '--field ' was provided more than once, but cannot be used multiple times\n\nUsage: numfmt [OPTION]... [NUMBER]...\n\n\nFor more information try '--help'/g" tests/misc/numfmt.pl +sed -i -e "s/Try 'mv --help' for more information/For more information, try '--help'/g" tests/mv/diag.sh +sed -i -e "s/mv: missing file operand/error: the following required arguments were not provided:\n ...\n\nUsage: mv [OPTION]... [-T] SOURCE DEST\n mv [OPTION]... SOURCE... DIRECTORY\n mv [OPTION]... -t DIRECTORY SOURCE...\n/g" tests/mv/diag.sh +sed -i -e "s/mv: missing destination file operand after 'no-file'/error: The argument '...' requires at least 2 values, but only 1 was provided\n\nUsage: mv [OPTION]... [-T] SOURCE DEST\n mv [OPTION]... SOURCE... DIRECTORY\n mv [OPTION]... -t DIRECTORY SOURCE...\n/g" tests/mv/diag.sh # GNU doesn't support width > INT_MAX # disable these test cases From bc7a01dd3bfd20689026a76e2eb31bea5f875779 Mon Sep 17 00:00:00 2001 From: m11o Date: Sat, 29 Apr 2023 15:51:55 +0900 Subject: [PATCH 35/40] sync: move help strings to markdown file --- src/uu/sync/src/sync.rs | 7 ++++--- src/uu/sync/sync.md | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/uu/sync/sync.md diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index 120e31dfe..e12703bca 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -19,10 +19,11 @@ use uucore::display::Quotable; #[cfg(any(target_os = "linux", target_os = "android"))] use uucore::error::FromIo; use uucore::error::{UResult, USimpleError}; -use uucore::format_usage; +use uucore::{format_usage, help_about, help_usage}; + +const ABOUT: &str = help_about!("sync.md"); +const USAGE: &str = help_usage!("sync.md"); -static ABOUT: &str = "Synchronize cached writes to persistent storage"; -const USAGE: &str = "{} [OPTION]... FILE..."; pub mod options { pub static FILE_SYSTEM: &str = "file-system"; pub static DATA: &str = "data"; diff --git a/src/uu/sync/sync.md b/src/uu/sync/sync.md new file mode 100644 index 000000000..2fdd36339 --- /dev/null +++ b/src/uu/sync/sync.md @@ -0,0 +1,7 @@ +# sync + +``` +sync [OPTION]... FILE... +``` + +Synchronize cached writes to persistent storage From 5a77608ef94096fd33b8744e550b81aa2632d7cf Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 29 Apr 2023 09:48:05 +0200 Subject: [PATCH 36/40] move the declaration on a single line --- util/build-gnu.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 9364961dc..cc7dceedc 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -220,9 +220,7 @@ sed -i -Ez "s/\n([^\n#]*pad-3\.2[^\n]*)\n([^\n]*)\n([^\n]*)/\n# uutils\/numfmt s # Update the GNU error message to match the one generated by clap sed -i -e "s/\$prog: multiple field specifications/error: The argument '--field ' was provided more than once, but cannot be used multiple times\n\nUsage: numfmt [OPTION]... [NUMBER]...\n\n\nFor more information try '--help'/g" tests/misc/numfmt.pl -sed -i -e "s/Try 'mv --help' for more information/For more information, try '--help'/g" tests/mv/diag.sh -sed -i -e "s/mv: missing file operand/error: the following required arguments were not provided:\n ...\n\nUsage: mv [OPTION]... [-T] SOURCE DEST\n mv [OPTION]... SOURCE... DIRECTORY\n mv [OPTION]... -t DIRECTORY SOURCE...\n/g" tests/mv/diag.sh -sed -i -e "s/mv: missing destination file operand after 'no-file'/error: The argument '...' requires at least 2 values, but only 1 was provided\n\nUsage: mv [OPTION]... [-T] SOURCE DEST\n mv [OPTION]... SOURCE... DIRECTORY\n mv [OPTION]... -t DIRECTORY SOURCE...\n/g" tests/mv/diag.sh +sed -i -e "s/Try 'mv --help' for more information/For more information, try '--help'/g" -e "s/mv: missing file operand/error: the following required arguments were not provided:\n ...\n\nUsage: mv [OPTION]... [-T] SOURCE DEST\n mv [OPTION]... SOURCE... DIRECTORY\n mv [OPTION]... -t DIRECTORY SOURCE...\n/g" -e "s/mv: missing destination file operand after 'no-file'/error: The argument '...' requires at least 2 values, but only 1 was provided\n\nUsage: mv [OPTION]... [-T] SOURCE DEST\n mv [OPTION]... SOURCE... DIRECTORY\n mv [OPTION]... -t DIRECTORY SOURCE...\n/g" tests/mv/diag.sh # GNU doesn't support width > INT_MAX # disable these test cases From 7cfdbe676cc2d3665d4a00ed691a1e6d2a4f1d33 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sat, 29 Apr 2023 16:16:00 +0200 Subject: [PATCH 37/40] mv: validate --target arg --- src/uu/mv/src/mv.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index 7fcc70a57..d583a1338 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -106,14 +106,22 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let backup_suffix = backup_control::determine_backup_suffix(&matches); + let target_dir = matches + .get_one::(OPT_TARGET_DIRECTORY) + .map(OsString::from); + + if let Some(ref maybe_dir) = target_dir { + if !Path::new(&maybe_dir).is_dir() { + return Err(MvError::TargetNotADirectory(maybe_dir.quote().to_string()).into()); + } + } + let behavior = Behavior { overwrite: overwrite_mode, backup: backup_mode, suffix: backup_suffix, update: matches.get_flag(OPT_UPDATE), - target_dir: matches - .get_one::(OPT_TARGET_DIRECTORY) - .map(OsString::from), + target_dir, no_target_dir: matches.get_flag(OPT_NO_TARGET_DIRECTORY), verbose: matches.get_flag(OPT_VERBOSE), strip_slashes: matches.get_flag(OPT_STRIP_TRAILING_SLASHES), @@ -320,12 +328,7 @@ fn exec(files: &[OsString], b: &Behavior) -> UResult<()> { fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UResult<()> { if !target_dir.is_dir() { - match b.target_dir { - Some(_) => { - return Err(MvError::TargetNotADirectory(target_dir.quote().to_string()).into()) - } - None => return Err(MvError::NotADirectory(target_dir.quote().to_string()).into()), - } + return Err(MvError::NotADirectory(target_dir.quote().to_string()).into()); } let canonized_target_dir = target_dir From 22490ae978c58be9fe84f27662dfbbfa01309d48 Mon Sep 17 00:00:00 2001 From: iambasanta Date: Sun, 30 Apr 2023 10:32:58 +0545 Subject: [PATCH 38/40] tr: move help string to markdown file --- src/uu/tr/src/tr.rs | 12 +++++------- src/uu/tr/tr.md | 11 +++++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 src/uu/tr/tr.md diff --git a/src/uu/tr/src/tr.rs b/src/uu/tr/src/tr.rs index 8ccd08366..9abbca631 100644 --- a/src/uu/tr/src/tr.rs +++ b/src/uu/tr/src/tr.rs @@ -13,17 +13,15 @@ use clap::{crate_version, Arg, ArgAction, Command}; use nom::AsBytes; use operation::{translate_input, Sequence, SqueezeOperation, TranslateOperation}; use std::io::{stdin, stdout, BufReader, BufWriter}; -use uucore::{format_usage, show}; +use uucore::{format_usage, help_about, help_section, help_usage, show}; use crate::operation::DeleteOperation; use uucore::display::Quotable; use uucore::error::{UResult, USimpleError, UUsageError}; -const ABOUT: &str = "Translate or delete characters"; -const USAGE: &str = "{} [OPTION]... SET1 [SET2]"; -const LONG_USAGE: &str = "\ - Translate, squeeze, and/or delete characters from standard input, \ - writing to standard output."; +const ABOUT: &str = help_about!("tr.md"); +const AFTER_HELP: &str = help_section!("after help", "tr.md"); +const USAGE: &str = help_usage!("tr.md"); mod options { pub const COMPLEMENT: &str = "complement"; @@ -37,7 +35,7 @@ mod options { pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args.collect_lossy(); - let matches = uu_app().after_help(LONG_USAGE).try_get_matches_from(args)?; + let matches = uu_app().after_help(AFTER_HELP).try_get_matches_from(args)?; let delete_flag = matches.get_flag(options::DELETE); let complement_flag = matches.get_flag(options::COMPLEMENT); diff --git a/src/uu/tr/tr.md b/src/uu/tr/tr.md new file mode 100644 index 000000000..93349eeaa --- /dev/null +++ b/src/uu/tr/tr.md @@ -0,0 +1,11 @@ +# tr + +``` +tr [OPTION]... SET1 [SET2] +``` + +Translate or delete characters + +## After help + +Translate, squeeze, and/or delete characters from standard input, writing to standard output. From e46b05722f00031d5a21bc4e77de74176bfeac37 Mon Sep 17 00:00:00 2001 From: Masahito Osako <43847020+m11o@users.noreply.github.com> Date: Sun, 30 Apr 2023 15:51:14 +0900 Subject: [PATCH 39/40] timeout: move help strings to markdown file (#4806) * timeout: move help strings to markdown file --- src/uu/timeout/src/timeout.rs | 6 +++--- src/uu/timeout/timeout.md | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 src/uu/timeout/timeout.md diff --git a/src/uu/timeout/src/timeout.rs b/src/uu/timeout/src/timeout.rs index 153beea3d..531f29e82 100644 --- a/src/uu/timeout/src/timeout.rs +++ b/src/uu/timeout/src/timeout.rs @@ -22,12 +22,12 @@ use uucore::process::ChildExt; use uucore::signals::enable_pipe_errors; use uucore::{ - format_usage, show_error, + format_usage, help_about, help_usage, show_error, signals::{signal_by_name_or_value, signal_name_by_value}, }; -static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION."; -const USAGE: &str = "{} [OPTION] DURATION COMMAND..."; +const ABOUT: &str = help_about!("timeout.md"); +const USAGE: &str = help_usage!("timeout.md"); pub mod options { pub static FOREGROUND: &str = "foreground"; diff --git a/src/uu/timeout/timeout.md b/src/uu/timeout/timeout.md new file mode 100644 index 000000000..f992ab327 --- /dev/null +++ b/src/uu/timeout/timeout.md @@ -0,0 +1,7 @@ +# timeout + +``` +timeout [OPTION] DURATION COMMAND... +``` + +Start `COMMAND`, and kill it if still running after `DURATION`. From 70b69efadbe588f189afcc97c23d489a05dcb8dd Mon Sep 17 00:00:00 2001 From: iambasanta <68998545+iambasanta@users.noreply.github.com> Date: Sun, 30 Apr 2023 23:35:28 +0545 Subject: [PATCH 40/40] sort: Move help strings to markdown file (#4808) * sort: Move help strings to markdown file * Correction for spell check --- src/uu/sort/sort.md | 21 +++++++++++++++++++++ src/uu/sort/src/sort.rs | 21 +++++---------------- 2 files changed, 26 insertions(+), 16 deletions(-) create mode 100644 src/uu/sort/sort.md diff --git a/src/uu/sort/sort.md b/src/uu/sort/sort.md new file mode 100644 index 000000000..1d1aa5d5f --- /dev/null +++ b/src/uu/sort/sort.md @@ -0,0 +1,21 @@ + + +# sort + +``` +sort [OPTION]... [FILE]... +``` + +Display sorted concatenation of all FILE(s). With no FILE, or when FILE is -, read standard input. + +## After help + +The key format is `FIELD[.CHAR][OPTIONS][,FIELD[.CHAR]][OPTIONS]`. + +Fields by default are separated by the first whitespace after a non-whitespace character. Use `-t` to specify a custom separator. +In the default case, whitespace is appended at the beginning of each field. Custom separators however are not included in fields. + +`FIELD` and `CHAR` both start at 1 (i.e. they are 1-indexed). If there is no end specified after a comma, the end will be the end of the line. +If `CHAR` is set 0, it means the end of the field. `CHAR` defaults to 1 for the start position and to 0 for the end position. + +Valid options are: `MbdfhnRrV`. They override the global options for this key. diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 5b309e413..1744148f2 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -45,26 +45,15 @@ use std::str::Utf8Error; use unicode_width::UnicodeWidthStr; use uucore::display::Quotable; use uucore::error::{set_exit_code, strip_errno, UError, UResult, USimpleError, UUsageError}; -use uucore::format_usage; use uucore::parse_size::{ParseSizeError, Parser}; use uucore::version_cmp::version_cmp; +use uucore::{format_usage, help_about, help_section, help_usage}; use crate::tmp_dir::TmpDirWrapper; -const ABOUT: &str = "\ - Display sorted concatenation of all FILE(s). \ - With no FILE, or when FILE is -, read standard input."; -const USAGE: &str = "{} [OPTION]... [FILE]..."; - -const LONG_HELP_KEYS: &str = "The key format is FIELD[.CHAR][OPTIONS][,FIELD[.CHAR]][OPTIONS]. - -Fields by default are separated by the first whitespace after a non-whitespace character. Use -t to specify a custom separator. -In the default case, whitespace is appended at the beginning of each field. Custom separators however are not included in fields. - -FIELD and CHAR both start at 1 (i.e. they are 1-indexed). If there is no end specified after a comma, the end will be the end of the line. -If CHAR is set 0, it means the end of the field. CHAR defaults to 1 for the start position and to 0 for the end position. - -Valid options are: MbdfhnRrV. They override the global options for this key."; +const ABOUT: &str = help_about!("sort.md"); +const USAGE: &str = help_usage!("sort.md"); +const AFTER_HELP: &str = help_section!("after help", "sort.md"); mod options { pub mod modes { @@ -1292,7 +1281,7 @@ pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) - .after_help(LONG_HELP_KEYS) + .after_help(AFTER_HELP) .override_usage(format_usage(USAGE)) .infer_long_args(true) .disable_help_flag(true)