From 5ed527c890cb804ce3c4fb216322a3bf2d10b01e Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 5 Mar 2023 15:20:24 +0100 Subject: [PATCH 01/60] References the other implementations --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f2e5763a1..91bd54dea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -113,6 +113,22 @@ install it and then run with: cargo deny --all-features check all ``` +## Other implementations + +The Coreutils has different implementations, with different level of completions: + +* [GNU's](https://git.savannah.gnu.org/gitweb/?p=coreutils.git) +* [BSD](https://github.com/openbsd/src/tree/master/bin) +* [Busybox](https://github.com/mirror/busybox/tree/master/coreutils) +* [Toybox (Android)](https://github.com/landley/toybox/tree/master/toys/posix) +* [V lang](https://github.com/vlang/coreutils) +* [SerenityOS](https://github.com/SerenityOS/serenity/tree/master/Userland/Utilities) +* [Initial Unix](https://github.com/dspinellis/unix-history-repo) + +However, when reimplementing the tools/options in Rust, don't read at their source codes +when they are using reciprocal licenses. + + ## Licensing uutils is distributed under the terms of the MIT License; see the `LICENSE` file From 66295b923153763d17bb84c0a5bd600cc912a512 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 5 Mar 2023 15:50:56 +0100 Subject: [PATCH 02/60] Add examples of reciprocal licenses --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 91bd54dea..25f3f5a05 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -126,7 +126,7 @@ The Coreutils has different implementations, with different level of completions * [Initial Unix](https://github.com/dspinellis/unix-history-repo) However, when reimplementing the tools/options in Rust, don't read at their source codes -when they are using reciprocal licenses. +when they are using reciprocal licenses (ex: GNU GPL, GNU LGPL, etc). ## Licensing From 1494b80d96f8ffe032158ffb64dc999f681973e5 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 5 Mar 2023 16:16:53 +0100 Subject: [PATCH 03/60] Add "reimplementing toybox" to the ignore list --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 25f3f5a05..66f3168ed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,5 @@ + + # Contributing to coreutils Contributions are very welcome, and should target Rust's main branch until the From 40a816ce6e0b27d299977adc8d898bfc62c5e110 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 6 Mar 2023 18:03:00 +0100 Subject: [PATCH 04/60] Fix typos --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 66f3168ed..e1ff2238b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,7 +117,7 @@ cargo deny --all-features check all ## Other implementations -The Coreutils has different implementations, with different level of completions: +The Coreutils has different implementations, with different levels of completions: * [GNU's](https://git.savannah.gnu.org/gitweb/?p=coreutils.git) * [BSD](https://github.com/openbsd/src/tree/master/bin) @@ -127,7 +127,7 @@ The Coreutils has different implementations, with different level of completions * [SerenityOS](https://github.com/SerenityOS/serenity/tree/master/Userland/Utilities) * [Initial Unix](https://github.com/dspinellis/unix-history-repo) -However, when reimplementing the tools/options in Rust, don't read at their source codes +However, when reimplementing the tools/options in Rust, don't read their source codes when they are using reciprocal licenses (ex: GNU GPL, GNU LGPL, etc). From eb47efaadc596959bb628abcfb3d2d26216d6f26 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 7 Mar 2023 22:48:24 +0100 Subject: [PATCH 05/60] fix typo Co-authored-by: Terts Diepraam --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1ff2238b..e1a59717c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,7 +117,7 @@ cargo deny --all-features check all ## Other implementations -The Coreutils has different implementations, with different levels of completions: +The Coreutils have different implementations, with different levels of completions: * [GNU's](https://git.savannah.gnu.org/gitweb/?p=coreutils.git) * [BSD](https://github.com/openbsd/src/tree/master/bin) From f722e9b4073e139a46240820687ee98a0d4ffc0d Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 7 Mar 2023 22:49:05 +0100 Subject: [PATCH 06/60] document OpenBSD --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1a59717c..f658dbf81 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -120,7 +120,7 @@ cargo deny --all-features check all The Coreutils have different implementations, with different levels of completions: * [GNU's](https://git.savannah.gnu.org/gitweb/?p=coreutils.git) -* [BSD](https://github.com/openbsd/src/tree/master/bin) +* [OpenBSD](https://github.com/openbsd/src/tree/master/bin) * [Busybox](https://github.com/mirror/busybox/tree/master/coreutils) * [Toybox (Android)](https://github.com/landley/toybox/tree/master/toys/posix) * [V lang](https://github.com/vlang/coreutils) From f406b56f4a76488346da9ff10265f8e7ea0a208e Mon Sep 17 00:00:00 2001 From: Miles Liu Date: Wed, 1 Feb 2023 15:39:07 +0800 Subject: [PATCH 07/60] timeout: fix subprocess is never terminated --- src/uu/timeout/src/timeout.rs | 33 +++++++++++++++++++------- src/uucore/src/lib/features/process.rs | 15 ++++++++++++ tests/by-util/test_timeout.rs | 16 +++++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/uu/timeout/src/timeout.rs b/src/uu/timeout/src/timeout.rs index 26235e0df..fe342727b 100644 --- a/src/uu/timeout/src/timeout.rs +++ b/src/uu/timeout/src/timeout.rs @@ -196,6 +196,22 @@ fn report_if_verbose(signal: usize, cmd: &str, verbose: bool) { } } +fn send_signal(process: &mut Child, signal: usize, foreground: bool) { + // NOTE: GNU timeout doesn't check for errors of signal. + // The subprocess might have exited just after the timeout. + // Sending a signal now would return "No such process", but we should still try to kill the children. + _ = process.send_signal(signal); + if !foreground { + _ = process.send_signal_group(signal); + let kill_signal = signal_by_name_or_value("KILL").unwrap(); + let continued_signal = signal_by_name_or_value("CONT").unwrap(); + if signal != kill_signal && signal != continued_signal { + _ = process.send_signal(continued_signal); + _ = process.send_signal_group(continued_signal); + } + } +} + /// Wait for a child process and send a kill signal if it does not terminate. /// /// This function waits for the child `process` for the time period @@ -217,10 +233,11 @@ fn report_if_verbose(signal: usize, cmd: &str, verbose: bool) { /// If there is a problem sending the `SIGKILL` signal or waiting for /// the process after that signal is sent. fn wait_or_kill_process( - mut process: Child, + process: &mut Child, cmd: &str, duration: Duration, preserve_status: bool, + foreground: bool, verbose: bool, ) -> std::io::Result { match process.wait_or_timeout(duration) { @@ -234,7 +251,7 @@ fn wait_or_kill_process( Ok(None) => { let signal = signal_by_name_or_value("KILL").unwrap(); report_if_verbose(signal, cmd, verbose); - process.send_signal(signal)?; + send_signal(process, signal, foreground); process.wait()?; Ok(ExitStatus::SignalSent(signal).into()) } @@ -300,7 +317,7 @@ fn timeout( enable_pipe_errors()?; - let mut process = process::Command::new(&cmd[0]) + let process = &mut process::Command::new(&cmd[0]) .args(&cmd[1..]) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) @@ -335,7 +352,7 @@ fn timeout( .into()), Ok(None) => { report_if_verbose(signal, &cmd[0], verbose); - process.send_signal(signal)?; + send_signal(process, signal, foreground); match kill_after { None => { if preserve_status { @@ -350,6 +367,7 @@ fn timeout( &cmd[0], kill_after, preserve_status, + foreground, verbose, ) { Ok(status) => Err(status.into()), @@ -363,11 +381,8 @@ fn timeout( } Err(_) => { // We're going to return ERR_EXIT_STATUS regardless of - // whether `send_signal()` succeeds or fails, so just - // ignore the return value. - process - .send_signal(signal) - .map_err(|e| USimpleError::new(ExitStatus::TimeoutFailed.into(), format!("{e}")))?; + // whether `send_signal()` succeeds or fails + send_signal(process, signal, foreground); Err(ExitStatus::TimeoutFailed.into()) } } diff --git a/src/uucore/src/lib/features/process.rs b/src/uucore/src/lib/features/process.rs index 933b1f21b..b8b2f178f 100644 --- a/src/uucore/src/lib/features/process.rs +++ b/src/uucore/src/lib/features/process.rs @@ -48,6 +48,9 @@ pub trait ChildExt { /// send the signal to an unrelated process that recycled the PID. fn send_signal(&mut self, signal: usize) -> io::Result<()>; + /// Send a signal to a process group. + fn send_signal_group(&mut self, signal: usize) -> io::Result<()>; + /// Wait for a process to finish or return after the specified duration. /// A `timeout` of zero disables the timeout. fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result>; @@ -62,6 +65,18 @@ impl ChildExt for Child { } } + fn send_signal_group(&mut self, signal: usize) -> io::Result<()> { + // Ignore the signal, so we don't go into a signal loop. + if unsafe { libc::signal(signal as i32, libc::SIG_IGN) } != 0 { + return Err(io::Error::last_os_error()); + } + if unsafe { libc::kill(0, signal as i32) } != 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result> { if timeout == Duration::from_micros(0) { return self.wait().map(Some); diff --git a/tests/by-util/test_timeout.rs b/tests/by-util/test_timeout.rs index deedea6c7..eb6c99211 100644 --- a/tests/by-util/test_timeout.rs +++ b/tests/by-util/test_timeout.rs @@ -138,3 +138,19 @@ fn test_kill_after_long() { .no_stdout() .no_stderr(); } + +#[test] +fn test_kill_subprocess() { + new_ucmd!() + .args(&[ + // Make sure the CI can spawn the subprocess. + "10", + "sh", + "-c", + "sh -c \"trap 'echo xyz' TERM; sleep 30\"", + ]) + .fails() + .code_is(124) + .stdout_contains("xyz") + .stderr_contains("Terminated"); +} From 9cb6b4a3c032357a571fc8782f943e4e83f16cb4 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Sun, 27 Nov 2022 17:14:02 -0500 Subject: [PATCH 08/60] dd: open stdin from file descriptor when possible Open stdin using its file descriptor so that a `dd skip=N` command in a subshell does not consume all bytes from stdin. For example, before this commit, multiple instances of `dd` reading from stdin and appearing in a single command line would incorrectly result in an empty stdin for each instance of `dd` after the first: $ printf "abcdef\n" | (dd bs=1 skip=3 count=0 && dd) 2> /dev/null # incorrectly results in no output After this commit, the `dd skip=3` process reads three bytes from the file descriptor referring to stdin without draining the remaining three bytes when it terminates: $ printf "abcdef\n" | (dd bs=1 skip=3 count=0 && dd) 2> /dev/null def --- src/uu/dd/src/dd.rs | 49 ++++++++++++++++++++++++++++++++++++---- tests/by-util/test_dd.rs | 14 ++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index eaf89ca55..00be1558c 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -27,11 +27,14 @@ use std::cmp; use std::env; use std::ffi::OsString; use std::fs::{File, OpenOptions}; -use std::io::{self, Read, Seek, SeekFrom, Stdin, Stdout, Write}; -#[cfg(unix)] -use std::os::unix::fs::FileTypeExt; +use std::io::{self, Read, Seek, SeekFrom, Stdout, Write}; #[cfg(any(target_os = "linux", target_os = "android"))] use std::os::unix::fs::OpenOptionsExt; +#[cfg(unix)] +use std::os::unix::{ + fs::FileTypeExt, + io::{AsRawFd, FromRawFd}, +}; use std::path::Path; use std::sync::mpsc; use std::thread; @@ -93,21 +96,44 @@ impl Num { } /// Data sources. +/// +/// Use [`Source::stdin_as_file`] if available to enable more +/// fine-grained access to reading from stdin. enum Source { /// Input from stdin. - Stdin(Stdin), + #[cfg(not(unix))] + Stdin(io::Stdin), /// Input from a file. File(File), + /// Input from stdin, opened from its file descriptor. + #[cfg(unix)] + StdinFile(File), + /// Input from a named pipe, also known as a FIFO. #[cfg(unix)] Fifo(File), } impl Source { + /// Create a source from stdin using its raw file descriptor. + /// + /// This returns an instance of the `Source::StdinFile` variant, + /// using the raw file descriptor of [`std::io::Stdin`] to create + /// the [`std::fs::File`] parameter. You can use this instead of + /// `Source::Stdin` to allow reading from stdin without consuming + /// the entire contents of stdin when this process terminates. + #[cfg(unix)] + fn stdin_as_file() -> Self { + let fd = io::stdin().as_raw_fd(); + let f = unsafe { File::from_raw_fd(fd) }; + Self::StdinFile(f) + } + fn skip(&mut self, n: u64) -> io::Result { match self { + #[cfg(not(unix))] Self::Stdin(stdin) => match io::copy(&mut stdin.take(n), &mut io::sink()) { Ok(m) if m < n => { show_error!("'standard input': cannot skip to specified offset"); @@ -116,6 +142,15 @@ impl Source { Ok(m) => Ok(m), Err(e) => Err(e), }, + #[cfg(unix)] + Self::StdinFile(f) => match io::copy(&mut f.take(n), &mut io::sink()) { + Ok(m) if m < n => { + show_error!("'standard input': cannot skip to specified offset"); + Ok(m) + } + Ok(m) => Ok(m), + Err(e) => Err(e), + }, Self::File(f) => f.seek(io::SeekFrom::Start(n)), #[cfg(unix)] Self::Fifo(f) => io::copy(&mut f.take(n), &mut io::sink()), @@ -126,9 +161,12 @@ impl Source { impl Read for Source { fn read(&mut self, buf: &mut [u8]) -> io::Result { match self { + #[cfg(not(unix))] Self::Stdin(stdin) => stdin.read(buf), Self::File(f) => f.read(buf), #[cfg(unix)] + Self::StdinFile(f) => f.read(buf), + #[cfg(unix)] Self::Fifo(f) => f.read(buf), } } @@ -151,7 +189,10 @@ struct Input<'a> { impl<'a> Input<'a> { /// Instantiate this struct with stdin as a source. fn new_stdin(settings: &'a Settings) -> UResult { + #[cfg(not(unix))] let mut src = Source::Stdin(io::stdin()); + #[cfg(unix)] + let mut src = Source::stdin_as_file(); if settings.skip > 0 { src.skip(settings.skip)?; } diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 5deeb12f0..b0d5db8f3 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -1514,3 +1514,17 @@ fn test_skip_input_fifo() { assert!(output.stdout.is_empty()); assert_eq!(&output.stderr, b"1+0 records in\n1+0 records out\n"); } + +/// Test for reading part of stdin from each of two child processes. +#[cfg(all(not(windows), feature = "printf"))] +#[test] +fn test_multiple_processes_reading_stdin() { + // TODO Investigate if this is possible on Windows. + let printf = format!("{TESTS_BINARY} printf 'abcdef\n'"); + let dd_skip = format!("{TESTS_BINARY} dd bs=1 skip=3 count=0"); + let dd = format!("{TESTS_BINARY} dd"); + UCommand::new() + .arg(format!("{printf} | ( {dd_skip} && {dd} ) 2> /dev/null")) + .succeeds() + .stdout_only("def\n"); +} From 6608a7ea883825282d6f30c1d20e62ec05440b18 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 8 Mar 2023 22:39:39 +0100 Subject: [PATCH 09/60] Use sccache to cache build results instead of Swatinem/rust-cache@v2 --- .github/workflows/CICD.yml | 116 ++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 27 deletions(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index f5ddefc4f..700bee996 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -37,8 +37,6 @@ jobs: ## ToDO: [2021-11-10; rivy] 'Style/deps' needs more informative output and better integration of results into the GHA dashboard name: Style/deps runs-on: ${{ matrix.job.os }} - # env: - # STYLE_FAIL_ON_FAULT: false # overrides workflow default strategy: fail-fast: false matrix: @@ -73,7 +71,6 @@ jobs: run: | rustup toolchain install nightly --no-self-update --profile minimal rustup default nightly - - uses: Swatinem/rust-cache@v2 - name: Install `cargo-udeps` run: cargo install cargo-udeps env: @@ -93,8 +90,6 @@ jobs: style_format: name: Style/format runs-on: ${{ matrix.job.os }} - # env: - # STYLE_FAIL_ON_FAULT: false # overrides workflow default strategy: fail-fast: false matrix: @@ -124,7 +119,6 @@ jobs: ## Install `rust` toolchain rustup toolchain install stable --no-self-update -c rustfmt --profile minimal rustup default stable - - uses: Swatinem/rust-cache@v2 - name: "`cargo fmt` testing" shell: bash run: | @@ -184,8 +178,9 @@ jobs: style_lint: name: Style/lint runs-on: ${{ matrix.job.os }} - # env: - # STYLE_FAIL_ON_FAULT: false # overrides workflow default + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -195,6 +190,10 @@ jobs: - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Initialize workflow variables id: vars shell: bash @@ -229,7 +228,6 @@ jobs: ## Install `rust` toolchain rustup toolchain install stable --no-self-update -c clippy --profile minimal rustup default stable - - uses: Swatinem/rust-cache@v2 - name: "`cargo clippy` lint testing" shell: bash run: | @@ -244,15 +242,12 @@ jobs: style_spellcheck: name: Style/spelling runs-on: ${{ matrix.job.os }} - # env: - # STYLE_FAIL_ON_FAULT: false # overrides workflow default strategy: matrix: job: - { os: ubuntu-latest , features: feat_os_unix } steps: - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 - name: Initialize workflow variables id: vars shell: bash @@ -292,6 +287,9 @@ jobs: doc_warnings: name: Documentation/warnings runs-on: ${{ matrix.job.os }} + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -304,6 +302,10 @@ jobs: # - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Initialize workflow variables id: vars shell: bash @@ -331,7 +333,6 @@ jobs: ## Install `rust` toolchain rustup toolchain install stable --no-self-update -c clippy --profile minimal rustup default stable - - uses: Swatinem/rust-cache@v2 - name: "`cargo doc` with warnings" shell: bash run: | @@ -347,12 +348,19 @@ jobs: min_version: name: MinRustV # Minimum supported rust version (aka, MinSRV or MSRV) runs-on: ${{ matrix.job.os }} + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: matrix: job: - { os: ubuntu-latest , features: feat_os_unix } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Initialize workflow variables id: vars shell: bash @@ -369,7 +377,6 @@ jobs: ## Install `rust` toolchain (v${{ env.RUST_MIN_SRV }}) rustup toolchain install --no-self-update ${{ env.RUST_MIN_SRV }} --profile minimal rustup default ${{ env.RUST_MIN_SRV }} - - uses: Swatinem/rust-cache@v2 - name: Confirm MinSRV compatible 'Cargo.lock' shell: bash run: | @@ -424,7 +431,6 @@ jobs: ## Install `rust` toolchain rustup toolchain install stable --no-self-update --profile minimal rustup default stable - - uses: Swatinem/rust-cache@v2 - name: "`cargo update` testing" shell: bash run: | @@ -436,6 +442,9 @@ jobs: name: Build/Makefile needs: [ min_version, deps ] runs-on: ${{ matrix.job.os }} + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -443,12 +452,15 @@ jobs: - { os: ubuntu-latest , features: feat_os_unix } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Install `rust` toolchain run: | ## Install `rust` toolchain rustup toolchain install stable --no-self-update --profile minimal rustup default stable - - uses: Swatinem/rust-cache@v2 - name: "`make build`" shell: bash run: | @@ -470,12 +482,14 @@ jobs: env: RUST_BACKTRACE: "1" - build_rust_stable: name: Build/stable needs: [ min_version, deps ] runs-on: ${{ matrix.job.os }} timeout-minutes: 90 + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -485,12 +499,15 @@ jobs: - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Install `rust` toolchain run: | ## Install `rust` toolchain rustup toolchain install stable --no-self-update --profile minimal rustup default stable - - uses: Swatinem/rust-cache@v2 - name: Test run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} env: @@ -501,6 +518,9 @@ jobs: needs: [ min_version, deps ] runs-on: ${{ matrix.job.os }} timeout-minutes: 90 + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -510,12 +530,15 @@ jobs: - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Install `rust` toolchain run: | ## Install `rust` toolchain rustup toolchain install nightly --no-self-update --profile minimal rustup default nightly - - uses: Swatinem/rust-cache@v2 - name: Test run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} env: @@ -525,6 +548,9 @@ jobs: name: Binary sizes needs: [ min_version, deps ] runs-on: ${{ matrix.job.os }} + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -532,6 +558,10 @@ jobs: - { os: ubuntu-latest , features: feat_os_unix } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Install dependencies shell: bash run: | @@ -543,7 +573,6 @@ jobs: ## Install `rust` toolchain rustup toolchain install stable --no-self-update --profile minimal rustup default stable - - uses: Swatinem/rust-cache@v2 - name: "`make install`" shell: bash run: | @@ -579,6 +608,8 @@ jobs: timeout-minutes: 90 env: DOCKER_OPTS: '--volume /etc/passwd:/etc/passwd --volume /etc/group:/etc/group' + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -605,6 +636,10 @@ jobs: - { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Initialize workflow variables id: vars shell: bash @@ -732,9 +767,6 @@ jobs: ## rust toolchain ~ install rustup toolchain install --no-self-update ${{ env.RUST_MIN_SRV }} -t ${{ matrix.job.target }} --profile minimal rustup default ${{ env.RUST_MIN_SRV }} - - uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.job.os }}-${{ matrix.job.target }} - name: Initialize toolchain-dependent workflow variables id: dep_vars shell: bash @@ -844,6 +876,9 @@ jobs: name: Tests/BusyBox test suite needs: [ min_version, deps ] runs-on: ${{ matrix.job.os }} + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -857,7 +892,10 @@ jobs: ## VARs setup echo "TEST_SUMMARY_FILE=busybox-result.json" >> $GITHUB_OUTPUT - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Install/setup prerequisites shell: bash run: | @@ -917,6 +955,9 @@ jobs: name: Tests/Toybox test suite needs: [ min_version, deps ] runs-on: ${{ matrix.job.os }} + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -932,7 +973,10 @@ jobs: TEST_SUMMARY_FILE="toybox-result.json" outputs TEST_SUMMARY_FILE - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: rust toolchain ~ install run: | ## rust toolchain ~ install @@ -1010,8 +1054,14 @@ jobs: arch: [x86] # , arm64-v8a env: TERMUX: v0.118.0 + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: AVD cache uses: actions/cache@v3 id: avd-cache @@ -1065,9 +1115,14 @@ jobs: - { os: macos-12 , features: unix } ## GHA MacOS-11.0 VM won't have VirtualBox; refs: , env: mem: 4096 + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" steps: - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" - name: Prepare, build and test ## spell-checker:ignore (ToDO) sshfs usesh vmactions uses: vmactions/freebsd-vm@v0.3.0 @@ -1132,6 +1187,9 @@ jobs: name: Code Coverage runs-on: ${{ matrix.job.os }} timeout-minutes: 90 + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" strategy: fail-fast: false matrix: @@ -1141,6 +1199,10 @@ jobs: - { os: windows-latest , features: windows } steps: - uses: actions/checkout@v3 + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.2 + with: + version: "v0.4.0-pre.9" # - name: Reattach HEAD ## may be needed for accurate code coverage info # run: git checkout ${{ github.head_ref }} - name: Initialize workflow variables @@ -1194,7 +1256,6 @@ jobs: ## rust toolchain ~ install rustup toolchain install ${{ steps.vars.outputs.TOOLCHAIN }} --no-self-update --profile minimal rustup default ${{ steps.vars.outputs.TOOLCHAIN }} - - uses: Swatinem/rust-cache@v2 - name: Initialize toolchain-dependent workflow variables id: dep_vars shell: bash @@ -1260,3 +1321,4 @@ jobs: flags: ${{ steps.vars.outputs.CODECOV_FLAGS }} name: codecov-umbrella fail_ci_if_error: false + From aecc8aa40f4f426aa6e3e5f3f5ba501434db8842 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 10 Mar 2023 16:41:05 +0100 Subject: [PATCH 10/60] keep Swatinem/rust-cache@v2 --- .github/workflows/CICD.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 700bee996..ebacd43c3 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -190,6 +190,7 @@ jobs: - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -302,6 +303,7 @@ jobs: # - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -357,6 +359,7 @@ jobs: - { os: ubuntu-latest , features: feat_os_unix } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -452,6 +455,7 @@ jobs: - { os: ubuntu-latest , features: feat_os_unix } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -499,6 +503,7 @@ jobs: - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -530,6 +535,7 @@ jobs: - { os: windows-latest , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -558,6 +564,7 @@ jobs: - { os: ubuntu-latest , features: feat_os_unix } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -636,6 +643,7 @@ jobs: - { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -892,6 +900,7 @@ jobs: ## VARs setup echo "TEST_SUMMARY_FILE=busybox-result.json" >> $GITHUB_OUTPUT - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -973,6 +982,7 @@ jobs: TEST_SUMMARY_FILE="toybox-result.json" outputs TEST_SUMMARY_FILE - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -1058,6 +1068,7 @@ jobs: RUSTC_WRAPPER: "sccache" steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -1119,6 +1130,7 @@ jobs: RUSTC_WRAPPER: "sccache" steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: @@ -1199,6 +1211,7 @@ jobs: - { os: windows-latest , features: windows } steps: - uses: actions/checkout@v3 + - uses: Swatinem/rust-cache@v2 - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: From fcdb7e48ed51ccaf944c087bc1b6b25bd7322e3d Mon Sep 17 00:00:00 2001 From: shaoyuteng Date: Fri, 10 Mar 2023 20:44:28 +0800 Subject: [PATCH 11/60] relpath: move help strings to markdown file --- src/uu/relpath/relpath.md | 8 ++++++++ src/uu/relpath/src/relpath.rs | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/uu/relpath/relpath.md diff --git a/src/uu/relpath/relpath.md b/src/uu/relpath/relpath.md new file mode 100644 index 000000000..a1ff9bf4a --- /dev/null +++ b/src/uu/relpath/relpath.md @@ -0,0 +1,8 @@ +# relpath + +``` +relpath [-d DIR] TO [FROM] +``` + +Convert TO destination to the relative path from the FROM dir. +If FROM path is omitted, current working dir will be used. \ No newline at end of file diff --git a/src/uu/relpath/src/relpath.rs b/src/uu/relpath/src/relpath.rs index 522cc54e5..d25956fc1 100644 --- a/src/uu/relpath/src/relpath.rs +++ b/src/uu/relpath/src/relpath.rs @@ -14,10 +14,10 @@ use uucore::display::println_verbatim; use uucore::error::{FromIo, UResult}; use uucore::format_usage; use uucore::fs::{canonicalize, MissingHandling, ResolveMode}; +use uucore::{help_about, help_usage}; -static ABOUT: &str = "Convert TO destination to the relative path from the FROM dir. -If FROM path is omitted, current working dir will be used."; -const USAGE: &str = "{} [-d DIR] TO [FROM]"; +const USAGE: &str = help_usage!("relpath.md"); +const ABOUT: &str = help_about!("relpath.md"); mod options { pub const DIR: &str = "DIR"; From 27150a970bc2e997b5354300f45726bba65c0e83 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 12 Mar 2023 10:58:29 +0100 Subject: [PATCH 12/60] Merge the use declarations --- src/uu/relpath/src/relpath.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/uu/relpath/src/relpath.rs b/src/uu/relpath/src/relpath.rs index d25956fc1..2b4706a81 100644 --- a/src/uu/relpath/src/relpath.rs +++ b/src/uu/relpath/src/relpath.rs @@ -12,9 +12,8 @@ use std::env; use std::path::{Path, PathBuf}; use uucore::display::println_verbatim; use uucore::error::{FromIo, UResult}; -use uucore::format_usage; +use uucore::{format_usage, help_about, help_usage}; use uucore::fs::{canonicalize, MissingHandling, ResolveMode}; -use uucore::{help_about, help_usage}; const USAGE: &str = help_usage!("relpath.md"); const ABOUT: &str = help_about!("relpath.md"); From 0d03c48f6b9f7fd89b2227ef54d627ae8f6c874a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 12 Mar 2023 11:11:50 +0100 Subject: [PATCH 13/60] Move the declaration at the right place --- src/uu/relpath/src/relpath.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/relpath/src/relpath.rs b/src/uu/relpath/src/relpath.rs index 2b4706a81..ef7c43474 100644 --- a/src/uu/relpath/src/relpath.rs +++ b/src/uu/relpath/src/relpath.rs @@ -12,8 +12,8 @@ use std::env; use std::path::{Path, PathBuf}; use uucore::display::println_verbatim; use uucore::error::{FromIo, UResult}; -use uucore::{format_usage, help_about, help_usage}; use uucore::fs::{canonicalize, MissingHandling, ResolveMode}; +use uucore::{format_usage, help_about, help_usage}; const USAGE: &str = help_usage!("relpath.md"); const ABOUT: &str = help_about!("relpath.md"); From 3198fe5417a9bb927c55d27de3e664bcd1ee5d2a Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sun, 12 Mar 2023 14:08:19 +0100 Subject: [PATCH 14/60] Bump procfs from 0.14.1 to 0.15.1 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d53a4c2e..1a443502e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1719,15 +1719,15 @@ dependencies = [ [[package]] name = "procfs" -version = "0.14.1" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfb6451c91904606a1abe93e83a8ec851f45827fa84273f256ade45dc095818" +checksum = "943ca7f9f29bab5844ecd8fdb3992c5969b6622bb9609b9502fef9b4310e3f1f" dependencies = [ "bitflags", "byteorder", "hex", "lazy_static", - "rustix 0.35.13", + "rustix 0.36.8", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index be545c860..ca3f0d332 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -493,7 +493,7 @@ hex-literal = "0.3.1" rstest = "0.16.0" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies] -procfs = { version = "0.14", default-features = false } +procfs = { version = "0.15", default-features = false } rlimit = "0.9.1" [target.'cfg(unix)'.dev-dependencies] From 946aab37ede4b050c6ad287aa673966d51bfddaa Mon Sep 17 00:00:00 2001 From: Joining7943 <111500881+Joining7943@users.noreply.github.com> Date: Tue, 28 Feb 2023 07:36:04 +0100 Subject: [PATCH 15/60] Cargo: Bump fundu version v0.3.0 -> v0.4.2. Adjust test in test_tail. --- .vscode/cspell.dictionaries/workspace.wordlist.txt | 1 + Cargo.lock | 4 ++-- Cargo.toml | 2 +- tests/by-util/test_tail.rs | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.vscode/cspell.dictionaries/workspace.wordlist.txt b/.vscode/cspell.dictionaries/workspace.wordlist.txt index d6e91dca5..6d6533bcf 100644 --- a/.vscode/cspell.dictionaries/workspace.wordlist.txt +++ b/.vscode/cspell.dictionaries/workspace.wordlist.txt @@ -20,6 +20,7 @@ exacl filetime formatteriteminfo fsext +fundu getopts getrandom globset diff --git a/Cargo.lock b/Cargo.lock index 4d53a4c2e..ca348f194 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -880,9 +880,9 @@ dependencies = [ [[package]] name = "fundu" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925250bc259498d4008ee072bf16586083ab2c491aa4b06b3c4d0a6556cebd74" +checksum = "da58c38fe7b706cead98429d8a8535261addbe55fd531c7d7c7d770346464010" [[package]] name = "futures" diff --git a/Cargo.toml b/Cargo.toml index be545c860..1fe04f34c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -282,7 +282,7 @@ filetime = "0.2" fnv = "1.0.7" fs_extra = "1.1.0" fts-sys = "0.2" -fundu = "0.3.0" +fundu = "0.4.2" gcd = "2.2" glob = "0.3.0" half = "2.1" diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index eb18e858f..93ca1046d 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -4459,7 +4459,7 @@ fn test_follow_when_files_are_pointing_to_same_relative_file_and_file_stays_same } #[rstest] -#[case::exponent_exceed_float_max("1.0e2048")] +#[case::exponent_exceed_float_max("1.0e100000")] #[case::underscore_delimiter("1_000")] #[case::only_point(".")] #[case::space_in_primes("' '")] From 3a28b616d998cf2e1917ebe947893b37dabca529 Mon Sep 17 00:00:00 2001 From: Joining7943 <111500881+Joining7943@users.noreply.github.com> Date: Tue, 28 Feb 2023 07:36:22 +0100 Subject: [PATCH 16/60] sleep: Use fundu instead of uucore::parse_time::from_str --- Cargo.lock | 1 + src/uu/sleep/Cargo.toml | 1 + src/uu/sleep/src/sleep.rs | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ca348f194..98b5cb973 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3041,6 +3041,7 @@ name = "uu_sleep" version = "0.0.17" dependencies = [ "clap", + "fundu", "uucore", ] diff --git a/src/uu/sleep/Cargo.toml b/src/uu/sleep/Cargo.toml index 048f551c1..aa4bf0664 100644 --- a/src/uu/sleep/Cargo.toml +++ b/src/uu/sleep/Cargo.toml @@ -16,6 +16,7 @@ path = "src/sleep.rs" [dependencies] clap = { workspace=true } +fundu = { workspace=true } uucore = { workspace=true } [[bin]] diff --git a/src/uu/sleep/src/sleep.rs b/src/uu/sleep/src/sleep.rs index 4751d89b2..af6a0f22e 100644 --- a/src/uu/sleep/src/sleep.rs +++ b/src/uu/sleep/src/sleep.rs @@ -14,6 +14,7 @@ use uucore::{ }; use clap::{crate_version, Arg, ArgAction, Command}; +use fundu::{self, DurationParser}; static ABOUT: &str = help_about!("sleep.md"); const USAGE: &str = help_usage!("sleep.md"); @@ -61,10 +62,14 @@ pub fn uu_app() -> Command { fn sleep(args: &[&str]) -> UResult<()> { let mut arg_error = false; + + use fundu::TimeUnit::*; + let parser = DurationParser::with_time_units(&[Second, Minute, Hour, Day]); + let sleep_dur = args .iter() .filter_map(|input| { - uucore::parse_time::from_str(input.trim()).ok().or_else(|| { + parser.parse(input.trim()).ok().or_else(|| { arg_error = true; show_error!("invalid time interval '{input}'"); None From 5fb091a4fb14eed29894de19ab62212941945bb6 Mon Sep 17 00:00:00 2001 From: Joining7943 <111500881+Joining7943@users.noreply.github.com> Date: Wed, 1 Mar 2023 07:35:53 +0100 Subject: [PATCH 17/60] sleep: Use fundu error types to improve error messages --- src/uu/sleep/src/sleep.rs | 26 +++++++++++++++++++++----- tests/by-util/test_sleep.rs | 16 +++++++++------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/uu/sleep/src/sleep.rs b/src/uu/sleep/src/sleep.rs index af6a0f22e..009986095 100644 --- a/src/uu/sleep/src/sleep.rs +++ b/src/uu/sleep/src/sleep.rs @@ -14,7 +14,7 @@ use uucore::{ }; use clap::{crate_version, Arg, ArgAction, Command}; -use fundu::{self, DurationParser}; +use fundu::{self, DurationParser, ParseError}; static ABOUT: &str = help_about!("sleep.md"); const USAGE: &str = help_usage!("sleep.md"); @@ -68,12 +68,28 @@ fn sleep(args: &[&str]) -> UResult<()> { let sleep_dur = args .iter() - .filter_map(|input| { - parser.parse(input.trim()).ok().or_else(|| { + .filter_map(|input| match parser.parse(input.trim()) { + Ok(duration) => Some(duration), + Err(error) => { arg_error = true; - show_error!("invalid time interval '{input}'"); + + let reason = match error { + ParseError::Empty if input.is_empty() => "Input was empty".to_string(), + ParseError::Empty => "Found only whitespace in input".to_string(), + ParseError::Syntax(pos, description) + | ParseError::TimeUnit(pos, description) => { + format!("{description} at position {}", pos.saturating_add(1)) + } + ParseError::NegativeExponentOverflow | ParseError::PositiveExponentOverflow => { + "Exponent was out of bounds".to_string() + } + ParseError::NegativeNumber => "Number was negative".to_string(), + error => error.to_string(), + }; + show_error!("invalid time interval '{input}': {reason}"); + None - }) + } }) .fold(Duration::ZERO, |acc, n| acc.saturating_add(n)); diff --git a/tests/by-util/test_sleep.rs b/tests/by-util/test_sleep.rs index c525cc0d2..8bb4b11ea 100644 --- a/tests/by-util/test_sleep.rs +++ b/tests/by-util/test_sleep.rs @@ -10,11 +10,11 @@ fn test_invalid_time_interval() { new_ucmd!() .arg("xyz") .fails() - .usage_error("invalid time interval 'xyz'"); + .usage_error("invalid time interval 'xyz': Invalid character: 'x' at position 1"); new_ucmd!() .args(&["--", "-1"]) .fails() - .usage_error("invalid time interval '-1'"); + .usage_error("invalid time interval '-1': Number was negative"); } #[test] @@ -204,14 +204,16 @@ fn test_sleep_when_input_has_only_whitespace_then_error(#[case] input: &str) { .arg(input) .timeout(Duration::from_secs(10)) .fails() - .usage_error(format!("invalid time interval '{input}'")); + .usage_error(format!( + "invalid time interval '{input}': Found only whitespace in input" + )); } #[test] fn test_sleep_when_multiple_input_some_with_error_then_shows_all_errors() { - let expected = "invalid time interval 'abc'\n\ - sleep: invalid time interval '1years'\n\ - sleep: invalid time interval ' '"; + let expected = "invalid time interval 'abc': Invalid character: 'a' at position 1\n\ + sleep: invalid time interval '1years': Invalid time unit: 'years' at position 2\n\ + sleep: invalid time interval ' ': Found only whitespace in input"; // Even if one of the arguments is valid, but the rest isn't, we should still fail and exit early. // So, the timeout of 10 seconds ensures we haven't executed `thread::sleep` with the only valid @@ -228,5 +230,5 @@ fn test_negative_interval() { new_ucmd!() .args(&["--", "-1"]) .fails() - .usage_error("invalid time interval '-1'"); + .usage_error("invalid time interval '-1': Number was negative"); } From a585d7f3a750b289ca5de79504a09738da88b7c6 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Sun, 12 Mar 2023 16:26:56 +0100 Subject: [PATCH 18/60] Bump terminal_size from 0.2.2 to 0.2.5 --- Cargo.lock | 46 ++++++++++------------------------------------ Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a443502e..ea3674485 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1139,12 +1139,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-lifetimes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" - [[package]] name = "io-lifetimes" version = "1.0.5" @@ -1162,8 +1156,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ "hermit-abi 0.3.1", - "io-lifetimes 1.0.5", - "rustix 0.36.8", + "io-lifetimes", + "rustix", "windows-sys 0.45.0", ] @@ -1257,12 +1251,6 @@ dependencies = [ "cc", ] -[[package]] -name = "linux-raw-sys" -version = "0.0.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" - [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -1727,7 +1715,7 @@ dependencies = [ "byteorder", "hex", "lazy_static", - "rustix 0.36.8", + "rustix", ] [[package]] @@ -1921,20 +1909,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.35.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes 0.7.5", - "libc", - "linux-raw-sys 0.0.46", - "windows-sys 0.42.0", -] - [[package]] name = "rustix" version = "0.36.8" @@ -1943,9 +1917,9 @@ checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", - "io-lifetimes 1.0.5", + "io-lifetimes", "libc", - "linux-raw-sys 0.1.4", + "linux-raw-sys", "windows-sys 0.45.0", ] @@ -2185,7 +2159,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix 0.36.8", + "rustix", "windows-sys 0.42.0", ] @@ -2209,12 +2183,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ca90c434fd12083d1a6bdcbe9f92a14f96c8a1ba600ba451734ac334521f7a" +checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" dependencies = [ - "rustix 0.35.13", - "windows-sys 0.42.0", + "rustix", + "windows-sys 0.45.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ca3f0d332..c1b00667e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -320,7 +320,7 @@ strum = "0.24.1" strum_macros = "0.24.2" tempfile = "3.4.0" term_grid = "0.1.5" -terminal_size = "0.2.2" +terminal_size = "0.2.5" textwrap = { version="0.16.0", features=["terminal_size"] } thiserror = "1.0" time = { version="0.3" } From ffcf2b5d55ad9533ab69e031f500ad11dcec747f Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 12 Mar 2023 22:01:00 +0100 Subject: [PATCH 19/60] readme: advise using --locked with cargo install --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4bf12ccf5..97e115a6a 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ make UTILS='UTILITY_1 UTILITY_2' Likewise, installing can simply be done using: ```shell -cargo install --path . +cargo install --path . --locked ``` This command will install uutils into Cargo's *bin* folder (*e.g.* `$HOME/.cargo/bin`). From 787ad780c02cccd86600172d2102df6ddd1b42d6 Mon Sep 17 00:00:00 2001 From: Miles Liu Date: Mon, 13 Mar 2023 15:33:07 +0800 Subject: [PATCH 20/60] docs: fix tr.pl and stat-printf.pl don't show up in gnu-full-result --- util/gnu-json-result.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/gnu-json-result.py b/util/gnu-json-result.py index 1cd16e64c..c1adb3ffc 100644 --- a/util/gnu-json-result.py +++ b/util/gnu-json-result.py @@ -18,7 +18,7 @@ for filepath in test_dir.glob("**/*.log"): current[key] = {} current = current[key] try: - with open(path) as f: + with open(path, errors="ignore") as f: content = f.read() result = re.search( r"(PASS|FAIL|SKIP|ERROR) [^ ]+ \(exit status: \d+\)$", content From f53edbe89a5a7f84f379a5e93fc71969e4f57ba8 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Mon, 13 Mar 2023 10:40:13 +0100 Subject: [PATCH 21/60] Bump fts-sys to 0.2.4 & selinux-sys to 0.6.2 --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5365f9fca..c86edc12a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,9 +89,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.62.0" +version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6720a8b7b2d39dd533285ed438d458f65b31b5c257e6ac7bb3d7e82844dd722" +checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" dependencies = [ "bitflags", "cexpr", @@ -870,9 +870,9 @@ dependencies = [ [[package]] name = "fts-sys" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32bd98333d10742c0b048272ebf4cb05336d415423b853961c92ccb398966a03" +checksum = "9a66c0a21e344f20c87b4ca12643cf4f40a7018f132c98d344e989b959f49dd1" dependencies = [ "bindgen", "libc", @@ -1966,9 +1966,9 @@ dependencies = [ [[package]] name = "selinux-sys" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c02c5c6e2db8a78b3ffffc666f75fcda5bbd7068ba3c0f560e5504f4d88443" +checksum = "806d381649bb85347189d2350728817418138d11d738e2482cb644ec7f3c755d" dependencies = [ "bindgen", "cc", From 5ec2e36f5872e405b7730a31d523399b8fbbab48 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 13 Mar 2023 11:26:53 +0100 Subject: [PATCH 22/60] Adjust the fuzzers tests in the CI as some have been fixed --- .github/workflows/CICD.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index ebacd43c3..2a474a89a 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -145,7 +145,7 @@ jobs: - name: Install `cargo-fuzz` run: cargo install cargo-fuzz - name: Run fuzz_date for XX seconds - # TODO: fix the issues + # TODO: fix https://github.com/uutils/coreutils/issues/4494 continue-on-error: true shell: bash run: | @@ -153,8 +153,6 @@ jobs: cd fuzz cargo +nightly fuzz run fuzz_date -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0 - name: Run fuzz_parse_glob for XX seconds - # TODO: fix the issues - continue-on-error: true shell: bash run: | ## Run it @@ -167,8 +165,6 @@ jobs: cd fuzz cargo +nightly fuzz run fuzz_parse_size -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0 - name: Run fuzz_parse_time for XX seconds - # TODO: fix the issues - continue-on-error: true shell: bash run: | ## Run it From a480ab069402ff3b1570eb44570a42e361276c75 Mon Sep 17 00:00:00 2001 From: Koki Ueha Date: Mon, 13 Mar 2023 15:04:46 +0000 Subject: [PATCH 23/60] mkfifo: move help strings to markdown file --- src/uu/mkfifo/mkfifo.md | 7 +++++++ src/uu/mkfifo/src/mkfifo.rs | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 src/uu/mkfifo/mkfifo.md diff --git a/src/uu/mkfifo/mkfifo.md b/src/uu/mkfifo/mkfifo.md new file mode 100644 index 000000000..b63437829 --- /dev/null +++ b/src/uu/mkfifo/mkfifo.md @@ -0,0 +1,7 @@ +# mkfifo + +``` +mkfifo [OPTION]... NAME... +``` + +Create a FIFO with the given name. diff --git a/src/uu/mkfifo/src/mkfifo.rs b/src/uu/mkfifo/src/mkfifo.rs index 99c16acff..dc338cf12 100644 --- a/src/uu/mkfifo/src/mkfifo.rs +++ b/src/uu/mkfifo/src/mkfifo.rs @@ -10,10 +10,10 @@ use libc::mkfifo; use std::ffi::CString; use uucore::display::Quotable; use uucore::error::{UResult, USimpleError}; -use uucore::{format_usage, show}; +use uucore::{format_usage, help_about, help_usage, show}; -static USAGE: &str = "{} [OPTION]... NAME..."; -static ABOUT: &str = "Create a FIFO with the given name."; +static USAGE: &str = help_usage!("mkfifo.md"); +static ABOUT: &str = help_about!("mkfifo.md"); mod options { pub static MODE: &str = "mode"; From d241ec7e0877b2d1f85878ae863a322e5be397eb Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Mon, 13 Mar 2023 22:19:29 +0100 Subject: [PATCH 24/60] pwd: small refactor of some match expressions --- src/uu/pwd/src/pwd.rs | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/src/uu/pwd/src/pwd.rs b/src/uu/pwd/src/pwd.rs index c79f78dc2..7af194872 100644 --- a/src/uu/pwd/src/pwd.rs +++ b/src/uu/pwd/src/pwd.rs @@ -15,10 +15,10 @@ use uucore::{format_usage, help_about, help_usage}; use uucore::display::println_verbatim; use uucore::error::{FromIo, UResult}; -static ABOUT: &str = help_about!("pwd.md"); +const ABOUT: &str = help_about!("pwd.md"); const USAGE: &str = help_usage!("pwd.md"); -static OPT_LOGICAL: &str = "logical"; -static OPT_PHYSICAL: &str = "physical"; +const OPT_LOGICAL: &str = "logical"; +const OPT_PHYSICAL: &str = "physical"; fn physical_path() -> io::Result { // std::env::current_dir() is a thin wrapper around libc::getcwd(). @@ -84,36 +84,22 @@ fn logical_path() -> io::Result { { use std::fs::metadata; use std::os::unix::fs::MetadataExt; - let path_info = match metadata(path) { - Ok(info) => info, - Err(_) => return false, - }; - let real_info = match metadata(".") { - Ok(info) => info, - Err(_) => return false, - }; - if path_info.dev() != real_info.dev() || path_info.ino() != real_info.ino() { - return false; + match (metadata(path), metadata(".")) { + (Ok(info1), Ok(info2)) => { + info1.dev() == info2.dev() && info1.ino() == info2.ino() + } + _ => false, } } #[cfg(not(unix))] { use std::fs::canonicalize; - let canon_path = match canonicalize(path) { - Ok(path) => path, - Err(_) => return false, - }; - let real_path = match canonicalize(".") { - Ok(path) => path, - Err(_) => return false, - }; - if canon_path != real_path { - return false; + match (canonicalize(path), canonicalize(".")) { + (Ok(path1), Ok(path2)) => path1 == path2, + _ => false, } } - - true } match env::var_os("PWD").map(PathBuf::from) { From 50e019a711ac61d885245879f75c2f7259cb15d9 Mon Sep 17 00:00:00 2001 From: Parag Jain Date: Tue, 14 Mar 2023 12:28:49 -0400 Subject: [PATCH 25/60] Fixing failing test locally because of missing case sensitivity handling --- tests/by-util/test_ls.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 36ae816b3..5c0c15d0e 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -1280,7 +1280,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]+ ){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(); @@ -1289,13 +1289,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]+ ){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]+ 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(); From 08d2492cac10e71932c4be13ab093da5c5010ac3 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Mar 2023 17:09:49 +0100 Subject: [PATCH 26/60] README: add logo and center title and logo --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 97e115a6a..296413bec 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +
+ +![uutils logo](docs/src/logo.svg) + # uutils coreutils [![Crates.io](https://img.shields.io/crates/v/coreutils.svg)](https://crates.io/crates/coreutils) @@ -9,7 +13,9 @@ [![CodeCov](https://codecov.io/gh/uutils/coreutils/branch/master/graph/badge.svg)](https://codecov.io/gh/uutils/coreutils) ![MSRV](https://img.shields.io/badge/MSRV-1.64.0-brightgreen) ------------------------------------------------ +
+ +--- From c83f6eeadd07c7c54a1ffad394e9a53a5ef4bc2d Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Mar 2023 17:16:10 +0100 Subject: [PATCH 27/60] Move testing instructions from README to CONTRIBUTING --- CONTRIBUTING.md | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 125 +--------------------------------------------- 2 files changed, 131 insertions(+), 124 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f658dbf81..9af1948fe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,6 +47,136 @@ For Windows, Microsoft provides some images (VMWare, Hyper-V, VirtualBox and Par for development: +## Testing + +Testing can be done using either Cargo or `make`. + +### Testing with Cargo + +Just like with building, we follow the standard procedure for testing using +Cargo: + +```shell +cargo test +``` + +By default, `cargo test` only runs the common programs. To run also platform +specific tests, run: + +```shell +cargo test --features unix +``` + +If you would prefer to test a select few utilities: + +```shell +cargo test --features "chmod mv tail" --no-default-features +``` + +If you also want to test the core utilities: + +```shell +cargo test -p uucore -p coreutils +``` + +To debug: + +```shell +gdb --args target/debug/coreutils ls +(gdb) b ls.rs:79 +(gdb) run +``` + +### Testing with GNU Make + +To simply test all available utilities: + +```shell +make test +``` + +To test all but a few of the available utilities: + +```shell +make SKIP_UTILS='UTILITY_1 UTILITY_2' test +``` + +To test only a few of the available utilities: + +```shell +make UTILS='UTILITY_1 UTILITY_2' test +``` + +To include tests for unimplemented behavior: + +```shell +make UTILS='UTILITY_1 UTILITY_2' SPEC=y test +``` + +### Run Busybox Tests + +This testing functionality is only available on *nix operating systems and +requires `make`. + +To run busybox tests for all utilities for which busybox has tests + +```shell +make busytest +``` + +To run busybox tests for a few of the available utilities + +```shell +make UTILS='UTILITY_1 UTILITY_2' busytest +``` + +To pass an argument like "-v" to the busybox test runtime + +```shell +make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest +``` + +### Comparing with GNU + +To run uutils against the GNU test suite locally, run the following commands: + +```shell +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 +# To run several tests: +bash util/run-gnu-test.sh tests/touch/not-owner.sh tests/rm/no-give-up.sh # for example +# If this is a perl (.pl) test, to run in debug: +DEBUG=1 bash util/run-gnu-test.sh tests/misc/sm3sum.pl +``` + +Note that it relies on individual utilities (not the multicall binary). + +### Improving the GNU compatibility + +The Python script `./util/remaining-gnu-error.py` shows the list of failing +tests in the CI. + +To improve the GNU compatibility, the following process is recommended: + +1. Identify a test (the smaller, the better) on a program that you understand or + is easy to understand. You can use the `./util/remaining-gnu-error.py` script + to help with this decision. +1. Build both the GNU and Rust coreutils using: `bash util/build-gnu.sh` +1. Run the test with `bash util/run-gnu-test.sh ` +1. Start to modify `` to understand what is wrong. Examples: + 1. Add `set -v` to have the bash verbose mode + 1. Add `echo $?` where needed + 1. When the variable `fail` is used in the test, `echo $fail` to see when the + test started to fail + 1. Bump the content of the output (ex: `cat err`) + 1. ... +1. Or, if the test is simple, extract the relevant information to create a new + test case running both GNU & Rust implementation +1. Start to modify the Rust implementation to match the expected behavior +1. Add a test to make sure that we don't regress (our test suite is super quick) + ## Commit messages To help the project maintainers review pull requests from contributors across diff --git a/README.md b/README.md index 296413bec..abf18255a 100644 --- a/README.md +++ b/README.md @@ -286,96 +286,7 @@ make PREFIX=/my/path uninstall -## Testing - -Testing can be done using either Cargo or `make`. - -### Testing with Cargo - -Just like with building, we follow the standard procedure for testing using -Cargo: - -```shell -cargo test -``` - -By default, `cargo test` only runs the common programs. To run also platform -specific tests, run: - -```shell -cargo test --features unix -``` - -If you would prefer to test a select few utilities: - -```shell -cargo test --features "chmod mv tail" --no-default-features -``` - -If you also want to test the core utilities: - -```shell -cargo test -p uucore -p coreutils -``` - -To debug: - -```shell -gdb --args target/debug/coreutils ls -(gdb) b ls.rs:79 -(gdb) run -``` - -### Testing with GNU Make - -To simply test all available utilities: - -```shell -make test -``` - -To test all but a few of the available utilities: - -```shell -make SKIP_UTILS='UTILITY_1 UTILITY_2' test -``` - -To test only a few of the available utilities: - -```shell -make UTILS='UTILITY_1 UTILITY_2' test -``` - -To include tests for unimplemented behavior: - -```shell -make UTILS='UTILITY_1 UTILITY_2' SPEC=y test -``` - -### Run Busybox Tests - -This testing functionality is only available on *nix operating systems and -requires `make`. - -To run busybox tests for all utilities for which busybox has tests - -```shell -make busytest -``` - -To run busybox tests for a few of the available utilities - -```shell -make UTILS='UTILITY_1 UTILITY_2' busytest -``` - -To pass an argument like "-v" to the busybox test runtime - -```shell -make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest -``` - -### Comparing with GNU +## GNU test suite compatibility Below is the evolution of how many GNU tests uutils passes. A more detailed breakdown of the GNU test results of the main branch can be found @@ -383,40 +294,6 @@ breakdown of the GNU test results of the main branch can be found ![Evolution over time](https://github.com/uutils/coreutils-tracking/blob/main/gnu-results.png?raw=true) -To run locally: - -```shell -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 -# To run several tests: -bash util/run-gnu-test.sh tests/touch/not-owner.sh tests/rm/no-give-up.sh # for example -# If this is a perl (.pl) test, to run in debug: -DEBUG=1 bash util/run-gnu-test.sh tests/misc/sm3sum.pl -``` - -Note that it relies on individual utilities (not the multicall binary). - -### Improving the GNU compatibility - -The Python script `./util/remaining-gnu-error.py` shows the list of failing tests in the CI. - -To improve the GNU compatibility, the following process is recommended: - -1. Identify a test (the smaller, the better) on a program that you understand or is easy to understand. You can use the `./util/remaining-gnu-error.py` script to help with this decision. -1. Build both the GNU and Rust coreutils using: `bash util/build-gnu.sh` -1. Run the test with `bash util/run-gnu-test.sh ` -1. Start to modify `` to understand what is wrong. Examples: - 1. Add `set -v` to have the bash verbose mode - 1. Add `echo $?` where needed - 1. When the variable `fail` is used in the test, `echo $fail` to see when the test started to fail - 1. Bump the content of the output (ex: `cat err`) - 1. ... -1. Or, if the test is simple, extract the relevant information to create a new test case running both GNU & Rust implementation -1. Start to modify the Rust implementation to match the expected behavior -1. Add a test to make sure that we don't regress (our test suite is super quick) - ## Contributing To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md). From 04c7d2f60db7fa51bbd9f08067c9c3b66ea0c41d Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Mar 2023 17:19:12 +0100 Subject: [PATCH 28/60] README: rewrite description - Remove "attempt", I think we're good enough to call it more than an attempt - Make it more specifically about the GNU coreutils. --- README.md | 266 +++++++++++++++++++++++++++--------------------------- 1 file changed, 135 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index abf18255a..d2351417f 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,9 @@ -uutils is an attempt at writing universal (as in cross-platform) CLI -utilities in [Rust](http://www.rust-lang.org). -While all programs have been implemented, some options might be missing -or different behavior might be experienced. +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: @@ -33,13 +32,15 @@ cargo install coreutils ``` -## Why? -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. Rust was -chosen not only because it is fast and safe, but is also excellent for -writing cross-platform code. +## Goals + +uutils aims to be a drop-in replacement for the GNU utils. Differences with GNU +are treated as bugs. + +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 @@ -48,10 +49,11 @@ uutils has both user and developer documentation available: - [User Manual](https://uutils.github.io/user/) - [Developer Documentation](https://uutils.github.io/dev/coreutils/) -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. +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 - Rust (`cargo`, `rustc`) @@ -59,13 +61,13 @@ Both can also be generated locally, the instructions for that can be found in th ### Rust Version -uutils follows Rust's release channels and is tested against stable, beta and nightly. -The current Minimum Supported Rust Version (MSRV) is `1.64.0`. +uutils follows Rust's release channels and is tested against stable, beta and +nightly. The current Minimum Supported Rust Version (MSRV) is `1.64.0`. ## Building -There are currently two methods to build the uutils binaries: either Cargo -or GNU Make. +There are currently two methods to build the uutils binaries: either Cargo or +GNU Make. > Building the full package, including all documentation, requires both Cargo > and Gnu Make on a Unix platform. @@ -79,8 +81,8 @@ cd coreutils ### Cargo -Building uutils using Cargo is easy because the process is the same as for -every other Rust program: +Building uutils using Cargo is easy because the process is the same as for every +other Rust program: ```shell cargo build --release @@ -89,9 +91,9 @@ cargo build --release This command builds the most portable common core set of uutils into a multicall (BusyBox-type) binary, named 'coreutils', on most Rust-supported platforms. -Additional platform-specific uutils are often available. Building these -expanded sets of uutils for a platform (on that platform) is as simple as -specifying it as a feature: +Additional platform-specific uutils are often available. Building these expanded +sets of uutils for a platform (on that platform) is as simple as specifying it +as a feature: ```shell cargo build --release --features macos @@ -102,18 +104,18 @@ cargo build --release --features unix ``` If you don't want to build every utility available on your platform into the -final binary, you can also specify which ones you want to build manually. -For example: +final binary, you can also specify which ones you want to build manually. For +example: ```shell cargo build --features "base32 cat echo rm" --no-default-features ``` -If you don't want to build the multicall binary and would prefer to build -the utilities as individual binaries, that is also possible. Each utility -is contained in its own package within the main repository, named -"uu_UTILNAME". To build individual utilities, use cargo to build just the -specific packages (using the `--package` [aka `-p`] option). For example: +If you don't want to build the multicall binary and would prefer to build the +utilities as individual binaries, that is also possible. Each utility is +contained in its own package within the main repository, named "uu_UTILNAME". To +build individual utilities, use cargo to build just the specific packages (using +the `--package` [aka `-p`] option). For example: ```shell cargo build -p uu_base32 -p uu_cat -p uu_echo -p uu_rm @@ -157,10 +159,12 @@ Likewise, installing can simply be done using: cargo install --path . --locked ``` -This command will install uutils into Cargo's *bin* folder (*e.g.* `$HOME/.cargo/bin`). +This command will install uutils into Cargo's _bin_ folder (_e.g._ +`$HOME/.cargo/bin`). -This does not install files necessary for shell completion or manpages. -For manpages or shell completion to work, use `GNU Make` or see `Manually install shell completions`/`Manually install manpages`. +This does not install files necessary for shell completion or manpages. For +manpages or shell completion to work, use `GNU Make` or see +`Manually install shell completions`/`Manually install manpages`. ### Install with GNU Make @@ -213,8 +217,8 @@ be generated; See `Manually install shell completions`. ### Manually install shell completions -The `coreutils` binary can generate completions for the `bash`, `elvish`, `fish`, `powershell` -and `zsh` shells. It prints the result to stdout. +The `coreutils` binary can generate completions for the `bash`, `elvish`, +`fish`, `powershell` and `zsh` shells. It prints the result to stdout. The syntax is: @@ -222,8 +226,8 @@ The syntax is: cargo run completion ``` -So, to install completions for `ls` on `bash` to `/usr/local/share/bash-completion/completions/ls`, -run: +So, to install completions for `ls` on `bash` to +`/usr/local/share/bash-completion/completions/ls`, run: ```shell cargo run completion ls bash > /usr/local/share/bash-completion/completions/ls @@ -232,12 +236,12 @@ cargo run completion ls bash > /usr/local/share/bash-completion/completions/ls ### Manually install manpages To generate manpages, the syntax is: + ```bash cargo run manpage ``` -So, to install the manpage for `ls` to `/usr/local/share/man/man1/ls.1` -run: +So, to install the manpage for `ls` to `/usr/local/share/man/man1/ls.1` run: ```bash cargo run manpage ls > /usr/local/share/man/man1/ls.1 @@ -245,8 +249,8 @@ cargo run manpage ls > /usr/local/share/man/man1/ls.1 ## Un-installation -Un-installation differs depending on how you have installed uutils. If you used -Cargo to install, use Cargo to uninstall. If you used GNU Make to install, use +Un-installation differs depending on how you have installed uutils. If you used +Cargo to install, use Cargo to uninstall. If you used GNU Make to install, use Make to uninstall. ### Uninstall with Cargo @@ -309,98 +313,98 @@ Please note that this is not fully accurate: See for the main meta bugs (many are missing). -| Done | WIP | -|-----------|-----------| -| arch | cp | -| base32 | date | -| base64 | dd | -| basename | df | -| basenc | expr | -| cat | install | -| chcon | ls | -| chgrp | more | -| chmod | numfmt | -| chown | od (`--strings` and 128-bit data types missing) | -| chroot | pr | -| cksum | printf | -| comm | sort | -| csplit | split | -| cut | tac | -| dircolors | test | -| dirname | dir | -| du | vdir | -| echo | stty | -| env | | -| expand | | -| factor | | -| false | | -| fmt | | -| fold | | -| groups | | -| hashsum | | -| head | | -| hostid | | -| hostname | | -| id | | -| join | | -| kill | | -| link | | -| ln | | -| logname | | -| ~~md5sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha1sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha224sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha256sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha384sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha512sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| mkdir | | -| mkfifo | | -| mknod | | -| mktemp | | -| mv | | -| nice | | -| nl | | -| nohup | | -| nproc | | -| paste | | -| pathchk | | -| pinky | | -| printenv | | -| ptx | | -| pwd | | -| readlink | | -| realpath | | -| relpath | | -| rm | | -| rmdir | | -| runcon | | -| seq | | -| shred | | -| shuf | | -| sleep | | -| stat | | -| stdbuf | | -| sum | | -| sync | | -| tail | | -| tee | | -| timeout | | -| touch | | -| tr | | -| true | | -| truncate | | -| tsort | | -| tty | | -| uname | | -| unexpand | | -| uniq | | -| unlink | | -| uptime | | -| users | | -| wc | | -| who | | -| whoami | | -| yes | | +| Done | WIP | +| ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------- | +| arch | cp | +| base32 | date | +| base64 | dd | +| basename | df | +| basenc | expr | +| cat | install | +| chcon | ls | +| chgrp | more | +| chmod | numfmt | +| chown | od (`--strings` and 128-bit data types missing) | +| chroot | pr | +| cksum | printf | +| comm | sort | +| csplit | split | +| cut | tac | +| dircolors | test | +| dirname | dir | +| du | vdir | +| echo | stty | +| env | | +| expand | | +| factor | | +| false | | +| fmt | | +| fold | | +| groups | | +| hashsum | | +| head | | +| hostid | | +| hostname | | +| id | | +| join | | +| kill | | +| link | | +| ln | | +| logname | | +| ~~md5sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | +| ~~sha1sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | +| ~~sha224sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | +| ~~sha256sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | +| ~~sha384sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | +| ~~sha512sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | +| mkdir | | +| mkfifo | | +| mknod | | +| mktemp | | +| mv | | +| nice | | +| nl | | +| nohup | | +| nproc | | +| paste | | +| pathchk | | +| pinky | | +| printenv | | +| ptx | | +| pwd | | +| readlink | | +| realpath | | +| relpath | | +| rm | | +| rmdir | | +| runcon | | +| seq | | +| shred | | +| shuf | | +| sleep | | +| stat | | +| stdbuf | | +| sum | | +| sync | | +| tail | | +| tee | | +| timeout | | +| touch | | +| tr | | +| true | | +| truncate | | +| tsort | | +| tty | | +| uname | | +| unexpand | | +| uniq | | +| unlink | | +| uptime | | +| users | | +| wc | | +| who | | +| whoami | | +| yes | | ## License From 20fcce1c21e647c493f5308fe1294541e6cfe7ea Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Mar 2023 17:26:18 +0100 Subject: [PATCH 29/60] README: remove list of utilities This was barely being updated and categorized subjectively instead of by a useful measure, so it did more harm than good. --- README.md | 107 ++---------------------------------------------------- 1 file changed, 3 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index d2351417f..fb4e860a1 100644 --- a/README.md +++ b/README.md @@ -296,116 +296,15 @@ Below is the evolution of how many GNU tests uutils passes. A more detailed breakdown of the GNU test results of the main branch can be found [in the user manual](https://uutils.github.io/user/test_coverage.html). +See for the main meta bugs +(many are missing). + ![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). -## Utilities - -Please note that this is not fully accurate: - -- Some new options can be added / removed in the GNU implementation; -- Some error management might be missing; -- Some behaviors might be different. - -See for the main meta bugs -(many are missing). - -| Done | WIP | -| ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------- | -| arch | cp | -| base32 | date | -| base64 | dd | -| basename | df | -| basenc | expr | -| cat | install | -| chcon | ls | -| chgrp | more | -| chmod | numfmt | -| chown | od (`--strings` and 128-bit data types missing) | -| chroot | pr | -| cksum | printf | -| comm | sort | -| csplit | split | -| cut | tac | -| dircolors | test | -| dirname | dir | -| du | vdir | -| echo | stty | -| env | | -| expand | | -| factor | | -| false | | -| fmt | | -| fold | | -| groups | | -| hashsum | | -| head | | -| hostid | | -| hostname | | -| id | | -| join | | -| kill | | -| link | | -| ln | | -| logname | | -| ~~md5sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha1sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha224sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha256sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha384sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| ~~sha512sum~~ (replaced by [hashsum](https://github.com/uutils/coreutils/blob/main/src/uu/hashsum/src/hashsum.rs)) | | -| mkdir | | -| mkfifo | | -| mknod | | -| mktemp | | -| mv | | -| nice | | -| nl | | -| nohup | | -| nproc | | -| paste | | -| pathchk | | -| pinky | | -| printenv | | -| ptx | | -| pwd | | -| readlink | | -| realpath | | -| relpath | | -| rm | | -| rmdir | | -| runcon | | -| seq | | -| shred | | -| shuf | | -| sleep | | -| stat | | -| stdbuf | | -| sum | | -| sync | | -| tail | | -| tee | | -| timeout | | -| touch | | -| tr | | -| true | | -| truncate | | -| tsort | | -| tty | | -| uname | | -| unexpand | | -| uniq | | -| unlink | | -| uptime | | -| users | | -| wc | | -| who | | -| whoami | | -| yes | | - ## License uutils is licensed under the MIT License - see the `LICENSE` file for details From 1d24c94341c8ff52825cd17233304ec971640942 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Mar 2023 17:37:52 +0100 Subject: [PATCH 30/60] CONTRIBUTING: remove instructions for new utils --- CONTRIBUTING.md | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9af1948fe..6747bf46c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,21 +2,11 @@ # Contributing to coreutils -Contributions are very welcome, and should target Rust's main branch until the -standard libraries are stabilized. You may *claim* an item on the to-do list by -following these steps: - -1. Open an issue named "Implement [the utility of your choice]", e.g. "Implement - ls". -1. State that you are working on this utility. -1. Develop the utility. -1. Add integration tests. -1. Add the reference to your utility into Cargo.toml and Makefile. -1. Remove utility from the to-do list in the README. -1. Submit a pull request and close the issue. - -The steps above imply that, before starting to work on a utility, you should -search the issues to make sure no one else is working on it. +Contributions are very welcome via Pull Requests. If you don't know where to +start, take a look at the +[`good-first-issues`](https://github.com/uutils/coreutils/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). +If you have any questions, feel free to ask them in the issues or on +[Discord](https://discord.gg/wQVJbvJ). ## Best practices From de1f0ef315297ae60b3b566f26e9f70e190c9b79 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Mar 2023 17:58:37 +0100 Subject: [PATCH 31/60] Merge DEVELOPER_INSTRUCTIONS into CONTRIBUTING --- CONTRIBUTING.md | 106 ++++++++++++++++++++++++++++++++++---- DEVELOPER_INSTRUCTIONS.md | 68 ------------------------ 2 files changed, 96 insertions(+), 78 deletions(-) delete mode 100644 DEVELOPER_INSTRUCTIONS.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6747bf46c..ca4478d25 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,13 +30,81 @@ If you have any questions, feel free to ask them in the issues or on ## Platforms -We take pride in supporting many operating systems and architectures. +We take pride in supporting many operating systems and architectures. Any code +you contribute must at least compile without warnings for all platforms in the +CI. However, you can use `#[cfg(...)]` attributes to create platform dependent features. -**Tip:** -For Windows, Microsoft provides some images (VMWare, Hyper-V, VirtualBox and Parallels) -for development: +**Tip:** For Windows, Microsoft provides some images (VMWare, Hyper-V, +VirtualBox and Parallels) for development: +## Tools + +We have an extensive CI that will check your code before it can be merged. This +section explains how to run those checks locally to avoid waiting for the CI. + +### pre-commit hooks + +A configuration for `pre-commit` is provided in the repository. It allows +automatically checking every git commit you make to ensure it compiles, and +passes `clippy` and `rustfmt` without warnings. + +To use the provided hook: + +1. [Install `pre-commit`](https://pre-commit.com/#install) +1. Run `pre-commit install` while in the repository directory + +Your git commits will then automatically be checked. If a check fails, an error +message will explain why, and your commit will be canceled. You can then make +the suggested changes, and run `git commit ...` again. + +### clippy + +```shell +cargo clippy --all-targets --all-features +``` + +The `msrv` key in the clippy configuration file `clippy.toml` is used to disable +lints pertaining to newer features by specifying the minimum supported Rust +version (MSRV). + +### rustfmt + +```shell +cargo fmt --all +``` + +### cargo-deny + +This project uses [cargo-deny](https://github.com/EmbarkStudios/cargo-deny/) to +detect duplicate dependencies, checks licenses, etc. To run it locally, first +install it and then run with: + +``` +cargo deny --all-features check all +``` + +### Markdown linter + +We use [markdownlint](https://github.com/DavidAnson/markdownlint) to lint the +Markdown files in the repository. + +### Spell checker + +We use `cspell` as spell checker for all files in the project. If you are using +VS Code, you can install the +[code spell checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) +extension to enable spell checking within your editor. Otherwise, you can +install [cspell](https://cspell.org/) separately. + +If you want to make the spell checker ignore a word, you can add + +```rust +// spell-checker:ignore word_to_ignore +``` + +at the top of the file. + ## Testing Testing can be done using either Cargo or `make`. @@ -225,15 +293,33 @@ uutils: add new utility gitignore: add temporary files ``` -## cargo-deny +## Code coverage -This project uses [cargo-deny](https://github.com/EmbarkStudios/cargo-deny/) to -detect duplicate dependencies, checks licenses, etc. To run it locally, first -install it and then run with: + +Code coverage report can be generated using [grcov](https://github.com/mozilla/grcov). + +### Using Nightly Rust + +To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project) coverage report + +```shell +export CARGO_INCREMENTAL=0 +export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" +export RUSTDOCFLAGS="-Cpanic=abort" +cargo build # e.g., --features feat_os_unix +cargo test # e.g., --features feat_os_unix test_pathchk +grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing --ignore build.rs --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?\#\[derive\()" -o ./target/debug/coverage/ +# open target/debug/coverage/index.html in browser ``` -cargo deny --all-features check all -``` + +if changes are not reflected in the report then run `cargo clean` and run the above commands. + +### Using Stable Rust + +If you are using stable version of Rust that doesn't enable code coverage instrumentation by default +then add `-Z-Zinstrument-coverage` flag to `RUSTFLAGS` env variable specified above. + ## Other implementations diff --git a/DEVELOPER_INSTRUCTIONS.md b/DEVELOPER_INSTRUCTIONS.md deleted file mode 100644 index 3641f57b9..000000000 --- a/DEVELOPER_INSTRUCTIONS.md +++ /dev/null @@ -1,68 +0,0 @@ -# Documentation - -The source of the documentation is available on: - - - -The documentation is updated everyday on this repository: - - - -## Running GNU tests - - - -- Check out next to your fork as gnu -- Check out next to your fork as gnulib -- Rename the checkout of your fork to uutils - -At the end you should have uutils, gnu and gnulib checked out next to each other. - -- Run `cd uutils && ./util/build-gnu.sh && cd ..` to get everything ready (this may take a while) -- Finally, you can run tests with `bash uutils/util/run-gnu-test.sh `. Instead of `` insert the tests you want to run, e.g. `tests/misc/wc-proc.sh`. - -## Code Coverage Report Generation - - - -Code coverage report can be generated using [grcov](https://github.com/mozilla/grcov). - -### Using Nightly Rust - -To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project) coverage report - -```shell -export CARGO_INCREMENTAL=0 -export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" -export RUSTDOCFLAGS="-Cpanic=abort" -cargo build # e.g., --features feat_os_unix -cargo test # e.g., --features feat_os_unix test_pathchk -grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing --ignore build.rs --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?\#\[derive\()" -o ./target/debug/coverage/ -# open target/debug/coverage/index.html in browser -``` - -if changes are not reflected in the report then run `cargo clean` and run the above commands. - -### Using Stable Rust - -If you are using stable version of Rust that doesn't enable code coverage instrumentation by default -then add `-Z-Zinstrument-coverage` flag to `RUSTFLAGS` env variable specified above. - -## pre-commit hooks - -A configuration for `pre-commit` is provided in the repository. It allows automatically checking every git commit you make to ensure it compiles, and passes `clippy` and `rustfmt` without warnings. - -To use the provided hook: - -1. [Install `pre-commit`](https://pre-commit.com/#install) -1. Run `pre-commit install` while in the repository directory - -Your git commits will then automatically be checked. If a check fails, an error message will explain why, and your commit will be canceled. You can then make the suggested changes, and run `git commit ...` again. - -## Using Clippy - -The `msrv` key in the clippy configuration file `clippy.toml` is used to disable lints pertaining to newer features by specifying the minimum supported Rust version (MSRV). However, this key is only supported on `nightly`. To invoke clippy without errors, use `cargo +nightly clippy`. In order to also check tests and non-default crate features, use `cargo +nightly clippy --all-targets --all-features`. - -## Markdown linter - -We use to lint the Markdown files. From 4dd618e67becb520f6d41ddaa22e93014782206c Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Tue, 14 Mar 2023 21:53:22 +0100 Subject: [PATCH 32/60] README and CONTRIBUTING: markdown and spelling fixes --- CONTRIBUTING.md | 2 +- README.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca4478d25..6edfea44c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ - + # Contributing to coreutils diff --git a/README.md b/README.md index fb4e860a1..8b57855b5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ + + +
![uutils logo](docs/src/logo.svg) @@ -17,8 +20,6 @@ --- - - 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 From 1435d3573a59d64e156b99f2a46317b32256ddf6 Mon Sep 17 00:00:00 2001 From: Miles Liu Date: Wed, 15 Mar 2023 18:08:32 +0800 Subject: [PATCH 33/60] dd: fix unused imports on FreeBSD --- tests/by-util/test_dd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 5deeb12f0..71dd92da4 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -5,7 +5,7 @@ use crate::common::util::*; use std::fs::{File, OpenOptions}; use std::io::{BufReader, Read, Write}; use std::path::PathBuf; -#[cfg(all(not(windows), not(target_os = "macos")))] +#[cfg(all(unix, not(target_os = "macos"), not(target_os = "freebsd")))] use std::process::{Command, Stdio}; #[cfg(not(windows))] use std::thread::sleep; From 6c9d007d5bb90552e58162e3f3db782f98ef0a13 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 15 Mar 2023 16:56:11 +0100 Subject: [PATCH 34/60] Use https in link & fix quote in CONTRIBUTING.md --- CONTRIBUTING.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6edfea44c..8199b6d87 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -240,24 +240,30 @@ To improve the GNU compatibility, the following process is recommended: To help the project maintainers review pull requests from contributors across numerous utilities, the team has settled on conventions for commit messages. -From : +From : ``` -Short (50 chars or less) summary of changes +Capitalized, short (50 chars or less) summary More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of an email and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit -the body entirely); tools like rebase can get confused if you run the +the body entirely); tools like rebase will confuse you if you run the two together. +Write your commit message in the imperative: "Fix bug" and not "Fixed bug" +or "Fixes bug." This convention matches up with commit messages generated +by commands like git merge and git revert. + Further paragraphs come after blank lines. - Bullet points are okay, too - - Typically a hyphen or asterisk is used for the bullet, preceded by a + - Typically a hyphen or asterisk is used for the bullet, followed by a single space, with blank lines in between, but conventions vary here + + - Use a hanging indent ``` Furthermore, here are a few examples for a summary line: From 61ad84f4478ca75f6007c58574f82a8b9e12f4b7 Mon Sep 17 00:00:00 2001 From: ValentinyFilip <80767029+ValentinyFilip@users.noreply.github.com> Date: Wed, 15 Mar 2023 19:09:38 +0100 Subject: [PATCH 35/60] cksum: move help strings to markdown file --- src/uu/cksum/cksum.md | 23 +++++++++++++++++++++++ src/uu/cksum/src/cksum.rs | 25 +++++++------------------ 2 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 src/uu/cksum/cksum.md diff --git a/src/uu/cksum/cksum.md b/src/uu/cksum/cksum.md new file mode 100644 index 000000000..b613d4d43 --- /dev/null +++ b/src/uu/cksum/cksum.md @@ -0,0 +1,23 @@ +# cksum + +``` +cksum [OPTIONS] [FILE]... +``` + +Print CRC and size for each file + +## After Help + +DIGEST determines the digest algorithm and default output format: + +-a=sysv: (equivalent to sum -s) +-a=bsd: (equivalent to sum -r) +-a=crc: (equivalent to cksum) +-a=md5: (equivalent to md5sum) +-a=sha1: (equivalent to sha1sum) +-a=sha224: (equivalent to sha224sum) +-a=sha256: (equivalent to sha256sum) +-a=sha384: (equivalent to sha384sum) +-a=sha512: (equivalent to sha512sum) +-a=blake2b: (equivalent to b2sum) +-a=sm3: (only available through cksum) diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index e66d5f029..6cde7f6c1 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -20,10 +20,14 @@ use uucore::{ div_ceil, Blake2b, Digest, DigestWriter, Md5, Sha1, Sha224, Sha256, Sha384, Sha512, Sm3, BSD, CRC, SYSV, }, + help_about, + help_usage, + help_section, }; -const USAGE: &str = "{} [OPTIONS] [FILE]..."; -const ABOUT: &str = "Print CRC and size for each file"; +const USAGE: &str = help_usage!("cksum.md"); +const ABOUT: &str = help_about!("cksum.md"); +const AFTER_HELP: &str = help_section!("after help", "cksum.md"); const ALGORITHM_OPTIONS_SYSV: &str = "sysv"; const ALGORITHM_OPTIONS_BSD: &str = "bsd"; @@ -205,21 +209,6 @@ mod options { pub static ALGORITHM: &str = "algorithm"; } -const ALGORITHM_HELP_DESC: &str = - "DIGEST determines the digest algorithm and default output format:\n\ -\n\ --a=sysv: (equivalent to sum -s)\n\ --a=bsd: (equivalent to sum -r)\n\ --a=crc: (equivalent to cksum)\n\ --a=md5: (equivalent to md5sum)\n\ --a=sha1: (equivalent to sha1sum)\n\ --a=sha224: (equivalent to sha224sum)\n\ --a=sha256: (equivalent to sha256sum)\n\ --a=sha384: (equivalent to sha384sum)\n\ --a=sha512: (equivalent to sha512sum)\n\ --a=blake2b: (equivalent to b2sum)\n\ --a=sm3: (only available through cksum)\n"; - #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args.collect_ignore(); @@ -278,5 +267,5 @@ pub fn uu_app() -> Command { ALGORITHM_OPTIONS_SM3, ]), ) - .after_help(ALGORITHM_HELP_DESC) + .after_help(AFTER_HELP) } From 7c6a948526f520903f5d502178e494a308abdfb8 Mon Sep 17 00:00:00 2001 From: ValentinyFilip <80767029+ValentinyFilip@users.noreply.github.com> Date: Wed, 15 Mar 2023 21:05:55 +0100 Subject: [PATCH 36/60] cksum: fix format error --- src/uu/cksum/src/cksum.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index 6cde7f6c1..9bddd3d7a 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -15,14 +15,11 @@ use std::iter; use std::path::Path; use uucore::{ error::{FromIo, UResult}, - format_usage, + format_usage, help_about, help_section, help_usage, sum::{ div_ceil, Blake2b, Digest, DigestWriter, Md5, Sha1, Sha224, Sha256, Sha384, Sha512, Sm3, BSD, CRC, SYSV, }, - help_about, - help_usage, - help_section, }; const USAGE: &str = help_usage!("cksum.md"); From 2e36fa4f169482c57acf7704f3b9cdc6d71d1552 Mon Sep 17 00:00:00 2001 From: ValentinyFilip <80767029+ValentinyFilip@users.noreply.github.com> Date: Thu, 16 Mar 2023 09:49:48 +0100 Subject: [PATCH 37/60] cksum: fix markdown format --- src/uu/cksum/cksum.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/uu/cksum/cksum.md b/src/uu/cksum/cksum.md index b613d4d43..c54132ef5 100644 --- a/src/uu/cksum/cksum.md +++ b/src/uu/cksum/cksum.md @@ -10,14 +10,14 @@ Print CRC and size for each file DIGEST determines the digest algorithm and default output format: --a=sysv: (equivalent to sum -s) --a=bsd: (equivalent to sum -r) --a=crc: (equivalent to cksum) --a=md5: (equivalent to md5sum) --a=sha1: (equivalent to sha1sum) --a=sha224: (equivalent to sha224sum) --a=sha256: (equivalent to sha256sum) --a=sha384: (equivalent to sha384sum) --a=sha512: (equivalent to sha512sum) --a=blake2b: (equivalent to b2sum) --a=sm3: (only available through cksum) +- `-a=sysv`: (equivalent to sum -s) +- `-a=bsd`: (equivalent to sum -r) +- `-a=crc`: (equivalent to cksum) +- `-a=md5`: (equivalent to md5sum) +- `-a=sha1`: (equivalent to sha1sum) +- `-a=sha224`: (equivalent to sha224sum) +- `-a=sha256`: (equivalent to sha256sum) +- `-a=sha384`: (equivalent to sha384sum) +- `-a=sha512`: (equivalent to sha512sum) +- `-a=blake2b`: (equivalent to b2sum) +- `-a=sm3`: (only available through cksum) From f623a7e13aa215912dc8278b026ad1fc8355beb9 Mon Sep 17 00:00:00 2001 From: Miles Liu Date: Thu, 16 Mar 2023 17:57:00 +0800 Subject: [PATCH 38/60] whoami: move help strings to markdown file --- src/uu/whoami/src/whoami.rs | 5 ++++- src/uu/whoami/whoami.md | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 src/uu/whoami/whoami.md diff --git a/src/uu/whoami/src/whoami.rs b/src/uu/whoami/src/whoami.rs index 18c61e28e..04360fe7a 100644 --- a/src/uu/whoami/src/whoami.rs +++ b/src/uu/whoami/src/whoami.rs @@ -11,10 +11,12 @@ use clap::{crate_version, Command}; use uucore::display::println_verbatim; use uucore::error::{FromIo, UResult}; +use uucore::{format_usage, help_about, help_usage}; mod platform; -static ABOUT: &str = "Print the current username."; +const ABOUT: &str = help_about!("whoami.md"); +const USAGE: &str = help_usage!("whoami.md"); #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { @@ -28,5 +30,6 @@ pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) + .override_usage(format_usage(USAGE)) .infer_long_args(true) } diff --git a/src/uu/whoami/whoami.md b/src/uu/whoami/whoami.md new file mode 100644 index 000000000..6106d24ee --- /dev/null +++ b/src/uu/whoami/whoami.md @@ -0,0 +1,7 @@ +# whoami + +``` +whoami +``` + +Print the current username. From 66fef28ec66dd74a42b576e1088fb29e4ff57879 Mon Sep 17 00:00:00 2001 From: Miles Liu Date: Thu, 16 Mar 2023 17:48:55 +0800 Subject: [PATCH 39/60] uptime: move help strings to markdown file --- src/uu/uptime/src/uptime.rs | 8 +++----- src/uu/uptime/uptime.md | 9 +++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 src/uu/uptime/uptime.md diff --git a/src/uu/uptime/src/uptime.rs b/src/uu/uptime/src/uptime.rs index 3a561f419..7d54263eb 100644 --- a/src/uu/uptime/src/uptime.rs +++ b/src/uu/uptime/src/uptime.rs @@ -11,17 +11,15 @@ use chrono::{Local, TimeZone, Utc}; use clap::{crate_version, Arg, ArgAction, Command}; -use uucore::format_usage; +use uucore::{format_usage, help_about, help_usage}; // import crate time from utmpx pub use uucore::libc; use uucore::libc::time_t; use uucore::error::{UResult, USimpleError}; -static ABOUT: &str = "Display the current time, the length of time the system has been up,\n\ - the number of users on the system, and the average number of jobs\n\ - in the run queue over the last 1, 5 and 15 minutes."; -const USAGE: &str = "{} [OPTION]..."; +const ABOUT: &str = help_about!("uptime.md"); +const USAGE: &str = help_usage!("uptime.md"); pub mod options { pub static SINCE: &str = "since"; } diff --git a/src/uu/uptime/uptime.md b/src/uu/uptime/uptime.md new file mode 100644 index 000000000..fd9c8fd2f --- /dev/null +++ b/src/uu/uptime/uptime.md @@ -0,0 +1,9 @@ +# uptime + +``` +uptime [OPTION]... +``` + +Display the current time, the length of time the system has been up, +the number of users on the system, and the average number of jobs +in the run queue over the last 1, 5 and 15 minutes. From 6956377405cbc063a7b6c9bd324e7660d3bfdf57 Mon Sep 17 00:00:00 2001 From: Miles Liu Date: Thu, 16 Mar 2023 19:44:27 +0800 Subject: [PATCH 40/60] uptime: remove unused import --- src/uu/uptime/src/uptime.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/uu/uptime/src/uptime.rs b/src/uu/uptime/src/uptime.rs index 7d54263eb..6f4e62084 100644 --- a/src/uu/uptime/src/uptime.rs +++ b/src/uu/uptime/src/uptime.rs @@ -11,10 +11,8 @@ use chrono::{Local, TimeZone, Utc}; use clap::{crate_version, Arg, ArgAction, Command}; -use uucore::{format_usage, help_about, help_usage}; -// import crate time from utmpx -pub use uucore::libc; use uucore::libc::time_t; +use uucore::{format_usage, help_about, help_usage}; use uucore::error::{UResult, USimpleError}; From ac23dca426a6132300b9b21ce412c2845e0fdc50 Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Thu, 16 Mar 2023 15:53:43 +0100 Subject: [PATCH 41/60] tests/date: Added tests for date ISO8601 formats. Regex matching for correctness check. Tests for format with `minute`, `hour` and `date` added. --- tests/by-util/test_date.rs | 57 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index a1064a8fa..bedbc959d 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -45,15 +45,68 @@ fn test_date_rfc_3339() { #[test] fn test_date_rfc_8601() { + let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{9}[+-]\d{2}:\d{2}\n$").unwrap(); for param in ["--iso-8601", "--i"] { - new_ucmd!().arg(format!("{param}=ns")).succeeds(); + new_ucmd!() + .arg(format!("{param}=ns")) + .succeeds() + .stdout_matches(&re); } } #[test] fn test_date_rfc_8601_second() { + let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}\n$").unwrap(); for param in ["--iso-8601", "--i"] { - new_ucmd!().arg(format!("{param}=second")).succeeds(); + new_ucmd!() + .arg(format!("{param}=second")) + .succeeds() + .stdout_matches(&re); + new_ucmd!() + .arg(format!("{param}=seconds")) + .succeeds() + .stdout_matches(&re); + } +} + +#[test] +fn test_date_rfc_8601_minute() { + let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}[+-]\d{2}:\d{2}\n$").unwrap(); + for param in ["--iso-8601", "--i"] { + new_ucmd!() + .arg(format!("{param}=minute")) + .succeeds() + .stdout_matches(&re); + new_ucmd!() + .arg(format!("{param}=minutes")) + .succeeds() + .stdout_matches(&re); + } +} + +#[test] +fn test_date_rfc_8601_hour() { + let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}[+-]\d{2}:\d{2}\n$").unwrap(); + for param in ["--iso-8601", "--i"] { + new_ucmd!() + .arg(format!("{param}=hour")) + .succeeds() + .stdout_matches(&re); + new_ucmd!() + .arg(format!("{param}=hours")) + .succeeds() + .stdout_matches(&re); + } +} + +#[test] +fn test_date_rfc_8601_date() { + let re = Regex::new(r"^\d{4}-\d{2}-\d{2}\n$").unwrap(); + for param in ["--iso-8601", "--i"] { + new_ucmd!() + .arg(format!("{param}=date")) + .succeeds() + .stdout_matches(&re); } } From bd6905cf59a91ab08ebda7faa0fecc48a3597d64 Mon Sep 17 00:00:00 2001 From: Surya Teja K Date: Fri, 17 Mar 2023 01:20:37 +0530 Subject: [PATCH 42/60] fix: match date -I error messages with GNU date (#4499) * date: use value_parser to improve errors * date: update panic! to unreachable inside impl From for Iso8601Format --- src/uu/date/src/date.rs | 5 +++-- tests/by-util/test_date.rs | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 50736b2da..9368ef91f 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -114,8 +114,8 @@ impl<'a> From<&'a str> for Iso8601Format { SECONDS | SECOND => Self::Seconds, NS => Self::Ns, DATE => Self::Date, - // Should be caught by clap - _ => panic!("Invalid format: {s}"), + // Note: This is caught by clap via `possible_values` + _ => unreachable!(), } } } @@ -291,6 +291,7 @@ pub fn uu_app() -> Command { .short('I') .long(OPT_ISO_8601) .value_name("FMT") + .value_parser([DATE, HOUR, HOURS, MINUTE, MINUTES, SECOND, SECONDS, NS]) .help(ISO_8601_HELP_STRING), ) .arg( diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index a1064a8fa..6f471bb3e 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -50,6 +50,13 @@ fn test_date_rfc_8601() { } } +#[test] +fn test_date_rfc_8601_invalid_arg() { + for param in ["--iso-8601", "--i"] { + new_ucmd!().arg(format!("{param}=@")).fails(); + } +} + #[test] fn test_date_rfc_8601_second() { for param in ["--iso-8601", "--i"] { From 787d854f891a958de5dff0abb10db77f7e85ab37 Mon Sep 17 00:00:00 2001 From: Benjamin Bara Date: Mon, 27 Feb 2023 22:21:41 +0100 Subject: [PATCH 43/60] chmod: add GNU usage tests --- tests/by-util/test_chmod.rs | 65 +++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index b5f8ca5c5..83b633400 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -671,3 +671,68 @@ fn test_quiet_n_verbose_used_multiple_times() { .arg("file") .succeeds(); } + +#[test] +fn test_gnu_invalid_mode() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("file"); + scene.ucmd().arg("u+gr").arg("file").fails(); +} + +#[test] +fn test_gnu_options() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("file"); + scene.ucmd().arg("-w").arg("file").succeeds(); + scene.ucmd().arg("file").arg("-w").succeeds(); + scene.ucmd().arg("-w").arg("--").arg("file").succeeds(); +} + +#[test] +fn test_gnu_reoccuring_options() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("file"); + scene.ucmd().arg("-w").arg("-w").arg("file").succeeds(); + scene + .ucmd() + .arg("-w") + .arg("-w") + .arg("-w") + .arg("file") + .succeeds(); +} + +#[test] +fn test_gnu_special_filenames() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + let perms_before = Permissions::from_mode(0o100640); + let perms_after = Permissions::from_mode(0o100440); + + make_file(&at.plus_as_string("--"), perms_before.mode()); + scene.ucmd().arg("-w").arg("--").arg("--").succeeds(); + assert_eq!(at.metadata("--").permissions(), perms_after); + set_permissions(at.plus("--"), perms_before.clone()).unwrap(); + scene.ucmd().arg("--").arg("-w").arg("--").succeeds(); + assert_eq!(at.metadata("--").permissions(), perms_after); + at.remove("--"); + + make_file(&at.plus_as_string("-w"), perms_before.mode()); + scene.ucmd().arg("-w").arg("--").arg("-w").succeeds(); + assert_eq!(at.metadata("-w").permissions(), perms_after); + set_permissions(at.plus("-w"), perms_before).unwrap(); + scene.ucmd().arg("--").arg("-w").arg("-w").succeeds(); + assert_eq!(at.metadata("-w").permissions(), perms_after); +} + +#[test] +fn test_gnu_special_options() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.touch("file"); + scene.ucmd().arg("--").arg("--").arg("file").succeeds(); + scene.ucmd().arg("--").arg("--").fails(); +} From e982d578190f859e6a422209c238db7f275cdf23 Mon Sep 17 00:00:00 2001 From: Benjamin Bara Date: Tue, 21 Feb 2023 20:01:52 +0100 Subject: [PATCH 44/60] chmod: fix GNU test 'chmod/usage' --- src/uu/chmod/src/chmod.rs | 106 +++++++++++++++++++++++++--- src/uucore/src/lib/features/mode.rs | 9 +++ tests/by-util/test_chmod.rs | 34 +-------- 3 files changed, 106 insertions(+), 43 deletions(-) diff --git a/src/uu/chmod/src/chmod.rs b/src/uu/chmod/src/chmod.rs index ec92d4bac..14d761cf9 100644 --- a/src/uu/chmod/src/chmod.rs +++ b/src/uu/chmod/src/chmod.rs @@ -8,6 +8,7 @@ // spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's use clap::{crate_version, Arg, ArgAction, Command}; +use std::ffi::OsString; use std::fs; use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::path::Path; @@ -35,14 +36,64 @@ mod options { pub const FILE: &str = "FILE"; } +/// Extract negative modes (starting with '-') from the rest of the arguments. +/// +/// This is mainly required for GNU compatibility, where "non-positional negative" modes are used +/// as the actual positional MODE. Some examples of these cases are: +/// * "chmod -w -r file", which is the same as "chmod -w,-r file" +/// * "chmod -w file -r", which is the same as "chmod -w,-r file" +/// +/// These can currently not be handled by clap. +/// Therefore it might be possible that a pseudo MODE is inserted to pass clap parsing. +/// The pseudo MODE is later replaced by the extracted (and joined) negative modes. +fn extract_negative_modes(mut args: impl uucore::Args) -> (Option, Vec) { + // we look up the args until "--" is found + // "-mode" will be extracted into parsed_cmode_vec + let (parsed_cmode_vec, pre_double_hyphen_args): (Vec, Vec) = + args.by_ref().take_while(|a| a != "--").partition(|arg| { + let arg = if let Some(arg) = arg.to_str() { + arg.to_string() + } else { + return false; + }; + arg.len() >= 2 + && arg.starts_with('-') + && matches!( + arg.chars().nth(1).unwrap(), + 'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' + ) + }); + + let mut clean_args = Vec::new(); + if !parsed_cmode_vec.is_empty() { + // we need a pseudo cmode for clap, which won't be used later. + // this is required because clap needs the default "chmod MODE FILE" scheme. + clean_args.push("w".into()); + } + clean_args.extend(pre_double_hyphen_args); + + if let Some(arg) = args.next() { + // as there is still something left in the iterator, we previously consumed the "--" + // -> add it to the args again + clean_args.push("--".into()); + clean_args.push(arg); + } + clean_args.extend(args); + + let parsed_cmode = Some( + parsed_cmode_vec + .iter() + .map(|s| s.to_str().unwrap()) + .collect::>() + .join(","), + ) + .filter(|s| !s.is_empty()); + (parsed_cmode, clean_args) +} + #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let mut args = args.collect_lossy(); - - // Before we can parse 'args' with clap (and previously getopts), - // a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE"). - let mode_had_minus_prefix = mode::strip_minus_from_mode(&mut args); - + let (parsed_cmode, args) = extract_negative_modes(args.skip(1)); // skip binary name let matches = uu_app().after_help(LONG_USAGE).try_get_matches_from(args)?; let changes = matches.get_flag(options::CHANGES); @@ -62,13 +113,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }, None => None, }; - let modes = matches.get_one::(options::MODE).unwrap(); // should always be Some because required - let cmode = if mode_had_minus_prefix { - // clap parsing is finished, now put prefix back - format!("-{modes}") + + let modes = matches.get_one::(options::MODE); + let cmode = if let Some(parsed_cmode) = parsed_cmode { + parsed_cmode } else { - modes.to_string() + modes.unwrap().to_string() // modes is required }; + // FIXME: enable non-utf8 paths let mut files: Vec = matches .get_many::(options::FILE) .map(|v| v.map(ToString::to_string).collect()) @@ -107,6 +159,7 @@ pub fn uu_app() -> Command { .override_usage(format_usage(USAGE)) .args_override_self(true) .infer_long_args(true) + .no_binary_name(true) .arg( Arg::new(options::CHANGES) .long(options::CHANGES) @@ -376,3 +429,34 @@ impl Chmoder { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_extract_negative_modes() { + // "chmod -w -r file" becomes "chmod -w,-r file". clap does not accept "-w,-r" as MODE. + // Therefore, "w" is added as pseudo mode to pass clap. + let (c, a) = extract_negative_modes(vec!["-w", "-r", "file"].iter().map(OsString::from)); + assert_eq!(c, Some("-w,-r".to_string())); + assert_eq!(a, vec!["w", "file"]); + + // "chmod -w file -r" becomes "chmod -w,-r file". clap does not accept "-w,-r" as MODE. + // Therefore, "w" is added as pseudo mode to pass clap. + let (c, a) = extract_negative_modes(vec!["-w", "file", "-r"].iter().map(OsString::from)); + assert_eq!(c, Some("-w,-r".to_string())); + assert_eq!(a, vec!["w", "file"]); + + // "chmod -w -- -r file" becomes "chmod -w -r file", where "-r" is interpreted as file. + // Again, "w" is needed as pseudo mode. + let (c, a) = extract_negative_modes(vec!["-w", "--", "-r", "f"].iter().map(OsString::from)); + assert_eq!(c, Some("-w".to_string())); + assert_eq!(a, vec!["w", "--", "-r", "f"]); + + // "chmod -- -r file" becomes "chmod -r file". + let (c, a) = extract_negative_modes(vec!["--", "-r", "file"].iter().map(OsString::from)); + assert_eq!(c, None); + assert_eq!(a, vec!["--", "-r", "file"]); + } +} diff --git a/src/uucore/src/lib/features/mode.rs b/src/uucore/src/lib/features/mode.rs index 956981254..a54824d18 100644 --- a/src/uucore/src/lib/features/mode.rs +++ b/src/uucore/src/lib/features/mode.rs @@ -122,6 +122,15 @@ fn parse_change(mode: &str, fperm: u32, considering_dir: bool) -> (u32, usize) { 'o' => srwx = ((fperm << 6) & 0o700) | ((fperm << 3) & 0o070) | (fperm & 0o007), _ => break, }; + if ch == 'u' || ch == 'g' || ch == 'o' { + // symbolic modes only allows perms to be a single letter of 'ugo' + // therefore this must either be the first char or it is unexpected + if pos != 0 { + break; + } + pos = 1; + break; + } pos += 1; } if pos == 0 { diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index 83b633400..925643add 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -4,9 +4,8 @@ use std::fs::{metadata, set_permissions, OpenOptions, Permissions}; use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; use std::sync::Mutex; -extern crate libc; -use uucore::mode::strip_minus_from_mode; extern crate chmod; +extern crate libc; use self::libc::umask; static TEST_FILE: &str = "file"; @@ -503,35 +502,6 @@ fn test_chmod_symlink_non_existing_file_recursive() { .no_stderr(); } -#[test] -fn test_chmod_strip_minus_from_mode() { - let tests = vec![ - // ( before, after ) - ("chmod -v -xw -R FILE", "chmod -v xw -R FILE"), - ("chmod g=rwx FILE -c", "chmod g=rwx FILE -c"), - ( - "chmod -c -R -w,o+w FILE --preserve-root", - "chmod -c -R w,o+w FILE --preserve-root", - ), - ("chmod -c -R +w FILE ", "chmod -c -R +w FILE "), - ("chmod a=r,=xX FILE", "chmod a=r,=xX FILE"), - ( - "chmod -v --reference REF_FILE -R FILE", - "chmod -v --reference REF_FILE -R FILE", - ), - ("chmod -Rvc -w-x FILE", "chmod -Rvc w-x FILE"), - ("chmod 755 -v FILE", "chmod 755 -v FILE"), - ("chmod -v +0004 FILE -R", "chmod -v +0004 FILE -R"), - ("chmod -v -0007 FILE -R", "chmod -v 0007 FILE -R"), - ]; - - for test in tests { - let mut args: Vec = test.0.split(' ').map(|v| v.to_string()).collect(); - let _mode_had_minus_prefix = strip_minus_from_mode(&mut args); - assert_eq!(test.1, args.join(" ")); - } -} - #[test] fn test_chmod_keep_setgid() { for (from, arg, to) in [ @@ -691,7 +661,7 @@ fn test_gnu_options() { } #[test] -fn test_gnu_reoccuring_options() { +fn test_gnu_repeating_options() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; at.touch("file"); From 624588d37fbc301860af8dd60e40dac59083a53f Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Thu, 16 Mar 2023 18:50:08 +0100 Subject: [PATCH 45/60] date: Added default value for `date --i`. `default_missing_value` set to `OPT_DATE` (`"date"`) `num_args(0..=1)` required for `default_missing_value`. Using function name `test_date_rfc_8601_default`. The function name `test_date_rfc_8601` is left intact for compatibility. Fixes: #4521 --- src/uu/date/src/date.rs | 2 ++ tests/by-util/test_date.rs | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 9368ef91f..9a9a8cbf9 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -292,6 +292,8 @@ pub fn uu_app() -> Command { .long(OPT_ISO_8601) .value_name("FMT") .value_parser([DATE, HOUR, HOURS, MINUTE, MINUTES, SECOND, SECONDS, NS]) + .num_args(0..=1) + .default_missing_value(OPT_DATE) .help(ISO_8601_HELP_STRING), ) .arg( diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index d504ce419..e5da044fa 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -43,6 +43,14 @@ fn test_date_rfc_3339() { } } +#[test] +fn test_date_rfc_8601_default() { + let re = Regex::new(r"^\d{4}-\d{2}-\d{2}\n$").unwrap(); + for param in ["--iso-8601", "--i"] { + new_ucmd!().arg(param).succeeds().stdout_matches(&re); + } +} + #[test] fn test_date_rfc_8601() { let re = Regex::new(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{9}[+-]\d{2}:\d{2}\n$").unwrap(); From ab9d1030ff6c0f3bd1e373d0629ab7ad1eee4269 Mon Sep 17 00:00:00 2001 From: Miles Liu Date: Fri, 17 Mar 2023 14:37:15 +0800 Subject: [PATCH 46/60] shred: enable `test_shred_force` on FreeBSD --- tests/by-util/test_shred.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/by-util/test_shred.rs b/tests/by-util/test_shred.rs index 0780411f6..8992238b3 100644 --- a/tests/by-util/test_shred.rs +++ b/tests/by-util/test_shred.rs @@ -25,7 +25,6 @@ fn test_shred_remove() { assert!(at.file_exists(file_b)); } -#[cfg(not(target_os = "freebsd"))] #[test] fn test_shred_force() { let scene = TestScenario::new(util_name!()); From 1b1446ce0c722a0736a6f25a968d393eaeb86f99 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Fri, 17 Mar 2023 21:49:26 +0100 Subject: [PATCH 47/60] date: make sure 'invalid date' message also returns exit code 1 --- src/uu/date/src/date.rs | 7 +++++-- tests/by-util/test_date.rs | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 50736b2da..8337f64f1 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -22,7 +22,7 @@ use uucore::display::Quotable; #[cfg(not(any(target_os = "macos", target_os = "redox")))] use uucore::error::FromIo; use uucore::error::{UResult, USimpleError}; -use uucore::{format_usage, help_about, help_usage, show_error}; +use uucore::{format_usage, help_about, help_usage, show}; #[cfg(windows)] use windows_sys::Win32::{Foundation::SYSTEMTIME, System::SystemInformation::SetSystemTime}; @@ -257,7 +257,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .replace("%f", "%N"); println!("{formatted}"); } - Err((input, _err)) => show_error!("invalid date {}", input.quote()), + Err((input, _err)) => show!(USimpleError::new( + 1, + format!("invalid date {}", input.quote()) + )), } } } diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index a1064a8fa..85f9540ba 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -232,3 +232,13 @@ fn test_invalid_format_string() { result.no_stdout(); assert!(result.stderr_str().starts_with("date: invalid format ")); } + +#[test] +fn test_invalid_date_string() { + new_ucmd!() + .arg("-d") + .arg("foo") + .fails() + .no_stdout() + .stderr_contains("invalid date"); +} From 7f00dfda7645a40031a02a5e6764051c1f2035e4 Mon Sep 17 00:00:00 2001 From: Koki Ueha Date: Sat, 18 Mar 2023 12:43:00 +0000 Subject: [PATCH 48/60] mknod: move help strings to markdown file --- src/uu/mknod/mknod.md | 27 +++++++++++++++++++++++++++ src/uu/mknod/src/mknod.rs | 27 +++++---------------------- 2 files changed, 32 insertions(+), 22 deletions(-) create mode 100644 src/uu/mknod/mknod.md diff --git a/src/uu/mknod/mknod.md b/src/uu/mknod/mknod.md new file mode 100644 index 000000000..4cb366df9 --- /dev/null +++ b/src/uu/mknod/mknod.md @@ -0,0 +1,27 @@ +# mknod + +``` +mknod [OPTION]... NAME TYPE [MAJOR MINOR] +``` + +Create the special file NAME of the given TYPE. + +## After Help + +Mandatory arguments to long options are mandatory for short options too. +-m, --mode=MODE set file permission bits to MODE, not a=rw - umask +--help display this help and exit +--version output version information and exit + +Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they +must be omitted when TYPE is p. If MAJOR or MINOR begins with 0x or 0X, +it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal; +otherwise, as decimal. TYPE may be: + +b create a block (buffered) special file +c, u create a character (unbuffered) special file +p create a FIFO + +NOTE: your shell may have its own version of mknod, which usually supersedes +the version described here. Please refer to your shell's documentation +for details about the options it supports. diff --git a/src/uu/mknod/src/mknod.rs b/src/uu/mknod/src/mknod.rs index f4c6f5732..ad7618cc8 100644 --- a/src/uu/mknod/src/mknod.rs +++ b/src/uu/mknod/src/mknod.rs @@ -14,28 +14,11 @@ use std::ffi::CString; use uucore::display::Quotable; use uucore::error::{set_exit_code, UResult, USimpleError, UUsageError}; -use uucore::format_usage; +use uucore::{format_usage, help_about, help_section, help_usage}; -static ABOUT: &str = "Create the special file NAME of the given TYPE."; -static USAGE: &str = "{} [OPTION]... NAME TYPE [MAJOR MINOR]"; -static LONG_HELP: &str = "Mandatory arguments to long options are mandatory for short options too. --m, --mode=MODE set file permission bits to MODE, not a=rw - umask ---help display this help and exit ---version output version information and exit - -Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they -must be omitted when TYPE is p. If MAJOR or MINOR begins with 0x or 0X, -it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal; -otherwise, as decimal. TYPE may be: - -b create a block (buffered) special file -c, u create a character (unbuffered) special file -p create a FIFO - -NOTE: your shell may have its own version of mknod, which usually supersedes -the version described here. Please refer to your shell's documentation -for details about the options it supports. -"; +const ABOUT: &str = help_about!("mknod.md"); +const USAGE: &str = help_usage!("mknod.md"); +const AFTER_HELP: &str = help_section!("after help", "mknod.md"); const MODE_RW_UGO: mode_t = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; @@ -142,7 +125,7 @@ pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .override_usage(format_usage(USAGE)) - .after_help(LONG_HELP) + .after_help(AFTER_HELP) .about(ABOUT) .infer_long_args(true) .arg( From 89b83c2f6ada1f2cac062a2fdfd6ea0de341fbfd Mon Sep 17 00:00:00 2001 From: august radjoe Date: Sat, 18 Mar 2023 09:19:57 -0400 Subject: [PATCH 49/60] A better handler for `./coreutils date -f aze` (#4482) --- src/uu/date/src/date.rs | 22 +++++++++++++--------- tests/by-util/test_date.rs | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 2f428fa68..3c9488e7f 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -203,9 +203,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { return set_system_datetime(date); } else { - // Declare a file here because it needs to outlive the `dates` iterator. - let file: File; - // Get the current time, either in the local time zone or UTC. let now: DateTime = if settings.utc { let now = Utc::now(); @@ -222,12 +219,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let iter = std::iter::once(date); Box::new(iter) } - DateSource::File(ref path) => { - file = File::open(path).unwrap(); - let lines = BufReader::new(file).lines(); - let iter = lines.filter_map(Result::ok).map(parse_date); - Box::new(iter) - } + DateSource::File(ref path) => match File::open(path) { + Ok(file) => { + let lines = BufReader::new(file).lines(); + let iter = lines.filter_map(Result::ok).map(parse_date); + Box::new(iter) + } + Err(_err) => { + return Err(USimpleError::new( + 2, + format!("{}: No such file or directory", path.display()), + )); + } + }, DateSource::Now => { let iter = std::iter::once(Ok(now)); Box::new(iter) diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 7a353dd23..7451574ff 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -266,6 +266,24 @@ fn test_date_set_valid_2() { } } +#[test] +fn test_date_for_invalid_file() { + let result = new_ucmd!().arg("--file").arg("invalid_file").fails(); + result.no_stdout(); + assert_eq!( + result.stderr_str().trim(), + "date: invalid_file: No such file or directory", + ); +} + +#[test] +fn test_date_for_file() { + let (at, mut ucmd) = at_and_ucmd!(); + let file = "test_date_for_file"; + at.touch(file); + ucmd.arg("--file").arg(file).succeeds(); +} + #[test] #[cfg(all(unix, not(target_os = "macos")))] /// TODO: expected to fail currently; change to succeeds() when required. From d42b4883e1bbd4c2e74e75bbb61d927548af9ea8 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 18 Mar 2023 14:35:53 +0100 Subject: [PATCH 50/60] Fix some simply clippy warnings With: `cargo +nightly clippy --features unix --allow-dirty --fix -- -W clippy::pedantic` --- tests/common/util.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/common/util.rs b/tests/common/util.rs index 6c7072ff4..dfe39583c 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -2812,7 +2812,7 @@ mod tests { #[should_panic] fn test_cmd_result_stdout_check_when_false_then_panics() { let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); - result.stdout_check(|s| s.is_empty()); + result.stdout_check(<[u8]>::is_empty); } #[cfg(feature = "echo")] @@ -3055,9 +3055,10 @@ mod tests { // check `child.is_alive()` and `child.delay()` is working let mut trials = 10; while child.is_alive() { - if trials <= 0 { - panic!("Assertion failed: child process is still alive.") - } + assert!( + trials > 0, + "Assertion failed: child process is still alive." + ); child.delay(500); trials -= 1; From be6d5bfb9cf13a4cac39a582ad33c95f9daa4be9 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 18 Mar 2023 14:50:43 +0100 Subject: [PATCH 51/60] Fix some redundant closure in test_shurf --- tests/by-util/test_shuf.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/by-util/test_shuf.rs b/tests/by-util/test_shuf.rs index 39a7a640b..23851aacc 100644 --- a/tests/by-util/test_shuf.rs +++ b/tests/by-util/test_shuf.rs @@ -10,7 +10,7 @@ fn test_output_is_random_permutation() { let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let input = input_seq .iter() - .map(|x| x.to_string()) + .map(ToString::to_string) .collect::>() .join("\n"); @@ -52,7 +52,7 @@ fn test_echo() { .args( &input_seq .iter() - .map(|x| x.to_string()) + .map(ToString::to_string) .collect::>(), ) .succeeds(); @@ -74,7 +74,7 @@ fn test_head_count() { let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let input = input_seq .iter() - .map(|x| x.to_string()) + .map(ToString::to_string) .collect::>() .join("\n"); @@ -105,7 +105,7 @@ fn test_repeat() { let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let input = input_seq .iter() - .map(|x| x.to_string()) + .map(ToString::to_string) .collect::>() .join("\n"); From 37235d1e204edf0f378fd8bd7e6fe1176c55856a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 18 Mar 2023 16:28:02 +0100 Subject: [PATCH 52/60] build.rs: ignore a clippy warning: match_same_arms --- build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.rs b/build.rs index 5201b9169..04948c0d3 100644 --- a/build.rs +++ b/build.rs @@ -20,6 +20,8 @@ pub fn main() { for (key, val) in env::vars() { if val == "1" && key.starts_with(ENV_FEATURE_PREFIX) { let krate = key[ENV_FEATURE_PREFIX.len()..].to_lowercase(); + // Allow this as we have a bunch of info in the comments + #[allow(clippy::match_same_arms)] match krate.as_ref() { "default" | "macos" | "unix" | "windows" | "selinux" | "zip" => continue, // common/standard feature names "nightly" | "test_unimplemented" => continue, // crate-local custom features From 8393118aeec213ce0e63f6a0f5e0c10d171615f2 Mon Sep 17 00:00:00 2001 From: papparapa <37232476+papparapa@users.noreply.github.com> Date: Sun, 19 Mar 2023 00:42:16 +0900 Subject: [PATCH 53/60] Update src/uu/mknod/mknod.md Co-authored-by: Sylvestre Ledru --- src/uu/mknod/mknod.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/uu/mknod/mknod.md b/src/uu/mknod/mknod.md index 4cb366df9..88034e76a 100644 --- a/src/uu/mknod/mknod.md +++ b/src/uu/mknod/mknod.md @@ -9,9 +9,7 @@ Create the special file NAME of the given TYPE. ## After Help Mandatory arguments to long options are mandatory for short options too. --m, --mode=MODE set file permission bits to MODE, not a=rw - umask ---help display this help and exit ---version output version information and exit +`-m`, `--mode=MODE` set file permission bits to `MODE`, not `a=rw - umask` Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they must be omitted when TYPE is p. If MAJOR or MINOR begins with 0x or 0X, From 3b78b2e92fa88bb3d4d1e13e182de70487028351 Mon Sep 17 00:00:00 2001 From: papparapa <37232476+papparapa@users.noreply.github.com> Date: Sun, 19 Mar 2023 00:42:27 +0900 Subject: [PATCH 54/60] Update src/uu/mknod/mknod.md Co-authored-by: Sylvestre Ledru --- src/uu/mknod/mknod.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/uu/mknod/mknod.md b/src/uu/mknod/mknod.md index 88034e76a..78da97025 100644 --- a/src/uu/mknod/mknod.md +++ b/src/uu/mknod/mknod.md @@ -11,14 +11,14 @@ Create the special file NAME of the given TYPE. Mandatory arguments to long options are mandatory for short options too. `-m`, `--mode=MODE` set file permission bits to `MODE`, not `a=rw - umask` -Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they -must be omitted when TYPE is p. If MAJOR or MINOR begins with 0x or 0X, +Both `MAJOR` and `MINOR` must be specified when `TYPE` is `b`, `c`, or `u`, and they +must be omitted when `TYPE` is `p`. If `MAJOR` or `MINOR` begins with `0x` or `0X`, it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal; -otherwise, as decimal. TYPE may be: +otherwise, as decimal. `TYPE` may be: -b create a block (buffered) special file -c, u create a character (unbuffered) special file -p create a FIFO +* `b` create a block (buffered) special file +* `c`, `u` create a character (unbuffered) special file +* `p` create a FIFO NOTE: your shell may have its own version of mknod, which usually supersedes the version described here. Please refer to your shell's documentation From 1f0bedefc70cfc4424b46fb166901ee65ebce6cb Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 18 Mar 2023 16:52:20 +0100 Subject: [PATCH 55/60] update to sccache v0.4.0-pre.11 --- .github/workflows/CICD.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 2a474a89a..751d11de0 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -190,7 +190,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Initialize workflow variables id: vars shell: bash @@ -303,7 +303,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Initialize workflow variables id: vars shell: bash @@ -359,7 +359,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Initialize workflow variables id: vars shell: bash @@ -455,7 +455,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Install `rust` toolchain run: | ## Install `rust` toolchain @@ -503,7 +503,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Install `rust` toolchain run: | ## Install `rust` toolchain @@ -535,7 +535,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Install `rust` toolchain run: | ## Install `rust` toolchain @@ -564,7 +564,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Install dependencies shell: bash run: | @@ -643,7 +643,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Initialize workflow variables id: vars shell: bash @@ -900,7 +900,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Install/setup prerequisites shell: bash run: | @@ -982,7 +982,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: rust toolchain ~ install run: | ## rust toolchain ~ install @@ -1068,7 +1068,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: AVD cache uses: actions/cache@v3 id: avd-cache @@ -1130,7 +1130,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" - name: Prepare, build and test ## spell-checker:ignore (ToDO) sshfs usesh vmactions uses: vmactions/freebsd-vm@v0.3.0 @@ -1211,7 +1211,7 @@ jobs: - name: Run sccache-cache uses: mozilla-actions/sccache-action@v0.0.2 with: - version: "v0.4.0-pre.9" + version: "v0.4.0-pre.11" # - name: Reattach HEAD ## may be needed for accurate code coverage info # run: git checkout ${{ github.head_ref }} - name: Initialize workflow variables From 7376f3ad02b710459fe5d3b206b52236d79fe1de Mon Sep 17 00:00:00 2001 From: Koki Ueha Date: Sun, 19 Mar 2023 03:58:56 +0000 Subject: [PATCH 56/60] mktemp: move help strings to markdown file --- src/uu/mktemp/mktemp.md | 7 +++++++ src/uu/mktemp/src/mktemp.rs | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 src/uu/mktemp/mktemp.md diff --git a/src/uu/mktemp/mktemp.md b/src/uu/mktemp/mktemp.md new file mode 100644 index 000000000..75b56d667 --- /dev/null +++ b/src/uu/mktemp/mktemp.md @@ -0,0 +1,7 @@ +# mktemp + +``` +mktemp [OPTION]... [TEMPLATE] +``` + +Create a temporary file or directory. diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 390c77bfa..4a77da4c4 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -11,7 +11,7 @@ use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use uucore::display::{println_verbatim, Quotable}; use uucore::error::{FromIo, UError, UResult, UUsageError}; -use uucore::format_usage; +use uucore::{format_usage, help_about, help_usage}; use std::env; use std::error::Error; @@ -28,8 +28,8 @@ use std::os::unix::prelude::PermissionsExt; use rand::Rng; use tempfile::Builder; -static ABOUT: &str = "Create a temporary file or directory."; -const USAGE: &str = "{} [OPTION]... [TEMPLATE]"; +const ABOUT: &str = help_about!("mktemp.md"); +const USAGE: &str = help_usage!("mktemp.md"); static DEFAULT_TEMPLATE: &str = "tmp.XXXXXXXXXX"; From 0b042f0b32980b987ecc38be0973d32aa38cec54 Mon Sep 17 00:00:00 2001 From: Koki Ueha Date: Sun, 19 Mar 2023 04:59:08 +0000 Subject: [PATCH 57/60] test_du: fix unnecessary boolean operation --- tests/by-util/test_du.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 4a3cc3530..de72ed4e5 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -82,10 +82,10 @@ fn _du_basics_subdir(s: &str) { ))] fn _du_basics_subdir(s: &str) { // MS-WSL linux has altered expected output - if !uucore::os::is_wsl_1() { - assert_eq!(s, "8\tsubdir/deeper\n"); - } else { + if uucore::os::is_wsl_1() { assert_eq!(s, "0\tsubdir/deeper\n"); + } else { + assert_eq!(s, "8\tsubdir/deeper\n"); } } @@ -164,10 +164,10 @@ fn _du_soft_link(s: &str) { ))] fn _du_soft_link(s: &str) { // MS-WSL linux has altered expected output - if !uucore::os::is_wsl_1() { - assert_eq!(s, "16\tsubdir/links\n"); - } else { + if uucore::os::is_wsl_1() { assert_eq!(s, "8\tsubdir/links\n"); + } else { + assert_eq!(s, "16\tsubdir/links\n"); } } @@ -212,10 +212,10 @@ fn _du_hard_link(s: &str) { ))] fn _du_hard_link(s: &str) { // MS-WSL linux has altered expected output - if !uucore::os::is_wsl_1() { - assert_eq!(s, "16\tsubdir/links\n"); - } else { + if uucore::os::is_wsl_1() { assert_eq!(s, "8\tsubdir/links\n"); + } else { + assert_eq!(s, "16\tsubdir/links\n"); } } @@ -255,10 +255,10 @@ fn _du_d_flag(s: &str) { ))] fn _du_d_flag(s: &str) { // MS-WSL linux has altered expected output - if !uucore::os::is_wsl_1() { - assert_eq!(s, "28\t./subdir\n36\t.\n"); - } else { + if uucore::os::is_wsl_1() { assert_eq!(s, "8\t./subdir\n8\t.\n"); + } else { + assert_eq!(s, "28\t./subdir\n36\t.\n"); } } @@ -303,10 +303,10 @@ fn _du_dereference(s: &str) { ))] fn _du_dereference(s: &str) { // MS-WSL linux has altered expected output - if !uucore::os::is_wsl_1() { - assert_eq!(s, "8\tsubdir/links/deeper_dir\n24\tsubdir/links\n"); - } else { + if uucore::os::is_wsl_1() { assert_eq!(s, "0\tsubdir/links/deeper_dir\n8\tsubdir/links\n"); + } else { + assert_eq!(s, "8\tsubdir/links/deeper_dir\n24\tsubdir/links\n"); } } From b39c4d2756397760aefafa0c85bd91503a79172a Mon Sep 17 00:00:00 2001 From: Surya Teja K Date: Sun, 19 Mar 2023 13:24:45 +0530 Subject: [PATCH 58/60] date: fix invalid argument error for RFC 3339 (#4535) --- src/uu/date/src/date.rs | 1 + tests/by-util/test_date.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 3c9488e7f..8ff6283c5 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -314,6 +314,7 @@ pub fn uu_app() -> Command { Arg::new(OPT_RFC_3339) .long(OPT_RFC_3339) .value_name("FMT") + .value_parser([DATE, SECOND, SECONDS, NS]) .help(RFC_3339_HELP_STRING), ) .arg( diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 7451574ff..1727f4006 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -43,6 +43,13 @@ fn test_date_rfc_3339() { } } +#[test] +fn test_date_rfc_3339_invalid_arg() { + for param in ["--iso-3339", "--rfc-3"] { + new_ucmd!().arg(format!("{param}=foo")).fails(); + } +} + #[test] fn test_date_rfc_8601_default() { let re = Regex::new(r"^\d{4}-\d{2}-\d{2}\n$").unwrap(); From 0ca5020b083541e99fd78847e75b20c82f16073b Mon Sep 17 00:00:00 2001 From: Piotr Kwiecinski Date: Sun, 19 Mar 2023 11:59:14 +0100 Subject: [PATCH 59/60] who: move help strings to markdown file --- src/uu/who/src/who.rs | 6 +++--- src/uu/who/who.md | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/uu/who/who.md diff --git a/src/uu/who/src/who.rs b/src/uu/who/src/who.rs index 935319c31..26248b12b 100644 --- a/src/uu/who/src/who.rs +++ b/src/uu/who/src/who.rs @@ -18,7 +18,7 @@ use std::ffi::CStr; use std::fmt::Write; use std::os::unix::fs::MetadataExt; use std::path::PathBuf; -use uucore::format_usage; +use uucore::{format_usage, help_about, help_usage}; mod options { pub const ALL: &str = "all"; @@ -38,8 +38,8 @@ mod options { pub const FILE: &str = "FILE"; // if length=1: FILE, if length=2: ARG1 ARG2 } -static ABOUT: &str = "Print information about users who are currently logged in."; -const USAGE: &str = "{} [OPTION]... [ FILE | ARG1 ARG2 ]"; +const ABOUT: &str = help_about!("who.md"); +const USAGE: &str = help_usage!("who.md"); #[cfg(target_os = "linux")] static RUNLEVEL_HELP: &str = "print current runlevel"; diff --git a/src/uu/who/who.md b/src/uu/who/who.md new file mode 100644 index 000000000..6adc26597 --- /dev/null +++ b/src/uu/who/who.md @@ -0,0 +1,8 @@ +# who + +``` +who [OPTION]... [ FILE | ARG1 ARG2 ] +``` + +Print information about users who are currently logged in. + From 96a148b5585331a303581253a6f2beb1c94ebbe5 Mon Sep 17 00:00:00 2001 From: Piotr Kwiecinski Date: Sun, 19 Mar 2023 13:18:03 +0100 Subject: [PATCH 60/60] fold: move move help strings to markdown file --- src/uu/fold/fold.md | 8 ++++++++ src/uu/fold/src/fold.rs | 7 +++---- 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 src/uu/fold/fold.md diff --git a/src/uu/fold/fold.md b/src/uu/fold/fold.md new file mode 100644 index 000000000..13062c858 --- /dev/null +++ b/src/uu/fold/fold.md @@ -0,0 +1,8 @@ +# fold + +``` +fold [OPTION]... [FILE]... +``` + +Writes each file (or standard input if no files are given) +to standard output whilst breaking long lines diff --git a/src/uu/fold/src/fold.rs b/src/uu/fold/src/fold.rs index dee30b258..01eba0b82 100644 --- a/src/uu/fold/src/fold.rs +++ b/src/uu/fold/src/fold.rs @@ -13,13 +13,12 @@ use std::io::{stdin, BufRead, BufReader, Read}; use std::path::Path; use uucore::display::Quotable; use uucore::error::{FromIo, UResult, USimpleError}; -use uucore::format_usage; +use uucore::{format_usage, help_about, help_usage}; const TAB_WIDTH: usize = 8; -static USAGE: &str = "{} [OPTION]... [FILE]..."; -static ABOUT: &str = "Writes each file (or standard input if no files are given) - to standard output whilst breaking long lines"; +const USAGE: &str = help_usage!("fold.md"); +const ABOUT: &str = help_about!("fold.md"); mod options { pub const BYTES: &str = "bytes";