diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index a8054055b..6f61cf6d1 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -1,11 +1,11 @@ name: CICD -# spell-checker:ignore (acronyms) CICD MSVC musl +# spell-checker:ignore (abbrev/names) CICD CodeCOV MacOS MinGW MSVC musl # spell-checker:ignore (env/flags) Awarnings Ccodegen Coverflow Cpanic Dwarnings RUSTDOCFLAGS RUSTFLAGS Zpanic # spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain -# spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy -# spell-checker:ignore (shell/tools) choco clippy dmake dpkg esac fakeroot gmake grcov halium lcov libssl mkdir popd printf pushd rsync rustc rustfmt rustup shopt xargs -# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend pell runtest tempfile testsuite uutils DESTDIR multisize Swatinem +# spell-checker:ignore (people) Peltoche rivy +# spell-checker:ignore (shell/tools) choco clippy dmake dpkg esac fakeroot fdesc fdescfs gmake grcov halium lcov libssl mkdir popd printf pushd rsync rustc rustfmt rustup shopt utmpdump xargs +# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils defconfig DESTDIR gecos gnueabihf issuecomment maint multisize nullglob onexitbegin onexitend pell runtest Swatinem tempfile testsuite toybox uutils env: PROJECT_NAME: coreutils @@ -50,7 +50,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # failure mode unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in ''|0|f|false|n|no|off) FAULT_TYPE=warning ;; @@ -102,7 +102,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # failure mode unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in ''|0|f|false|n|no|off) FAULT_TYPE=warning ;; @@ -116,6 +116,7 @@ jobs: outputs CARGO_FEATURES_OPTION - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt} rustup toolchain install stable -c rustfmt --profile minimal rustup default stable @@ -150,7 +151,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # failure mode unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in ''|0|f|false|n|no|off) FAULT_TYPE=warning ;; @@ -170,11 +171,13 @@ jobs: - name: Install/setup prerequisites shell: bash run: | + ## Install/setup prerequisites case '${{ matrix.job.os }}' in macos-latest) brew install coreutils ;; # needed for show-utils.sh esac - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rustup toolchain install stable -c clippy --profile minimal rustup default stable - uses: Swatinem/rust-cache@v2 @@ -206,7 +209,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # failure mode unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in ''|0|f|false|n|no|off) FAULT_TYPE=warning ;; @@ -257,7 +260,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # failure mode unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in ''|0|f|false|n|no|off) FAULT_TYPE=warning ;; @@ -276,6 +279,7 @@ jobs: outputs CARGO_UTILITY_LIST_OPTIONS - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rustup toolchain install stable -c clippy --profile minimal rustup default stable - uses: Swatinem/rust-cache@v2 @@ -299,7 +303,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # target-specific options # * CARGO_FEATURES_OPTION unset CARGO_FEATURES_OPTION @@ -307,6 +311,7 @@ jobs: outputs CARGO_FEATURES_OPTION - name: Install `rust` toolchain (v${{ env.RUST_MIN_SRV }}) run: | + ## Install `rust` toolchain (v${{ env.RUST_MIN_SRV }}) rustup toolchain install ${{ env.RUST_MIN_SRV }} --profile minimal rustup default ${{ env.RUST_MIN_SRV }} - uses: Swatinem/rust-cache@v2 @@ -347,6 +352,7 @@ jobs: run: cargo test -v ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -p uucore -p coreutils env: RUSTFLAGS: "-Awarnings --cfg unsound_local_offset" + RUST_BACKTRACE: "1" deps: name: Dependencies @@ -360,6 +366,7 @@ jobs: - uses: actions/checkout@v3 - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rustup toolchain install stable --profile minimal rustup default stable - uses: Swatinem/rust-cache@v2 @@ -383,6 +390,7 @@ jobs: - uses: actions/checkout@v3 - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rustup toolchain install stable --profile minimal rustup default stable - uses: Swatinem/rust-cache@v2 @@ -394,6 +402,8 @@ jobs: shell: bash run: | make test + env: + RUST_BACKTRACE: "1" build_rust_stable: @@ -412,11 +422,14 @@ jobs: - uses: actions/checkout@v3 - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rustup toolchain install stable --profile minimal rustup default stable - uses: Swatinem/rust-cache@v2 - name: Test run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} + env: + RUST_BACKTRACE: "1" build_rust_nightly: name: Build/nightly @@ -434,11 +447,14 @@ jobs: - uses: actions/checkout@v3 - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rustup toolchain install nightly --profile minimal rustup default nightly - uses: Swatinem/rust-cache@v2 - name: Test run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} + env: + RUST_BACKTRACE: "1" compute_size: name: Binary sizes @@ -459,26 +475,29 @@ jobs: sudo apt-get install jq - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rustup toolchain install stable --profile minimal rustup default stable - uses: Swatinem/rust-cache@v2 - name: "`make install`" shell: bash run: | + ## `make install` make install DESTDIR=target/size-release/ make install MULTICALL=y DESTDIR=target/size-multi-release/ # strip the results strip target/size*/usr/local/bin/* - - name: "Compute sizes" + - name: Compute uutil release sizes shell: bash run: | + ## Compute uutil release sizes SIZE=$(du -s target/size-release/usr/local/bin/|awk '{print $1}') - SIZEMULTI=$(du -s target/size-multi-release/usr/local/bin/|awk '{print $1}') + SIZE_MULTI=$(du -s target/size-multi-release/usr/local/bin/|awk '{print $1}') jq -n \ --arg date "$(date --rfc-email)" \ --arg sha "$GITHUB_SHA" \ --arg size "$SIZE" \ - --arg multisize "$SIZEMULTI" \ + --arg multisize "$SIZE_MULTI" \ '{($date): { sha: $sha, size: $size, multisize: $multisize, }}' > size-result.json - uses: actions/upload-artifact@v3 with: @@ -526,7 +545,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # toolchain TOOLCHAIN="stable" ## default to "stable" toolchain # * specify alternate/non-default TOOLCHAIN for *-pc-windows-gnu targets; gnu targets on Windows are broken for the standard *-pc-windows-msvc toolchain (refs: GH:rust-lang/rust#47048, GH:rust-lang/rust#53454, GH:rust-lang/cargo#6754) @@ -546,7 +565,7 @@ jobs: REF_NAME=${GITHUB_REF#refs/*/} unset REF_BRANCH ; case "${GITHUB_REF}" in refs/heads/*) REF_BRANCH=${GITHUB_REF#refs/heads/} ;; esac; unset REF_TAG ; case "${GITHUB_REF}" in refs/tags/*) REF_TAG=${GITHUB_REF#refs/tags/} ;; esac; - REF_SHAS=${GITHUB_SHA:0:8} + REF_SHAS=${GITHUB_SHA:0:10} outputs REF_NAME REF_BRANCH REF_TAG REF_SHAS # parse target unset TARGET_ARCH @@ -597,7 +616,7 @@ jobs: # ** pass needed environment into `cross` container (iff `cross` not already configured via "Cross.toml") if [ "${CARGO_CMD}" = 'cross' ] && [ ! -e "Cross.toml" ] ; then cargo install --version 0.2.1 cross - printf "[build.env]\npassthrough = [\"CI\"]\n" > Cross.toml + printf "[build.env]\npassthrough = [\"CI\", \"RUST_BACKTRACE\"]\n" > Cross.toml fi # * test only library and/or binaries for arm-type targets unset CARGO_TEST_OPTIONS ; case '${{ matrix.job.target }}' in aarch64-* | arm-*) CARGO_TEST_OPTIONS="--bins" ;; esac; @@ -645,6 +664,7 @@ jobs: esac - name: rust toolchain ~ install run: | + ## rust toolchain ~ install rustup toolchain install ${{ env.RUST_MIN_SRV }} -t ${{ matrix.job.target }} --profile minimal rustup default ${{ env.RUST_MIN_SRV }} - uses: Swatinem/rust-cache@v2 @@ -655,7 +675,7 @@ jobs: shell: bash run: | ## Dependent VARs setup - outputs() { step_id="dep_vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # * determine sub-crate utility list UTILITY_LIST="$(./util/show-utils.sh ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }})" echo UTILITY_LIST=${UTILITY_LIST} @@ -687,18 +707,25 @@ jobs: - name: Build shell: bash run: | + ## Build ${{ steps.vars.outputs.CARGO_CMD }} +${{ env.RUST_MIN_SRV }} build --release \ --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} - name: Test shell: bash run: | + ## Test ${{ steps.vars.outputs.CARGO_CMD }} +${{ env.RUST_MIN_SRV }} test --target=${{ matrix.job.target }} \ ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} + env: + RUST_BACKTRACE: "1" - name: Test individual utilities shell: bash run: | + ## Test individual utilities ${{ steps.vars.outputs.CARGO_CMD }} +${{ env.RUST_MIN_SRV }} test --target=${{ matrix.job.target }} \ ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} + env: + RUST_BACKTRACE: "1" - name: Archive executable artifacts uses: actions/upload-artifact@v3 with: @@ -771,10 +798,11 @@ jobs: run: | ## Install/setup prerequisites make prepare-busytest - - name: "Run BusyBox test suite" + - name: Run BusyBox test suite id: summary shell: bash run: | + ## Run BusyBox test suite set -v cp .busybox-config target/debug/.config ## Run BusyBox test suite @@ -835,16 +863,20 @@ jobs: shell: bash run: | ## VARs setup - echo "TEST_SUMMARY_FILE=toybox-result.json" >> $GITHUB_OUTPUT + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + TEST_SUMMARY_FILE="toybox-result.json" + outputs TEST_SUMMARY_FILE - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 - name: rust toolchain ~ install run: | + ## rust toolchain ~ install rustup toolchain install ${{ env.RUST_MIN_SRV }} --profile minimal rustup default ${{ env.RUST_MIN_SRV }} - - name: "Build coreutils as multiple binaries" + - name: Build coreutils as multiple binaries shell: bash run: | + ## Build individual uutil binaries set -v make - name: Install/setup prerequisites @@ -852,12 +884,12 @@ jobs: run: | ## Install/setup prerequisites make toybox-src - - name: "Run Toybox test suite" + - name: Run Toybox test suite id: summary shell: bash run: | - set -v ## Run Toybox test suite + set -v cd tmp/toybox-*/ make defconfig make tests &> tmp.log || true @@ -1023,6 +1055,7 @@ jobs: cd "${WORKSPACE}" unset FAULT cargo build || FAULT=1 + export RUST_BACKTRACE=1 if (test -z "\$FAULT"); then cargo test --features '${{ matrix.job.features }}' || FAULT=1 ; fi if (test -z "\$FAULT"); then cargo test --all-features -p uucore || FAULT=1 ; fi # Clean to avoid to rsync back the files @@ -1050,7 +1083,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # toolchain TOOLCHAIN="nightly" ## default to "nightly" toolchain (required for certain required unstable compiler flags) ## !maint: refactor when stable channel has needed support # * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files @@ -1093,6 +1126,7 @@ jobs: esac - name: rust toolchain ~ install run: | + ## rust toolchain ~ install rustup toolchain install ${{ steps.vars.outputs.TOOLCHAIN }} --profile minimal rustup default ${{ steps.vars.outputs.TOOLCHAIN }} - uses: Swatinem/rust-cache@v2 @@ -1101,7 +1135,7 @@ jobs: shell: bash run: | ## Dependent VARs setup - outputs() { step_id="dep_vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # * determine sub-crate utility list UTILITY_LIST="$(./util/show-utils.sh ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }})" CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo -n "-puu_${u} "; done;)" @@ -1113,6 +1147,7 @@ jobs: RUSTC_WRAPPER: "" RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort" + RUST_BACKTRACE: "1" # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} - name: Test run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast @@ -1121,6 +1156,7 @@ jobs: RUSTC_WRAPPER: "" RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort" + RUST_BACKTRACE: "1" # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} - name: Test individual utilities run: cargo test --no-fail-fast ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} @@ -1129,6 +1165,7 @@ jobs: RUSTC_WRAPPER: "" RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort" + RUST_BACKTRACE: "1" # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} - name: "`grcov` ~ install" id: build_grcov diff --git a/.github/workflows/FixPR.yml b/.github/workflows/FixPR.yml index f2e9e7bb3..52561fb36 100644 --- a/.github/workflows/FixPR.yml +++ b/.github/workflows/FixPR.yml @@ -32,12 +32,13 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # surface MSRV from CICD workflow RUST_MIN_SRV=$(grep -P "^\s+RUST_MIN_SRV:" .github/workflows/CICD.yml | grep -Po "(?<=\x22)\d+[.]\d+(?:[.]\d+)?(?=\x22)" ) outputs RUST_MIN_SRV - name: Install `rust` toolchain (v${{ steps.vars.outputs.RUST_MIN_SRV }}) run: | + ## Install `rust` toolchain (v${{ steps.vars.outputs.RUST_MIN_SRV }}) rustup toolchain install ${{ steps.vars.outputs.RUST_MIN_SRV }} --profile minimal rustup default ${{ steps.vars.outputs.RUST_MIN_SRV }} - uses: Swatinem/rust-cache@v2 @@ -94,7 +95,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # target-specific options # * CARGO_FEATURES_OPTION CARGO_FEATURES_OPTION='' ; @@ -102,6 +103,7 @@ jobs: outputs CARGO_FEATURES_OPTION - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt} rustup toolchain install stable -c rustfmt --profile minimal rustup default stable diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index 1000792f3..a462b946a 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -1,6 +1,11 @@ name: GnuTests -# spell-checker:ignore (names) gnulib ; (jargon) submodules ; (people) Dawid Dziurla * dawidd ; (utils) autopoint chksum gperf pyinotify shopt texinfo ; (vars) FILESET SUBDIRS XPASS +# spell-checker:ignore (abbrev/names) CodeCov gnulib GnuTests +# spell-checker:ignore (jargon) submodules +# spell-checker:ignore (libs/utils) autopoint chksum gperf lcov libexpect pyinotify shopt texinfo valgrind +# spell-checker:ignore (options) Ccodegen Coverflow Cpanic Zpanic +# spell-checker:ignore (people) Dawid Dziurla * dawidd +# spell-checker:ignore (vars) FILESET SUBDIRS XPASS # * note: to run a single test => `REPO/util/run-gnu-test.sh PATH/TO/TEST/SCRIPT` @@ -23,7 +28,7 @@ jobs: shell: bash run: | ## VARs setup - outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } # * config path_GNU="gnu" path_GNU_tests="${path_GNU}/tests" @@ -67,6 +72,7 @@ jobs: path: "${{ steps.vars.outputs.path_reference }}" - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt} rustup toolchain install stable -c rustfmt --profile minimal rustup default stable @@ -79,6 +85,7 @@ jobs: - name: Add various locales shell: bash run: | + ## Add various locales echo "Before:" locale -a ## Some tests fail with 'cannot change locale (en_US.ISO-8859-1): No such file or directory' @@ -103,27 +110,31 @@ jobs: - name: Run GNU tests shell: bash run: | + ## Run GNU tests path_GNU='${{ steps.vars.outputs.path_GNU }}' path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' bash "${path_UUTILS}/util/run-gnu-test.sh" - name: Run GNU root tests shell: bash run: | + ## Run GNU root tests path_GNU='${{ steps.vars.outputs.path_GNU }}' path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' bash "${path_UUTILS}/util/run-gnu-test.sh" run-root - name: Extract testing info into JSON shell: bash run : | + ## Extract testing info into JSON path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' python ${path_UUTILS}/util/gnu-json-result.py ${{ steps.vars.outputs.path_GNU_tests }} > ${{ steps.vars.outputs.TEST_FULL_SUMMARY_FILE }} - name: Extract/summarize testing info id: summary shell: bash run: | - path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' ## Extract/summarize testing info - outputs() { step_id="summary"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; } + # + path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' # SUITE_LOG_FILE='${{ steps.vars.outputs.SUITE_LOG_FILE }}' ROOT_SUITE_LOG_FILE='${{ steps.vars.outputs.ROOT_SUITE_LOG_FILE }}' @@ -180,6 +191,7 @@ jobs: - name: Compare test failures VS reference shell: bash run: | + ## Compare test failures VS reference have_new_failures="" REF_LOG_FILE='${{ steps.vars.outputs.path_reference }}/test-logs/test-suite.log' REF_SUMMARY_FILE='${{ steps.vars.outputs.path_reference }}/test-summary/gnu-result.json' @@ -254,6 +266,7 @@ jobs: if: success() || failure() # run regardless of prior step success/failure shell: bash run: | + ## Compare test summary VS reference REF_SUMMARY_FILE='${{ steps.vars.outputs.path_reference }}/test-summary/gnu-result.json' if test -f "${REF_SUMMARY_FILE}"; then echo "Reference SHA1/ID: $(sha1sum -- "${REF_SUMMARY_FILE}")" @@ -280,15 +293,18 @@ jobs: submodules: recursive - name: Install `rust` toolchain run: | + ## Install `rust` toolchain rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt} rustup toolchain install nightly -c rustfmt --profile minimal rustup default nightly - name: Install dependencies run: | + ## Install dependencies sudo apt update sudo apt install autoconf autopoint bison texinfo gperf gcc g++ gdb python3-pyinotify jq valgrind libexpect-perl -y - name: Add various locales run: | + ## Add various locales echo "Before:" locale -a ## Some tests fail with 'cannot change locale (en_US.ISO-8859-1): No such file or directory' @@ -305,6 +321,7 @@ jobs: RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort" run: | + ## Build binaries cd uutils UU_MAKE_PROFILE=debug bash util/build-gnu.sh - name: Run GNU tests diff --git a/Cargo.lock b/Cargo.lock index e81300286..0e9d6d0ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -326,7 +326,7 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "coreutils" -version = "0.0.16" +version = "0.0.17" dependencies = [ "atty", "chrono", @@ -1633,9 +1633,9 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "platform-info" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4278b2b54a23c9a91d5bae9b09e21d566f8b23890491951160b05d64f29d1d8b" +checksum = "4e7c23cfae725ae06d9e43010153fa77bdfa8c827bf08fe4beeb2a3514e6be12" dependencies = [ "libc", "winapi", @@ -2328,7 +2328,7 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uu_arch" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "platform-info", @@ -2337,7 +2337,7 @@ dependencies = [ [[package]] name = "uu_base32" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2345,7 +2345,7 @@ dependencies = [ [[package]] name = "uu_base64" -version = "0.0.16" +version = "0.0.17" dependencies = [ "uu_base32", "uucore", @@ -2353,7 +2353,7 @@ dependencies = [ [[package]] name = "uu_basename" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2361,7 +2361,7 @@ dependencies = [ [[package]] name = "uu_basenc" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uu_base32", @@ -2370,7 +2370,7 @@ dependencies = [ [[package]] name = "uu_cat" -version = "0.0.16" +version = "0.0.17" dependencies = [ "atty", "clap", @@ -2381,7 +2381,7 @@ dependencies = [ [[package]] name = "uu_chcon" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "fts-sys", @@ -2393,7 +2393,7 @@ dependencies = [ [[package]] name = "uu_chgrp" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2401,7 +2401,7 @@ dependencies = [ [[package]] name = "uu_chmod" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2410,7 +2410,7 @@ dependencies = [ [[package]] name = "uu_chown" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2418,7 +2418,7 @@ dependencies = [ [[package]] name = "uu_chroot" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2426,7 +2426,7 @@ dependencies = [ [[package]] name = "uu_cksum" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2434,7 +2434,7 @@ dependencies = [ [[package]] name = "uu_comm" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2442,7 +2442,7 @@ dependencies = [ [[package]] name = "uu_cp" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "exacl", @@ -2458,7 +2458,7 @@ dependencies = [ [[package]] name = "uu_csplit" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "regex", @@ -2468,7 +2468,7 @@ dependencies = [ [[package]] name = "uu_cut" -version = "0.0.16" +version = "0.0.17" dependencies = [ "atty", "bstr", @@ -2479,7 +2479,7 @@ dependencies = [ [[package]] name = "uu_date" -version = "0.0.16" +version = "0.0.17" dependencies = [ "chrono", "clap", @@ -2490,7 +2490,7 @@ dependencies = [ [[package]] name = "uu_dd" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "gcd", @@ -2501,7 +2501,7 @@ dependencies = [ [[package]] name = "uu_df" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "unicode-width", @@ -2510,7 +2510,7 @@ dependencies = [ [[package]] name = "uu_dir" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uu_ls", @@ -2519,7 +2519,7 @@ dependencies = [ [[package]] name = "uu_dircolors" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2527,7 +2527,7 @@ dependencies = [ [[package]] name = "uu_dirname" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2535,7 +2535,7 @@ dependencies = [ [[package]] name = "uu_du" -version = "0.0.16" +version = "0.0.17" dependencies = [ "chrono", "clap", @@ -2546,7 +2546,7 @@ dependencies = [ [[package]] name = "uu_echo" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2554,7 +2554,7 @@ dependencies = [ [[package]] name = "uu_env" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "nix", @@ -2564,7 +2564,7 @@ dependencies = [ [[package]] name = "uu_expand" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "unicode-width", @@ -2573,7 +2573,7 @@ dependencies = [ [[package]] name = "uu_expr" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "num-bigint", @@ -2584,7 +2584,7 @@ dependencies = [ [[package]] name = "uu_factor" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "coz", @@ -2598,7 +2598,7 @@ dependencies = [ [[package]] name = "uu_false" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2606,7 +2606,7 @@ dependencies = [ [[package]] name = "uu_fmt" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "unicode-width", @@ -2615,7 +2615,7 @@ dependencies = [ [[package]] name = "uu_fold" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2623,7 +2623,7 @@ dependencies = [ [[package]] name = "uu_groups" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2631,7 +2631,7 @@ dependencies = [ [[package]] name = "uu_hashsum" -version = "0.0.16" +version = "0.0.17" dependencies = [ "blake2b_simd", "blake3", @@ -2649,7 +2649,7 @@ dependencies = [ [[package]] name = "uu_head" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "memchr", @@ -2658,7 +2658,7 @@ dependencies = [ [[package]] name = "uu_hostid" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2667,7 +2667,7 @@ dependencies = [ [[package]] name = "uu_hostname" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "hostname", @@ -2677,7 +2677,7 @@ dependencies = [ [[package]] name = "uu_id" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "selinux", @@ -2686,7 +2686,7 @@ dependencies = [ [[package]] name = "uu_install" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "file_diff", @@ -2698,7 +2698,7 @@ dependencies = [ [[package]] name = "uu_join" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "memchr", @@ -2707,7 +2707,7 @@ dependencies = [ [[package]] name = "uu_kill" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "nix", @@ -2716,7 +2716,7 @@ dependencies = [ [[package]] name = "uu_link" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2724,7 +2724,7 @@ dependencies = [ [[package]] name = "uu_ln" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2732,7 +2732,7 @@ dependencies = [ [[package]] name = "uu_logname" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2741,7 +2741,7 @@ dependencies = [ [[package]] name = "uu_ls" -version = "0.0.16" +version = "0.0.17" dependencies = [ "atty", "chrono", @@ -2759,7 +2759,7 @@ dependencies = [ [[package]] name = "uu_mkdir" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2767,7 +2767,7 @@ dependencies = [ [[package]] name = "uu_mkfifo" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2776,7 +2776,7 @@ dependencies = [ [[package]] name = "uu_mknod" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2785,7 +2785,7 @@ dependencies = [ [[package]] name = "uu_mktemp" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "rand", @@ -2795,7 +2795,7 @@ dependencies = [ [[package]] name = "uu_more" -version = "0.0.16" +version = "0.0.17" dependencies = [ "atty", "clap", @@ -2808,7 +2808,7 @@ dependencies = [ [[package]] name = "uu_mv" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "fs_extra", @@ -2818,7 +2818,7 @@ dependencies = [ [[package]] name = "uu_nice" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2828,7 +2828,7 @@ dependencies = [ [[package]] name = "uu_nl" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "regex", @@ -2837,7 +2837,7 @@ dependencies = [ [[package]] name = "uu_nohup" -version = "0.0.16" +version = "0.0.17" dependencies = [ "atty", "clap", @@ -2847,7 +2847,7 @@ dependencies = [ [[package]] name = "uu_nproc" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2857,7 +2857,7 @@ dependencies = [ [[package]] name = "uu_numfmt" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2865,7 +2865,7 @@ dependencies = [ [[package]] name = "uu_od" -version = "0.0.16" +version = "0.0.17" dependencies = [ "byteorder", "clap", @@ -2875,7 +2875,7 @@ dependencies = [ [[package]] name = "uu_paste" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2883,7 +2883,7 @@ dependencies = [ [[package]] name = "uu_pathchk" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2892,7 +2892,7 @@ dependencies = [ [[package]] name = "uu_pinky" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2900,7 +2900,7 @@ dependencies = [ [[package]] name = "uu_pr" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "itertools", @@ -2912,7 +2912,7 @@ dependencies = [ [[package]] name = "uu_printenv" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2920,7 +2920,7 @@ dependencies = [ [[package]] name = "uu_printf" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2928,7 +2928,7 @@ dependencies = [ [[package]] name = "uu_ptx" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "regex", @@ -2937,7 +2937,7 @@ dependencies = [ [[package]] name = "uu_pwd" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2945,7 +2945,7 @@ dependencies = [ [[package]] name = "uu_readlink" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2953,7 +2953,7 @@ dependencies = [ [[package]] name = "uu_realpath" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2961,7 +2961,7 @@ dependencies = [ [[package]] name = "uu_relpath" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -2969,7 +2969,7 @@ dependencies = [ [[package]] name = "uu_rm" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2981,7 +2981,7 @@ dependencies = [ [[package]] name = "uu_rmdir" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -2990,7 +2990,7 @@ dependencies = [ [[package]] name = "uu_runcon" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -3001,7 +3001,7 @@ dependencies = [ [[package]] name = "uu_seq" -version = "0.0.16" +version = "0.0.17" dependencies = [ "bigdecimal", "clap", @@ -3012,7 +3012,7 @@ dependencies = [ [[package]] name = "uu_shred" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "rand", @@ -3021,7 +3021,7 @@ dependencies = [ [[package]] name = "uu_shuf" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "memchr", @@ -3032,7 +3032,7 @@ dependencies = [ [[package]] name = "uu_sleep" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3040,7 +3040,7 @@ dependencies = [ [[package]] name = "uu_sort" -version = "0.0.16" +version = "0.0.17" dependencies = [ "binary-heap-plus", "clap", @@ -3059,7 +3059,7 @@ dependencies = [ [[package]] name = "uu_split" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "memchr", @@ -3068,7 +3068,7 @@ dependencies = [ [[package]] name = "uu_stat" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3076,7 +3076,7 @@ dependencies = [ [[package]] name = "uu_stdbuf" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "tempfile", @@ -3086,7 +3086,7 @@ dependencies = [ [[package]] name = "uu_stdbuf_libstdbuf" -version = "0.0.16" +version = "0.0.17" dependencies = [ "cpp", "cpp_build", @@ -3096,7 +3096,7 @@ dependencies = [ [[package]] name = "uu_stty" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "nix", @@ -3105,7 +3105,7 @@ dependencies = [ [[package]] name = "uu_sum" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3113,7 +3113,7 @@ dependencies = [ [[package]] name = "uu_sync" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -3124,7 +3124,7 @@ dependencies = [ [[package]] name = "uu_tac" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "memchr", @@ -3135,7 +3135,7 @@ dependencies = [ [[package]] name = "uu_tail" -version = "0.0.16" +version = "0.0.17" dependencies = [ "atty", "clap", @@ -3151,7 +3151,7 @@ dependencies = [ [[package]] name = "uu_tee" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -3161,7 +3161,7 @@ dependencies = [ [[package]] name = "uu_test" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -3171,7 +3171,7 @@ dependencies = [ [[package]] name = "uu_timeout" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -3181,7 +3181,7 @@ dependencies = [ [[package]] name = "uu_touch" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "filetime", @@ -3192,7 +3192,7 @@ dependencies = [ [[package]] name = "uu_tr" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "nom", @@ -3201,7 +3201,7 @@ dependencies = [ [[package]] name = "uu_true" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3209,7 +3209,7 @@ dependencies = [ [[package]] name = "uu_truncate" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3217,7 +3217,7 @@ dependencies = [ [[package]] name = "uu_tsort" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3225,7 +3225,7 @@ dependencies = [ [[package]] name = "uu_tty" -version = "0.0.16" +version = "0.0.17" dependencies = [ "atty", "clap", @@ -3235,7 +3235,7 @@ dependencies = [ [[package]] name = "uu_uname" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "platform-info", @@ -3244,7 +3244,7 @@ dependencies = [ [[package]] name = "uu_unexpand" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "unicode-width", @@ -3253,7 +3253,7 @@ dependencies = [ [[package]] name = "uu_uniq" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "strum", @@ -3263,7 +3263,7 @@ dependencies = [ [[package]] name = "uu_unlink" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3271,7 +3271,7 @@ dependencies = [ [[package]] name = "uu_uptime" -version = "0.0.16" +version = "0.0.17" dependencies = [ "chrono", "clap", @@ -3280,7 +3280,7 @@ dependencies = [ [[package]] name = "uu_users" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3288,7 +3288,7 @@ dependencies = [ [[package]] name = "uu_vdir" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uu_ls", @@ -3297,7 +3297,7 @@ dependencies = [ [[package]] name = "uu_wc" -version = "0.0.16" +version = "0.0.17" dependencies = [ "bytecount", "clap", @@ -3310,7 +3310,7 @@ dependencies = [ [[package]] name = "uu_who" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "uucore", @@ -3318,7 +3318,7 @@ dependencies = [ [[package]] name = "uu_whoami" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -3328,7 +3328,7 @@ dependencies = [ [[package]] name = "uu_yes" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "libc", @@ -3338,7 +3338,7 @@ dependencies = [ [[package]] name = "uucore" -version = "0.0.16" +version = "0.0.17" dependencies = [ "clap", "data-encoding", @@ -3363,7 +3363,7 @@ dependencies = [ [[package]] name = "uucore_procs" -version = "0.0.16" +version = "0.0.17" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index dfd853997..90cc76f4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ [package] name = "coreutils" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust" @@ -30,6 +30,20 @@ windows = [ "feat_os_windows" ] ## project-specific feature shortcodes nightly = [] test_unimplemented = [] +# * only build `uudoc` when `--feature uudoc` is activated +uudoc = ["zip"] +## features +# "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`) +# NOTE: +# * On linux, the posix-acl/acl-sys crate requires `libacl` headers and shared library to be accessible in the C toolchain at compile time. +# * On FreeBSD and macOS this is not required. +feat_acl = ["cp/feat_acl"] +# "feat_selinux" == enable support for SELinux Security Context (by using `--features feat_selinux`) +# NOTE: +# * The selinux(-sys) crate requires `libselinux` headers and shared library to be accessible in the C toolchain at compile time. +# * Running a uutils compiled with `feat_selinux` requires an SELinux enabled Kernel at run time. +feat_selinux = ["cp/selinux", "id/selinux", "ls/selinux", "selinux", "feat_require_selinux"] +## ## feature sets ## (common/core and Tier1) feature sets # "feat_common_core" == baseline core set of utilities which can be built/run on most targets @@ -115,13 +129,15 @@ feat_Tier1 = [ "nproc", "sync", "touch", + "uname", "whoami", ] ## (primary platforms) feature sets # "feat_os_macos" == set of utilities which can be built/run on the MacOS platform feat_os_macos = [ "feat_os_unix", ## == a modern/usual *nix platform - "feat_require_hostid", + # + "feat_require_unix_hostid", ] # "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms feat_os_unix = [ @@ -141,31 +157,21 @@ feat_os_unix_gnueabihf = [ "feat_Tier1", # "feat_require_unix", + "feat_require_unix_hostid", "feat_require_unix_utmpx", - "feat_require_hostid", ] # "feat_os_unix_musl" == set of utilities which can be built/run on targets binding to the "musl" library (ref: ) feat_os_unix_musl = [ "feat_Tier1", # "feat_require_unix", - "feat_require_hostid", + "feat_require_unix_hostid", ] feat_os_unix_android = [ "feat_Tier1", # "feat_require_unix", ] -# "feat_selinux" == set of utilities providing support for SELinux Security Context if enabled with `--features feat_selinux`. -# NOTE: -# The selinux(-sys) crate requires `libselinux` headers and shared library to be accessible in the C toolchain at compile time. -# Running a uutils compiled with `feat_selinux` requires an SELinux enabled Kernel at run time. -feat_selinux = ["cp/selinux", "id/selinux", "ls/selinux", "selinux", "feat_require_selinux"] -# "feat_acl" == set of utilities providing support for acl (access control lists) if enabled with `--features feat_acl`. -# NOTE: -# On linux, the posix-acl/acl-sys crate requires `libacl` headers and shared library to be accessible in the C toolchain at compile time. -# On FreeBSD and macOS this is not required. -feat_acl = ["cp/feat_acl"] ## feature sets with requirements (restricting cross-platform availability) # # ** NOTE: these `feat_require_...` sets should be minimized as much as possible to encourage cross-platform availability of utilities @@ -194,7 +200,6 @@ feat_require_unix = [ "stty", "timeout", "tty", - "uname", ] # "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support # * ref: @@ -204,8 +209,8 @@ feat_require_unix_utmpx = [ "users", "who", ] -# "feat_require_hostid" == set of utilities requiring gethostid in libc (only some unixes provide) -feat_require_hostid = [ +# "feat_require_unix_hostid" == set of utilities requiring gethostid in libc (only some unixes provide) +feat_require_unix_hostid = [ "hostid", ] # "feat_require_selinux" == set of utilities depending on SELinux. @@ -256,7 +261,6 @@ feat_os_windows_legacy = [ ## # * bypass/override ~ translate 'test' feature name to avoid dependency collision with rust core 'test' crate (o/w surfaces as compiler errors during testing) test = [ "uu_test" ] -uudoc = [ "zip" ] [workspace] @@ -267,113 +271,113 @@ once_cell = "1.13.1" phf = "0.11.1" selinux = { version="0.3", optional = true } textwrap = { version="0.16.0", features=["terminal_size"] } -uucore = { version=">=0.0.16", package="uucore", path="src/uucore" } +uucore = { version=">=0.0.17", package="uucore", path="src/uucore" } zip = { version = "0.6.3", optional=true, default_features=false, features=["deflate"] } # * uutils -uu_test = { optional=true, version="0.0.16", package="uu_test", path="src/uu/test" } +uu_test = { optional=true, version="0.0.17", package="uu_test", path="src/uu/test" } # -arch = { optional=true, version="0.0.16", package="uu_arch", path="src/uu/arch" } -base32 = { optional=true, version="0.0.16", package="uu_base32", path="src/uu/base32" } -base64 = { optional=true, version="0.0.16", package="uu_base64", path="src/uu/base64" } -basename = { optional=true, version="0.0.16", package="uu_basename", path="src/uu/basename" } -basenc = { optional=true, version="0.0.16", package="uu_basenc", path="src/uu/basenc" } -cat = { optional=true, version="0.0.16", package="uu_cat", path="src/uu/cat" } -chcon = { optional=true, version="0.0.16", package="uu_chcon", path="src/uu/chcon" } -chgrp = { optional=true, version="0.0.16", package="uu_chgrp", path="src/uu/chgrp" } -chmod = { optional=true, version="0.0.16", package="uu_chmod", path="src/uu/chmod" } -chown = { optional=true, version="0.0.16", package="uu_chown", path="src/uu/chown" } -chroot = { optional=true, version="0.0.16", package="uu_chroot", path="src/uu/chroot" } -cksum = { optional=true, version="0.0.16", package="uu_cksum", path="src/uu/cksum" } -comm = { optional=true, version="0.0.16", package="uu_comm", path="src/uu/comm" } -cp = { optional=true, version="0.0.16", package="uu_cp", path="src/uu/cp" } -csplit = { optional=true, version="0.0.16", package="uu_csplit", path="src/uu/csplit" } -cut = { optional=true, version="0.0.16", package="uu_cut", path="src/uu/cut" } -date = { optional=true, version="0.0.16", package="uu_date", path="src/uu/date" } -dd = { optional=true, version="0.0.16", package="uu_dd", path="src/uu/dd" } -df = { optional=true, version="0.0.16", package="uu_df", path="src/uu/df" } -dir = { optional=true, version="0.0.16", package="uu_dir", path="src/uu/dir" } -dircolors= { optional=true, version="0.0.16", package="uu_dircolors", path="src/uu/dircolors" } -dirname = { optional=true, version="0.0.16", package="uu_dirname", path="src/uu/dirname" } -du = { optional=true, version="0.0.16", package="uu_du", path="src/uu/du" } -echo = { optional=true, version="0.0.16", package="uu_echo", path="src/uu/echo" } -env = { optional=true, version="0.0.16", package="uu_env", path="src/uu/env" } -expand = { optional=true, version="0.0.16", package="uu_expand", path="src/uu/expand" } -expr = { optional=true, version="0.0.16", package="uu_expr", path="src/uu/expr" } -factor = { optional=true, version="0.0.16", package="uu_factor", path="src/uu/factor" } -false = { optional=true, version="0.0.16", package="uu_false", path="src/uu/false" } -fmt = { optional=true, version="0.0.16", package="uu_fmt", path="src/uu/fmt" } -fold = { optional=true, version="0.0.16", package="uu_fold", path="src/uu/fold" } -groups = { optional=true, version="0.0.16", package="uu_groups", path="src/uu/groups" } -hashsum = { optional=true, version="0.0.16", package="uu_hashsum", path="src/uu/hashsum" } -head = { optional=true, version="0.0.16", package="uu_head", path="src/uu/head" } -hostid = { optional=true, version="0.0.16", package="uu_hostid", path="src/uu/hostid" } -hostname = { optional=true, version="0.0.16", package="uu_hostname", path="src/uu/hostname" } -id = { optional=true, version="0.0.16", package="uu_id", path="src/uu/id" } -install = { optional=true, version="0.0.16", package="uu_install", path="src/uu/install" } -join = { optional=true, version="0.0.16", package="uu_join", path="src/uu/join" } -kill = { optional=true, version="0.0.16", package="uu_kill", path="src/uu/kill" } -link = { optional=true, version="0.0.16", package="uu_link", path="src/uu/link" } -ln = { optional=true, version="0.0.16", package="uu_ln", path="src/uu/ln" } -ls = { optional=true, version="0.0.16", package="uu_ls", path="src/uu/ls" } -logname = { optional=true, version="0.0.16", package="uu_logname", path="src/uu/logname" } -mkdir = { optional=true, version="0.0.16", package="uu_mkdir", path="src/uu/mkdir" } -mkfifo = { optional=true, version="0.0.16", package="uu_mkfifo", path="src/uu/mkfifo" } -mknod = { optional=true, version="0.0.16", package="uu_mknod", path="src/uu/mknod" } -mktemp = { optional=true, version="0.0.16", package="uu_mktemp", path="src/uu/mktemp" } -more = { optional=true, version="0.0.16", package="uu_more", path="src/uu/more" } -mv = { optional=true, version="0.0.16", package="uu_mv", path="src/uu/mv" } -nice = { optional=true, version="0.0.16", package="uu_nice", path="src/uu/nice" } -nl = { optional=true, version="0.0.16", package="uu_nl", path="src/uu/nl" } -nohup = { optional=true, version="0.0.16", package="uu_nohup", path="src/uu/nohup" } -nproc = { optional=true, version="0.0.16", package="uu_nproc", path="src/uu/nproc" } -numfmt = { optional=true, version="0.0.16", package="uu_numfmt", path="src/uu/numfmt" } -od = { optional=true, version="0.0.16", package="uu_od", path="src/uu/od" } -paste = { optional=true, version="0.0.16", package="uu_paste", path="src/uu/paste" } -pathchk = { optional=true, version="0.0.16", package="uu_pathchk", path="src/uu/pathchk" } -pinky = { optional=true, version="0.0.16", package="uu_pinky", path="src/uu/pinky" } -pr = { optional=true, version="0.0.16", package="uu_pr", path="src/uu/pr" } -printenv = { optional=true, version="0.0.16", package="uu_printenv", path="src/uu/printenv" } -printf = { optional=true, version="0.0.16", package="uu_printf", path="src/uu/printf" } -ptx = { optional=true, version="0.0.16", package="uu_ptx", path="src/uu/ptx" } -pwd = { optional=true, version="0.0.16", package="uu_pwd", path="src/uu/pwd" } -readlink = { optional=true, version="0.0.16", package="uu_readlink", path="src/uu/readlink" } -realpath = { optional=true, version="0.0.16", package="uu_realpath", path="src/uu/realpath" } -relpath = { optional=true, version="0.0.16", package="uu_relpath", path="src/uu/relpath" } -rm = { optional=true, version="0.0.16", package="uu_rm", path="src/uu/rm" } -rmdir = { optional=true, version="0.0.16", package="uu_rmdir", path="src/uu/rmdir" } -runcon = { optional=true, version="0.0.16", package="uu_runcon", path="src/uu/runcon" } -seq = { optional=true, version="0.0.16", package="uu_seq", path="src/uu/seq" } -shred = { optional=true, version="0.0.16", package="uu_shred", path="src/uu/shred" } -shuf = { optional=true, version="0.0.16", package="uu_shuf", path="src/uu/shuf" } -sleep = { optional=true, version="0.0.16", package="uu_sleep", path="src/uu/sleep" } -sort = { optional=true, version="0.0.16", package="uu_sort", path="src/uu/sort" } -split = { optional=true, version="0.0.16", package="uu_split", path="src/uu/split" } -stat = { optional=true, version="0.0.16", package="uu_stat", path="src/uu/stat" } -stdbuf = { optional=true, version="0.0.16", package="uu_stdbuf", path="src/uu/stdbuf" } -stty = { optional=true, version="0.0.16", package="uu_stty", path="src/uu/stty" } -sum = { optional=true, version="0.0.16", package="uu_sum", path="src/uu/sum" } -sync = { optional=true, version="0.0.16", package="uu_sync", path="src/uu/sync" } -tac = { optional=true, version="0.0.16", package="uu_tac", path="src/uu/tac" } -tail = { optional=true, version="0.0.16", package="uu_tail", path="src/uu/tail" } -tee = { optional=true, version="0.0.16", package="uu_tee", path="src/uu/tee" } -timeout = { optional=true, version="0.0.16", package="uu_timeout", path="src/uu/timeout" } -touch = { optional=true, version="0.0.16", package="uu_touch", path="src/uu/touch" } -tr = { optional=true, version="0.0.16", package="uu_tr", path="src/uu/tr" } -true = { optional=true, version="0.0.16", package="uu_true", path="src/uu/true" } -truncate = { optional=true, version="0.0.16", package="uu_truncate", path="src/uu/truncate" } -tsort = { optional=true, version="0.0.16", package="uu_tsort", path="src/uu/tsort" } -tty = { optional=true, version="0.0.16", package="uu_tty", path="src/uu/tty" } -uname = { optional=true, version="0.0.16", package="uu_uname", path="src/uu/uname" } -unexpand = { optional=true, version="0.0.16", package="uu_unexpand", path="src/uu/unexpand" } -uniq = { optional=true, version="0.0.16", package="uu_uniq", path="src/uu/uniq" } -unlink = { optional=true, version="0.0.16", package="uu_unlink", path="src/uu/unlink" } -uptime = { optional=true, version="0.0.16", package="uu_uptime", path="src/uu/uptime" } -users = { optional=true, version="0.0.16", package="uu_users", path="src/uu/users" } -vdir = { optional=true, version="0.0.16", package="uu_vdir", path="src/uu/vdir" } -wc = { optional=true, version="0.0.16", package="uu_wc", path="src/uu/wc" } -who = { optional=true, version="0.0.16", package="uu_who", path="src/uu/who" } -whoami = { optional=true, version="0.0.16", package="uu_whoami", path="src/uu/whoami" } -yes = { optional=true, version="0.0.16", package="uu_yes", path="src/uu/yes" } +arch = { optional=true, version="0.0.17", package="uu_arch", path="src/uu/arch" } +base32 = { optional=true, version="0.0.17", package="uu_base32", path="src/uu/base32" } +base64 = { optional=true, version="0.0.17", package="uu_base64", path="src/uu/base64" } +basename = { optional=true, version="0.0.17", package="uu_basename", path="src/uu/basename" } +basenc = { optional=true, version="0.0.17", package="uu_basenc", path="src/uu/basenc" } +cat = { optional=true, version="0.0.17", package="uu_cat", path="src/uu/cat" } +chcon = { optional=true, version="0.0.17", package="uu_chcon", path="src/uu/chcon" } +chgrp = { optional=true, version="0.0.17", package="uu_chgrp", path="src/uu/chgrp" } +chmod = { optional=true, version="0.0.17", package="uu_chmod", path="src/uu/chmod" } +chown = { optional=true, version="0.0.17", package="uu_chown", path="src/uu/chown" } +chroot = { optional=true, version="0.0.17", package="uu_chroot", path="src/uu/chroot" } +cksum = { optional=true, version="0.0.17", package="uu_cksum", path="src/uu/cksum" } +comm = { optional=true, version="0.0.17", package="uu_comm", path="src/uu/comm" } +cp = { optional=true, version="0.0.17", package="uu_cp", path="src/uu/cp" } +csplit = { optional=true, version="0.0.17", package="uu_csplit", path="src/uu/csplit" } +cut = { optional=true, version="0.0.17", package="uu_cut", path="src/uu/cut" } +date = { optional=true, version="0.0.17", package="uu_date", path="src/uu/date" } +dd = { optional=true, version="0.0.17", package="uu_dd", path="src/uu/dd" } +df = { optional=true, version="0.0.17", package="uu_df", path="src/uu/df" } +dir = { optional=true, version="0.0.17", package="uu_dir", path="src/uu/dir" } +dircolors= { optional=true, version="0.0.17", package="uu_dircolors", path="src/uu/dircolors" } +dirname = { optional=true, version="0.0.17", package="uu_dirname", path="src/uu/dirname" } +du = { optional=true, version="0.0.17", package="uu_du", path="src/uu/du" } +echo = { optional=true, version="0.0.17", package="uu_echo", path="src/uu/echo" } +env = { optional=true, version="0.0.17", package="uu_env", path="src/uu/env" } +expand = { optional=true, version="0.0.17", package="uu_expand", path="src/uu/expand" } +expr = { optional=true, version="0.0.17", package="uu_expr", path="src/uu/expr" } +factor = { optional=true, version="0.0.17", package="uu_factor", path="src/uu/factor" } +false = { optional=true, version="0.0.17", package="uu_false", path="src/uu/false" } +fmt = { optional=true, version="0.0.17", package="uu_fmt", path="src/uu/fmt" } +fold = { optional=true, version="0.0.17", package="uu_fold", path="src/uu/fold" } +groups = { optional=true, version="0.0.17", package="uu_groups", path="src/uu/groups" } +hashsum = { optional=true, version="0.0.17", package="uu_hashsum", path="src/uu/hashsum" } +head = { optional=true, version="0.0.17", package="uu_head", path="src/uu/head" } +hostid = { optional=true, version="0.0.17", package="uu_hostid", path="src/uu/hostid" } +hostname = { optional=true, version="0.0.17", package="uu_hostname", path="src/uu/hostname" } +id = { optional=true, version="0.0.17", package="uu_id", path="src/uu/id" } +install = { optional=true, version="0.0.17", package="uu_install", path="src/uu/install" } +join = { optional=true, version="0.0.17", package="uu_join", path="src/uu/join" } +kill = { optional=true, version="0.0.17", package="uu_kill", path="src/uu/kill" } +link = { optional=true, version="0.0.17", package="uu_link", path="src/uu/link" } +ln = { optional=true, version="0.0.17", package="uu_ln", path="src/uu/ln" } +ls = { optional=true, version="0.0.17", package="uu_ls", path="src/uu/ls" } +logname = { optional=true, version="0.0.17", package="uu_logname", path="src/uu/logname" } +mkdir = { optional=true, version="0.0.17", package="uu_mkdir", path="src/uu/mkdir" } +mkfifo = { optional=true, version="0.0.17", package="uu_mkfifo", path="src/uu/mkfifo" } +mknod = { optional=true, version="0.0.17", package="uu_mknod", path="src/uu/mknod" } +mktemp = { optional=true, version="0.0.17", package="uu_mktemp", path="src/uu/mktemp" } +more = { optional=true, version="0.0.17", package="uu_more", path="src/uu/more" } +mv = { optional=true, version="0.0.17", package="uu_mv", path="src/uu/mv" } +nice = { optional=true, version="0.0.17", package="uu_nice", path="src/uu/nice" } +nl = { optional=true, version="0.0.17", package="uu_nl", path="src/uu/nl" } +nohup = { optional=true, version="0.0.17", package="uu_nohup", path="src/uu/nohup" } +nproc = { optional=true, version="0.0.17", package="uu_nproc", path="src/uu/nproc" } +numfmt = { optional=true, version="0.0.17", package="uu_numfmt", path="src/uu/numfmt" } +od = { optional=true, version="0.0.17", package="uu_od", path="src/uu/od" } +paste = { optional=true, version="0.0.17", package="uu_paste", path="src/uu/paste" } +pathchk = { optional=true, version="0.0.17", package="uu_pathchk", path="src/uu/pathchk" } +pinky = { optional=true, version="0.0.17", package="uu_pinky", path="src/uu/pinky" } +pr = { optional=true, version="0.0.17", package="uu_pr", path="src/uu/pr" } +printenv = { optional=true, version="0.0.17", package="uu_printenv", path="src/uu/printenv" } +printf = { optional=true, version="0.0.17", package="uu_printf", path="src/uu/printf" } +ptx = { optional=true, version="0.0.17", package="uu_ptx", path="src/uu/ptx" } +pwd = { optional=true, version="0.0.17", package="uu_pwd", path="src/uu/pwd" } +readlink = { optional=true, version="0.0.17", package="uu_readlink", path="src/uu/readlink" } +realpath = { optional=true, version="0.0.17", package="uu_realpath", path="src/uu/realpath" } +relpath = { optional=true, version="0.0.17", package="uu_relpath", path="src/uu/relpath" } +rm = { optional=true, version="0.0.17", package="uu_rm", path="src/uu/rm" } +rmdir = { optional=true, version="0.0.17", package="uu_rmdir", path="src/uu/rmdir" } +runcon = { optional=true, version="0.0.17", package="uu_runcon", path="src/uu/runcon" } +seq = { optional=true, version="0.0.17", package="uu_seq", path="src/uu/seq" } +shred = { optional=true, version="0.0.17", package="uu_shred", path="src/uu/shred" } +shuf = { optional=true, version="0.0.17", package="uu_shuf", path="src/uu/shuf" } +sleep = { optional=true, version="0.0.17", package="uu_sleep", path="src/uu/sleep" } +sort = { optional=true, version="0.0.17", package="uu_sort", path="src/uu/sort" } +split = { optional=true, version="0.0.17", package="uu_split", path="src/uu/split" } +stat = { optional=true, version="0.0.17", package="uu_stat", path="src/uu/stat" } +stdbuf = { optional=true, version="0.0.17", package="uu_stdbuf", path="src/uu/stdbuf" } +stty = { optional=true, version="0.0.17", package="uu_stty", path="src/uu/stty" } +sum = { optional=true, version="0.0.17", package="uu_sum", path="src/uu/sum" } +sync = { optional=true, version="0.0.17", package="uu_sync", path="src/uu/sync" } +tac = { optional=true, version="0.0.17", package="uu_tac", path="src/uu/tac" } +tail = { optional=true, version="0.0.17", package="uu_tail", path="src/uu/tail" } +tee = { optional=true, version="0.0.17", package="uu_tee", path="src/uu/tee" } +timeout = { optional=true, version="0.0.17", package="uu_timeout", path="src/uu/timeout" } +touch = { optional=true, version="0.0.17", package="uu_touch", path="src/uu/touch" } +tr = { optional=true, version="0.0.17", package="uu_tr", path="src/uu/tr" } +true = { optional=true, version="0.0.17", package="uu_true", path="src/uu/true" } +truncate = { optional=true, version="0.0.17", package="uu_truncate", path="src/uu/truncate" } +tsort = { optional=true, version="0.0.17", package="uu_tsort", path="src/uu/tsort" } +tty = { optional=true, version="0.0.17", package="uu_tty", path="src/uu/tty" } +uname = { optional=true, version="0.0.17", package="uu_uname", path="src/uu/uname" } +unexpand = { optional=true, version="0.0.17", package="uu_unexpand", path="src/uu/unexpand" } +uniq = { optional=true, version="0.0.17", package="uu_uniq", path="src/uu/uniq" } +unlink = { optional=true, version="0.0.17", package="uu_unlink", path="src/uu/unlink" } +uptime = { optional=true, version="0.0.17", package="uu_uptime", path="src/uu/uptime" } +users = { optional=true, version="0.0.17", package="uu_users", path="src/uu/users" } +vdir = { optional=true, version="0.0.17", package="uu_vdir", path="src/uu/vdir" } +wc = { optional=true, version="0.0.17", package="uu_wc", path="src/uu/wc" } +who = { optional=true, version="0.0.17", package="uu_who", path="src/uu/who" } +whoami = { optional=true, version="0.0.17", package="uu_whoami", path="src/uu/whoami" } +yes = { optional=true, version="0.0.17", package="uu_yes", path="src/uu/yes" } # this breaks clippy linting with: "tests/by-util/test_factor_benches.rs: No such file or directory (os error 2)" # factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" } @@ -396,7 +400,7 @@ sha1 = { version="0.10", features=["std"] } tempfile = "3" time = {version="0.3", features=["local-offset"]} unindent = "0.1" -uucore = { version=">=0.0.16", package="uucore", path="src/uucore", features=["entries", "process"] } +uucore = { version=">=0.0.17", package="uucore", path="src/uucore", features=["entries", "process", "signals"] } walkdir = "2.2" atty = "0.2" hex-literal = "0.3.1" diff --git a/docs/src/extensions.md b/docs/src/extensions.md index e57105915..56f2edcc9 100644 --- a/docs/src/extensions.md +++ b/docs/src/extensions.md @@ -33,3 +33,7 @@ We provide a simple implementation of `more`, which is not part of GNU coreutils. We do not aim for full compatibility with the `more` utility from `util-linux`. Features from more modern pagers (like `less` and `bat`) are therefore welcomed. + +## `cut` + +`cut` can separate fields by whitespace (Space and Tab) with `-w` flag. This feature is adopted from [FreeBSD](https://www.freebsd.org/cgi/man.cgi?cut). \ No newline at end of file diff --git a/src/uu/arch/Cargo.toml b/src/uu/arch/Cargo.toml index 81d4c90a9..5cb68c14f 100644 --- a/src/uu/arch/Cargo.toml +++ b/src/uu/arch/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_arch" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "arch ~ (uutils) display machine architecture" @@ -15,9 +15,9 @@ edition = "2021" path = "src/arch.rs" [dependencies] -platform-info = "1.0.1" +platform-info = "1.0.2" clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "arch" diff --git a/src/uu/base32/Cargo.toml b/src/uu/base32/Cargo.toml index a996fa811..172ac6086 100644 --- a/src/uu/base32/Cargo.toml +++ b/src/uu/base32/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_base32" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "base32 ~ (uutils) decode/encode input (base32-encoding)" @@ -16,7 +16,7 @@ path = "src/base32.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features = ["encoding"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features = ["encoding"] } [[bin]] name = "base32" diff --git a/src/uu/base64/Cargo.toml b/src/uu/base64/Cargo.toml index 3cd69eeb8..790af595d 100644 --- a/src/uu/base64/Cargo.toml +++ b/src/uu/base64/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_base64" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "base64 ~ (uutils) decode/encode input (base64-encoding)" @@ -15,8 +15,8 @@ edition = "2021" path = "src/base64.rs" [dependencies] -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features = ["encoding"] } -uu_base32 = { version=">=0.0.16", package="uu_base32", path="../base32"} +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features = ["encoding"] } +uu_base32 = { version=">=0.0.17", package="uu_base32", path="../base32"} [[bin]] name = "base64" diff --git a/src/uu/basename/Cargo.toml b/src/uu/basename/Cargo.toml index 125191dd2..ef326334d 100644 --- a/src/uu/basename/Cargo.toml +++ b/src/uu/basename/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_basename" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "basename ~ (uutils) display PATHNAME with leading directory components removed" @@ -16,7 +16,7 @@ path = "src/basename.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "basename" diff --git a/src/uu/basenc/Cargo.toml b/src/uu/basenc/Cargo.toml index ac22c84b7..b98b3ac9d 100644 --- a/src/uu/basenc/Cargo.toml +++ b/src/uu/basenc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_basenc" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "basenc ~ (uutils) decode/encode input" @@ -16,8 +16,8 @@ path = "src/basenc.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features = ["encoding"] } -uu_base32 = { version=">=0.0.16", package="uu_base32", path="../base32"} +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features = ["encoding"] } +uu_base32 = { version=">=0.0.17", package="uu_base32", path="../base32"} [[bin]] name = "basenc" diff --git a/src/uu/cat/Cargo.toml b/src/uu/cat/Cargo.toml index 10748c4b2..524179567 100644 --- a/src/uu/cat/Cargo.toml +++ b/src/uu/cat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_cat" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "cat ~ (uutils) concatenate and display input" @@ -18,7 +18,7 @@ path = "src/cat.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } thiserror = "1.0" atty = "0.2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs", "pipes"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs", "pipes"] } [target.'cfg(unix)'.dependencies] nix = { version = "0.25", default-features = false } diff --git a/src/uu/cat/src/cat.rs b/src/uu/cat/src/cat.rs index 3200bdf4e..35ef5abc1 100644 --- a/src/uu/cat/src/cat.rs +++ b/src/uu/cat/src/cat.rs @@ -35,7 +35,6 @@ use std::os::unix::fs::FileTypeExt; use std::os::unix::net::UnixStream; use uucore::format_usage; -static NAME: &str = "cat"; static USAGE: &str = "{} [OPTION]... [FILE]..."; static ABOUT: &str = "Concatenate FILE(s), or standard input, to standard output With no FILE, or when FILE is -, read standard input."; @@ -236,7 +235,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .override_usage(format_usage(USAGE)) .about(ABOUT) @@ -426,7 +424,7 @@ fn get_input_type(path: &str) -> CatResult { ft if ft.is_file() => Ok(InputType::File), ft if ft.is_symlink() => Ok(InputType::SymLink), _ => Err(CatError::UnknownFiletype { - ft_debug: format!("{:?}", ft), + ft_debug: format!("{ft:?}"), }), } } diff --git a/src/uu/chcon/Cargo.toml b/src/uu/chcon/Cargo.toml index ea39f4ca5..a90308af4 100644 --- a/src/uu/chcon/Cargo.toml +++ b/src/uu/chcon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chcon" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "chcon ~ (uutils) change file security context" diff --git a/src/uu/chcon/src/chcon.rs b/src/uu/chcon/src/chcon.rs index 2abf8d40a..3acd2ea43 100644 --- a/src/uu/chcon/src/chcon.rs +++ b/src/uu/chcon/src/chcon.rs @@ -70,7 +70,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { return Err(r.into()); } - return Err(UUsageError::new(libc::EXIT_FAILURE, format!("{}.\n", r))); + return Err(UUsageError::new(libc::EXIT_FAILURE, format!("{r}.\n"))); } }; diff --git a/src/uu/chcon/src/errors.rs b/src/uu/chcon/src/errors.rs index 1082dc601..0bd61ec4a 100644 --- a/src/uu/chcon/src/errors.rs +++ b/src/uu/chcon/src/errors.rs @@ -67,10 +67,10 @@ impl Error { pub(crate) fn report_full_error(mut err: &dyn std::error::Error) -> String { let mut desc = String::with_capacity(256); - write!(desc, "{}", err).unwrap(); + write!(desc, "{err}").unwrap(); while let Some(source) = err.source() { err = source; - write!(desc, ". {}", err).unwrap(); + write!(desc, ". {err}").unwrap(); } desc } diff --git a/src/uu/chgrp/Cargo.toml b/src/uu/chgrp/Cargo.toml index 94fb874ba..de00ba951 100644 --- a/src/uu/chgrp/Cargo.toml +++ b/src/uu/chgrp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chgrp" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "chgrp ~ (uutils) change the group ownership of FILE" @@ -16,7 +16,7 @@ path = "src/chgrp.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } [[bin]] name = "chgrp" diff --git a/src/uu/chmod/Cargo.toml b/src/uu/chmod/Cargo.toml index adb72a256..52335e13a 100644 --- a/src/uu/chmod/Cargo.toml +++ b/src/uu/chmod/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chmod" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "chmod ~ (uutils) change mode of FILE" @@ -17,7 +17,7 @@ path = "src/chmod.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs", "mode"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs", "mode"] } [[bin]] name = "chmod" diff --git a/src/uu/chmod/src/chmod.rs b/src/uu/chmod/src/chmod.rs index c21705ccd..4d578eeba 100644 --- a/src/uu/chmod/src/chmod.rs +++ b/src/uu/chmod/src/chmod.rs @@ -75,7 +75,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { 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) + format!("-{modes}") } else { modes.to_string() }; diff --git a/src/uu/chown/Cargo.toml b/src/uu/chown/Cargo.toml index cb425e819..79aa2e4c2 100644 --- a/src/uu/chown/Cargo.toml +++ b/src/uu/chown/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chown" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "chown ~ (uutils) change the ownership of FILE" @@ -16,7 +16,7 @@ path = "src/chown.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] } [[bin]] name = "chown" diff --git a/src/uu/chroot/Cargo.toml b/src/uu/chroot/Cargo.toml index a021d207a..4a44f9eaa 100644 --- a/src/uu/chroot/Cargo.toml +++ b/src/uu/chroot/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_chroot" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "chroot ~ (uutils) run COMMAND under a new root directory" @@ -16,7 +16,7 @@ path = "src/chroot.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "fs"] } [[bin]] name = "chroot" diff --git a/src/uu/chroot/src/error.rs b/src/uu/chroot/src/error.rs index 059715de1..43ef98595 100644 --- a/src/uu/chroot/src/error.rs +++ b/src/uu/chroot/src/error.rs @@ -77,8 +77,8 @@ impl Display for ChrootError { "cannot change root directory to {}: no such directory", s.quote(), ), - Self::SetGidFailed(s, e) => write!(f, "cannot set gid to {}: {}", s, e), - Self::SetGroupsFailed(e) => write!(f, "cannot set groups: {}", e), + Self::SetGidFailed(s, e) => write!(f, "cannot set gid to {s}: {e}"), + Self::SetGroupsFailed(e) => write!(f, "cannot set groups: {e}"), Self::SetUserFailed(s, e) => { write!(f, "cannot set user to {}: {}", s.maybe_quote(), e) } diff --git a/src/uu/cksum/Cargo.toml b/src/uu/cksum/Cargo.toml index 98bd60c5a..52c7dd7cb 100644 --- a/src/uu/cksum/Cargo.toml +++ b/src/uu/cksum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_cksum" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "cksum ~ (uutils) display CRC and size of input" @@ -16,7 +16,7 @@ path = "src/cksum.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "cksum" diff --git a/src/uu/cksum/src/cksum.rs b/src/uu/cksum/src/cksum.rs index 8bbcfd836..f567d8bf8 100644 --- a/src/uu/cksum/src/cksum.rs +++ b/src/uu/cksum/src/cksum.rs @@ -18,7 +18,6 @@ use uucore::{format_usage, show}; const CRC_TABLE_LEN: usize = 256; const CRC_TABLE: [u32; CRC_TABLE_LEN] = generate_crc_table(); -const NAME: &str = "cksum"; const USAGE: &str = "{} [OPTIONS] [FILE]..."; const ABOUT: &str = "Print CRC and size for each file"; @@ -124,13 +123,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if files.is_empty() { let (crc, size) = cksum("-")?; - println!("{} {}", crc, size); + println!("{crc} {size}"); return Ok(()); } for fname in &files { match cksum(fname.as_ref()).map_err_context(|| format!("{}", fname.maybe_quote())) { - Ok((crc, size)) => println!("{} {} {}", crc, size, fname), + Ok((crc, size)) => println!("{crc} {size} {fname}"), Err(err) => show!(err), }; } @@ -139,7 +138,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .about(ABOUT) .override_usage(format_usage(USAGE)) diff --git a/src/uu/comm/Cargo.toml b/src/uu/comm/Cargo.toml index ff59b88a3..eec6711bb 100644 --- a/src/uu/comm/Cargo.toml +++ b/src/uu/comm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_comm" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "comm ~ (uutils) compare sorted inputs" @@ -16,7 +16,7 @@ path = "src/comm.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "comm" diff --git a/src/uu/cp/Cargo.toml b/src/uu/cp/Cargo.toml index 189ef1609..03477e287 100644 --- a/src/uu/cp/Cargo.toml +++ b/src/uu/cp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_cp" -version = "0.0.16" +version = "0.0.17" authors = [ "Jordy Dickinson ", "Joshua S. Miller ", @@ -24,7 +24,7 @@ filetime = "0.2" libc = "0.2.137" quick-error = "2.0.1" selinux = { version="0.3", optional=true } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs", "perms", "mode"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "fs", "perms", "mode"] } walkdir = "2.2" indicatif = "0.17" diff --git a/src/uu/cp/src/copydir.rs b/src/uu/cp/src/copydir.rs index 902247629..a89bd8537 100644 --- a/src/uu/cp/src/copydir.rs +++ b/src/uu/cp/src/copydir.rs @@ -380,7 +380,7 @@ pub(crate) fn copy_directory( // the target directory. let context = match Context::new(root, target) { Ok(c) => c, - Err(e) => return Err(format!("failed to get current directory {}", e).into()), + Err(e) => return Err(format!("failed to get current directory {e}").into()), }; // Traverse the contents of the directory, copying each one. @@ -405,7 +405,7 @@ pub(crate) fn copy_directory( } } // Copy the attributes from the root directory to the target directory. - copy_attributes(root, target, &options.preserve_attributes)?; + copy_attributes(root, target, &options.attributes)?; Ok(()) } diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 6c59f0ce9..d9029810d 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -24,7 +24,6 @@ use std::os::unix::ffi::OsStrExt; #[cfg(unix)] use std::os::unix::fs::{FileTypeExt, PermissionsExt}; use std::path::{Path, PathBuf, StripPrefixError}; -use std::str::FromStr; use std::string::ToString; use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; @@ -33,6 +32,8 @@ use indicatif::{ProgressBar, ProgressStyle}; #[cfg(unix)] use libc::mkfifo; use quick_error::ResultExt; + +use platform::copy_on_write; use uucore::backup_control::{self, BackupMode}; use uucore::display::Quotable; use uucore::error::{set_exit_code, UClapError, UError, UResult, UUsageError}; @@ -41,12 +42,10 @@ use uucore::fs::{ }; use uucore::{crash, format_usage, prompt_yes, show_error, show_warning}; -mod copydir; use crate::copydir::copy_directory; +mod copydir; mod platform; -use platform::copy_on_write; - quick_error! { #[derive(Debug)] pub enum Error { @@ -157,18 +156,51 @@ pub enum CopyMode { AttrOnly, } -// The ordering here determines the order in which attributes are (re-)applied. -// In particular, Ownership must be changed first to avoid interfering with mode change. -#[derive(Clone, Eq, PartialEq, Debug, PartialOrd, Ord)] -pub enum Attribute { +#[derive(Debug)] +pub struct Attributes { #[cfg(unix)] - Ownership, - Mode, - Timestamps, - #[cfg(feature = "feat_selinux")] - Context, - Links, - Xattr, + ownership: Preserve, + mode: Preserve, + timestamps: Preserve, + context: Preserve, + links: Preserve, + xattr: Preserve, +} + +impl Attributes { + pub(crate) fn max(&mut self, other: Self) { + #[cfg(unix)] + { + self.ownership = self.ownership.max(other.ownership); + } + self.mode = self.mode.max(other.mode); + self.timestamps = self.timestamps.max(other.timestamps); + self.context = self.context.max(other.context); + self.links = self.links.max(other.links); + self.xattr = self.xattr.max(other.xattr); + } +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Preserve { + No, + Yes { required: bool }, +} + +impl Preserve { + /// Preservation level should only increase, with no preservation being the lowest option, + /// preserve but don't require - middle, and preserve and require - top. + pub(crate) fn max(&self, other: Self) -> Self { + match (self, other) { + (Self::Yes { required: true }, _) | (_, Self::Yes { required: true }) => { + Self::Yes { required: true } + } + (Self::Yes { required: false }, _) | (_, Self::Yes { required: false }) => { + Self::Yes { required: false } + } + _ => Self::No, + } + } } /// Re-usable, extensible copy options @@ -187,7 +219,7 @@ pub struct Options { sparse_mode: SparseMode, strip_trailing_slashes: bool, reflink_mode: ReflinkMode, - preserve_attributes: Vec, + attributes: Attributes, recursive: bool, backup_suffix: String, target_dir: Option, @@ -243,7 +275,6 @@ static PRESERVABLE_ATTRIBUTES: &[&str] = &[ "mode", "ownership", "timestamps", - #[cfg(feature = "feat_selinux")] "context", "links", "xattr", @@ -254,13 +285,6 @@ static PRESERVABLE_ATTRIBUTES: &[&str] = &[ static PRESERVABLE_ATTRIBUTES: &[&str] = &["mode", "timestamps", "context", "links", "xattr", "all"]; -static DEFAULT_ATTRIBUTES: &[Attribute] = &[ - Attribute::Mode, - #[cfg(unix)] - Attribute::Ownership, - Attribute::Timestamps, -]; - pub fn uu_app() -> Command { const MODE_ARGS: &[&str] = &[ options::LINK, @@ -552,7 +576,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { clap::error::ErrorKind::DisplayHelp => { app.print_help()?; } - clap::error::ErrorKind::DisplayVersion => println!("{}", app.render_version()), + clap::error::ErrorKind::DisplayVersion => print!("{}", app.render_version()), _ => return Err(Box::new(e.with_exit_code(1))), }; } else if let Ok(matches) = matches { @@ -627,46 +651,79 @@ impl CopyMode { } } -impl FromStr for Attribute { - type Err = Error; +impl Attributes { + // TODO: ownership is required if the user is root, for non-root users it's not required. + // See: https://github.com/coreutils/coreutils/blob/master/src/copy.c#L3181 - fn from_str(value: &str) -> CopyResult { - Ok(match &*value.to_lowercase() { - "mode" => Self::Mode, + fn all() -> Self { + Self { #[cfg(unix)] - "ownership" => Self::Ownership, - "timestamps" => Self::Timestamps, - #[cfg(feature = "feat_selinux")] - "context" => Self::Context, - "links" => Self::Links, - "xattr" => Self::Xattr, + ownership: Preserve::Yes { required: true }, + mode: Preserve::Yes { required: true }, + timestamps: Preserve::Yes { required: true }, + context: { + #[cfg(feature = "feat_selinux")] + { + Preserve::Yes { required: false } + } + #[cfg(not(feature = "feat_selinux"))] + { + Preserve::No + } + }, + links: Preserve::Yes { required: true }, + xattr: Preserve::Yes { required: false }, + } + } + + fn default() -> Self { + Self { + #[cfg(unix)] + ownership: Preserve::Yes { required: true }, + mode: Preserve::Yes { required: true }, + timestamps: Preserve::Yes { required: true }, + context: Preserve::No, + links: Preserve::No, + xattr: Preserve::No, + } + } + + fn none() -> Self { + Self { + #[cfg(unix)] + ownership: Preserve::No, + mode: Preserve::No, + timestamps: Preserve::No, + context: Preserve::No, + links: Preserve::No, + xattr: Preserve::No, + } + } + + /// Tries to match string containing a parameter to preserve with the corresponding entry in the + /// Attributes struct. + fn try_set_from_string(&mut self, value: &str) -> Result<(), Error> { + let preserve_yes_required = Preserve::Yes { required: true }; + + match &*value.to_lowercase() { + "mode" => self.mode = preserve_yes_required, + #[cfg(unix)] + "ownership" => self.ownership = preserve_yes_required, + "timestamps" => self.timestamps = preserve_yes_required, + "context" => self.context = preserve_yes_required, + "links" => self.links = preserve_yes_required, + "xattr" => self.xattr = preserve_yes_required, _ => { return Err(Error::InvalidArgument(format!( "invalid attribute {}", value.quote() ))); } - }) + }; + Ok(()) } } -fn add_all_attributes() -> Vec { - use Attribute::*; - - let attr = vec![ - #[cfg(unix)] - Ownership, - Mode, - Timestamps, - #[cfg(feature = "feat_selinux")] - Context, - Links, - Xattr, - ]; - - attr -} - impl Options { fn from_matches(matches: &ArgMatches) -> CopyResult { let not_implemented_opts = vec![ @@ -689,7 +746,7 @@ impl Options { let recursive = matches.get_flag(options::RECURSIVE) || matches.get_flag(options::ARCHIVE); let backup_mode = match backup_control::determine_backup_mode(matches) { - Err(e) => return Err(Error::Backup(format!("{}", e))), + Err(e) => return Err(Error::Backup(format!("{e}"))), Ok(mode) => mode, }; @@ -710,22 +767,23 @@ impl Options { }; // Parse attributes to preserve - let mut preserve_attributes: Vec = if matches.contains_id(options::PRESERVE) { + let attributes: Attributes = if matches.contains_id(options::PRESERVE) { match matches.get_many::(options::PRESERVE) { - None => DEFAULT_ATTRIBUTES.to_vec(), + None => Attributes::default(), Some(attribute_strs) => { - let mut attributes = Vec::new(); + let mut attributes: Attributes = Attributes::none(); + let mut attributes_empty = true; for attribute_str in attribute_strs { + attributes_empty = false; if attribute_str == "all" { - attributes = add_all_attributes(); - break; + attributes.max(Attributes::all()); } else { - attributes.push(Attribute::from_str(attribute_str)?); + attributes.try_set_from_string(attribute_str)?; } } // `--preserve` case, use the defaults - if attributes.is_empty() { - DEFAULT_ATTRIBUTES.to_vec() + if attributes_empty { + Attributes::default() } else { attributes } @@ -733,19 +791,27 @@ impl Options { } } else if matches.get_flag(options::ARCHIVE) { // --archive is used. Same as --preserve=all - add_all_attributes() + Attributes::all() } else if matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS) { - vec![Attribute::Links] + let mut attributes = Attributes::none(); + attributes.links = Preserve::Yes { required: true }; + attributes } else if matches.get_flag(options::PRESERVE_DEFAULT_ATTRIBUTES) { - DEFAULT_ATTRIBUTES.to_vec() + Attributes::default() } else { - vec![] + Attributes::none() }; - // Make sure ownership is changed before other attributes, - // as chown clears some of the permission and therefore could undo previous changes - // if not executed first. - preserve_attributes.sort_unstable(); + #[cfg(not(feature = "feat_selinux"))] + if let Preserve::Yes { required } = attributes.context { + let selinux_disabled_error = + Error::Error("SELinux was not enabled during the compile time!".to_string()); + if required { + return Err(selinux_disabled_error); + } else { + show_error_if_needed(&selinux_disabled_error); + } + } let options = Self { attributes_only: matches.get_flag(options::ATTRIBUTES_ONLY), @@ -799,9 +865,8 @@ impl Options { "never" => SparseMode::Never, _ => { return Err(Error::InvalidArgument(format!( - "invalid argument {} for \'sparse\'", - val - ))) + "invalid argument {val} for \'sparse\'" + ))); } } } else { @@ -812,7 +877,7 @@ impl Options { backup_suffix, overwrite, no_target_dir, - preserve_attributes, + attributes, recursive, target_dir, progress_bar: matches.get_flag(options::PROGRESS_BAR), @@ -826,12 +891,10 @@ impl Options { } fn preserve_hard_links(&self) -> bool { - for attribute in &self.preserve_attributes { - if *attribute == Attribute::Links { - return true; - } + match self.attributes.links { + Preserve::No => false, + Preserve::Yes { .. } => true, } - false } /// Whether to force overwriting the destination file. @@ -951,6 +1014,22 @@ fn preserve_hardlinks( Ok(found_hard_link) } +/// When handling errors, we don't always want to show them to the user. This function handles that. +/// If the error is printed, returns true, false otherwise. +fn show_error_if_needed(error: &Error) -> bool { + match error { + // When using --no-clobber, we don't want to show + // an error message + Error::NotAllFilesCopied => (), + Error::Skipped => (), + _ => { + show_error!("{}", error); + return true; + } + } + false +} + /// Copy all `sources` to `target`. Returns an /// `Err(Error::NotAllFilesCopied)` if at least one non-fatal error was /// encountered. @@ -1005,15 +1084,8 @@ fn copy(sources: &[Source], target: &TargetSlice, options: &Options) -> CopyResu options, &mut symlinked_files, ) { - match error { - // When using --no-clobber, we don't want to show - // an error message - Error::NotAllFilesCopied => (), - Error::Skipped => (), - _ => { - show_error!("{}", error); - non_fatal_errors = true; - } + if show_error_if_needed(&error) { + non_fatal_errors = true; } } } @@ -1100,114 +1172,138 @@ impl OverwriteMode { } } +/// Handles errors for attributes preservation. If the attribute is not required, and +/// errored, tries to show error (see `show_error_if_needed` for additional behavior details). +/// If it's required, then the error is thrown. +fn handle_preserve CopyResult<()>>(p: &Preserve, f: F) -> CopyResult<()> { + match p { + Preserve::No => {} + Preserve::Yes { required } => { + let result = f(); + if *required { + result?; + } else if let Err(error) = result { + show_error_if_needed(&error); + } + } + }; + Ok(()) +} + /// Copy the specified attributes from one path to another. pub(crate) fn copy_attributes( source: &Path, dest: &Path, - attributes: &[Attribute], + attributes: &Attributes, ) -> CopyResult<()> { - for attribute in attributes { - copy_attribute(source, dest, attribute)?; - } - Ok(()) -} - -fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResult<()> { let context = &*format!("{} -> {}", source.quote(), dest.quote()); let source_metadata = fs::symlink_metadata(source).context(context)?; - match *attribute { - Attribute::Mode => { - // The `chmod()` system call that underlies the - // `fs::set_permissions()` call is unable to change the - // permissions of a symbolic link. In that case, we just - // do nothing, since every symbolic link has the same - // permissions. - if !dest.is_symlink() { - fs::set_permissions(dest, source_metadata.permissions()).context(context)?; - // FIXME: Implement this for windows as well - #[cfg(feature = "feat_acl")] - exacl::getfacl(source, None) - .and_then(|acl| exacl::setfacl(&[dest], &acl, None)) - .map_err(|err| Error::Error(err.to_string()))?; - } + + // Ownership must be changed first to avoid interfering with mode change. + #[cfg(unix)] + handle_preserve(&attributes.ownership, || -> CopyResult<()> { + use std::os::unix::prelude::MetadataExt; + use uucore::perms::wrap_chown; + use uucore::perms::Verbosity; + use uucore::perms::VerbosityLevel; + + let dest_uid = source_metadata.uid(); + let dest_gid = source_metadata.gid(); + + wrap_chown( + dest, + &dest.symlink_metadata().context(context)?, + Some(dest_uid), + Some(dest_gid), + false, + Verbosity { + groups_only: false, + level: VerbosityLevel::Normal, + }, + ) + .map_err(Error::Error)?; + + Ok(()) + })?; + + handle_preserve(&attributes.mode, || -> CopyResult<()> { + // The `chmod()` system call that underlies the + // `fs::set_permissions()` call is unable to change the + // permissions of a symbolic link. In that case, we just + // do nothing, since every symbolic link has the same + // permissions. + if !dest.is_symlink() { + fs::set_permissions(dest, source_metadata.permissions()).context(context)?; + // FIXME: Implement this for windows as well + #[cfg(feature = "feat_acl")] + exacl::getfacl(source, None) + .and_then(|acl| exacl::setfacl(&[dest], &acl, None)) + .map_err(|err| Error::Error(err.to_string()))?; } - #[cfg(unix)] - Attribute::Ownership => { - use std::os::unix::prelude::MetadataExt; - use uucore::perms::wrap_chown; - use uucore::perms::Verbosity; - use uucore::perms::VerbosityLevel; - let dest_uid = source_metadata.uid(); - let dest_gid = source_metadata.gid(); + Ok(()) + })?; - wrap_chown( - dest, - &dest.symlink_metadata().context(context)?, - Some(dest_uid), - Some(dest_gid), - false, - Verbosity { - groups_only: false, - level: VerbosityLevel::Normal, - }, + handle_preserve(&attributes.timestamps, || -> CopyResult<()> { + let atime = FileTime::from_last_access_time(&source_metadata); + let mtime = FileTime::from_last_modification_time(&source_metadata); + if dest.is_symlink() { + filetime::set_symlink_file_times(dest, atime, mtime)?; + } else { + filetime::set_file_times(dest, atime, mtime)?; + } + + Ok(()) + })?; + + #[cfg(feature = "feat_selinux")] + handle_preserve(&attributes.context, || -> CopyResult<()> { + let context = selinux::SecurityContext::of_path(source, false, false).map_err(|e| { + format!( + "failed to get security context of {}: {}", + source.display(), + e ) - .map_err(Error::Error)?; - } - Attribute::Timestamps => { - let atime = FileTime::from_last_access_time(&source_metadata); - let mtime = FileTime::from_last_modification_time(&source_metadata); - if dest.is_symlink() { - filetime::set_symlink_file_times(dest, atime, mtime)?; - } else { - filetime::set_file_times(dest, atime, mtime)?; - } - } - #[cfg(feature = "feat_selinux")] - Attribute::Context => { - let context = selinux::SecurityContext::of_path(source, false, false).map_err(|e| { + })?; + if let Some(context) = context { + context.set_for_path(dest, false, false).map_err(|e| { format!( - "failed to get security context of {}: {}", - source.display(), + "failed to set security context for {}: {}", + dest.display(), e ) })?; - if let Some(context) = context { - context.set_for_path(dest, false, false).map_err(|e| { - format!( - "failed to set security context for {}: {}", - dest.display(), - e - ) - })?; - } } - Attribute::Links => {} - Attribute::Xattr => { - #[cfg(unix)] - { - let xattrs = xattr::list(source)?; - for attr in xattrs { - if let Some(attr_value) = xattr::get(source, attr.clone())? { - xattr::set(dest, attr, &attr_value[..])?; - } + + Ok(()) + })?; + + handle_preserve(&attributes.xattr, || -> CopyResult<()> { + #[cfg(unix)] + { + let xattrs = xattr::list(source)?; + for attr in xattrs { + if let Some(attr_value) = xattr::get(source, attr.clone())? { + xattr::set(dest, attr, &attr_value[..])?; } } - #[cfg(not(unix))] - { - // The documentation for GNU cp states: - // - // > Try to preserve SELinux security context and - // > extended attributes (xattr), but ignore any failure - // > to do that and print no corresponding diagnostic. - // - // so we simply do nothing here. - // - // TODO Silently ignore failures in the `#[cfg(unix)]` - // block instead of terminating immediately on errors. - } } - }; + #[cfg(not(unix))] + { + // The documentation for GNU cp states: + // + // > Try to preserve SELinux security context and + // > extended attributes (xattr), but ignore any failure + // > to do that and print no corresponding diagnostic. + // + // so we simply do nothing here. + // + // TODO Silently ignore failures in the `#[cfg(unix)]` + // block instead of terminating immediately on errors. + } + + Ok(()) + })?; Ok(()) } @@ -1580,7 +1676,8 @@ fn copy_file( // the user does not have permission to write to the file. fs::set_permissions(dest, dest_permissions).ok(); } - copy_attributes(source, dest, &options.preserve_attributes)?; + + copy_attributes(source, dest, &options.attributes)?; if let Some(progress_bar) = progress_bar { progress_bar.inc(fs::metadata(source)?.len()); @@ -1759,7 +1856,7 @@ mod tests { #[test] fn test_aligned_ancestors() { - let actual = aligned_ancestors(&Path::new("a/b/c"), &Path::new("d/a/b/c")); + let actual = aligned_ancestors(Path::new("a/b/c"), Path::new("d/a/b/c")); let expected = vec![ (Path::new("a"), Path::new("d/a")), (Path::new("a/b"), Path::new("d/a/b")), diff --git a/src/uu/cp/src/platform/macos.rs b/src/uu/cp/src/platform/macos.rs index 0aecc1466..4407e0edf 100644 --- a/src/uu/cp/src/platform/macos.rs +++ b/src/uu/cp/src/platform/macos.rs @@ -69,9 +69,7 @@ pub(crate) fn copy_on_write( // support COW). match reflink_mode { ReflinkMode::Always => { - return Err( - format!("failed to clone {:?} from {:?}: {}", source, dest, error).into(), - ) + return Err(format!("failed to clone {source:?} from {dest:?}: {error}").into()) } _ => { if source_is_fifo { diff --git a/src/uu/csplit/Cargo.toml b/src/uu/csplit/Cargo.toml index 1b6781e74..e9406d478 100644 --- a/src/uu/csplit/Cargo.toml +++ b/src/uu/csplit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_csplit" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "csplit ~ (uutils) Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output" @@ -18,7 +18,7 @@ path = "src/csplit.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } thiserror = "1.0" regex = "1.7.0" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "fs"] } [[bin]] name = "csplit" diff --git a/src/uu/csplit/src/csplit.rs b/src/uu/csplit/src/csplit.rs index bfe2f9512..5e3849687 100644 --- a/src/uu/csplit/src/csplit.rs +++ b/src/uu/csplit/src/csplit.rs @@ -574,7 +574,7 @@ mod tests { assert_eq!(input_splitter.add_line_to_buffer(0, line), None); assert_eq!(input_splitter.buffer_len(), 1); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -583,7 +583,7 @@ mod tests { assert_eq!(input_splitter.add_line_to_buffer(1, line), None); assert_eq!(input_splitter.buffer_len(), 2); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -595,7 +595,7 @@ mod tests { ); assert_eq!(input_splitter.buffer_len(), 2); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; input_splitter.rewind_buffer(); @@ -605,7 +605,7 @@ mod tests { assert_eq!(line, String::from("bbb")); assert_eq!(input_splitter.buffer_len(), 1); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -613,7 +613,7 @@ mod tests { assert_eq!(line, String::from("ccc")); assert_eq!(input_splitter.buffer_len(), 0); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -621,7 +621,7 @@ mod tests { assert_eq!(line, String::from("ddd")); assert_eq!(input_splitter.buffer_len(), 0); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; assert!(input_splitter.next().is_none()); @@ -646,7 +646,7 @@ mod tests { assert_eq!(input_splitter.add_line_to_buffer(0, line), None); assert_eq!(input_splitter.buffer_len(), 1); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -655,7 +655,7 @@ mod tests { assert_eq!(input_splitter.add_line_to_buffer(1, line), None); assert_eq!(input_splitter.buffer_len(), 2); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -664,7 +664,7 @@ mod tests { assert_eq!(input_splitter.add_line_to_buffer(2, line), None); assert_eq!(input_splitter.buffer_len(), 3); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; input_splitter.rewind_buffer(); @@ -675,7 +675,7 @@ mod tests { assert_eq!(input_splitter.add_line_to_buffer(0, line), None); assert_eq!(input_splitter.buffer_len(), 3); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -683,7 +683,7 @@ mod tests { assert_eq!(line, String::from("aaa")); assert_eq!(input_splitter.buffer_len(), 2); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -691,7 +691,7 @@ mod tests { assert_eq!(line, String::from("bbb")); assert_eq!(input_splitter.buffer_len(), 1); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -699,7 +699,7 @@ mod tests { assert_eq!(line, String::from("ccc")); assert_eq!(input_splitter.buffer_len(), 0); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; match input_splitter.next() { @@ -707,7 +707,7 @@ mod tests { assert_eq!(line, String::from("ddd")); assert_eq!(input_splitter.buffer_len(), 0); } - item => panic!("wrong item: {:?}", item), + item => panic!("wrong item: {item:?}"), }; assert!(input_splitter.next().is_none()); diff --git a/src/uu/csplit/src/patterns.rs b/src/uu/csplit/src/patterns.rs index 366794963..652b024d8 100644 --- a/src/uu/csplit/src/patterns.rs +++ b/src/uu/csplit/src/patterns.rs @@ -224,35 +224,35 @@ mod tests { assert_eq!(patterns.len(), 5); match patterns.get(0) { Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(1))) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test1.*end$"); } _ => panic!("expected UpToMatch pattern"), }; match patterns.get(1) { Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Always)) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test2.*end$"); } _ => panic!("expected UpToMatch pattern"), }; match patterns.get(2) { Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(5))) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test3.*end$"); } _ => panic!("expected UpToMatch pattern"), }; match patterns.get(3) { Some(Pattern::UpToMatch(reg, 3, ExecutePattern::Times(1))) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test4.*end$"); } _ => panic!("expected UpToMatch pattern"), }; match patterns.get(4) { Some(Pattern::UpToMatch(reg, -3, ExecutePattern::Times(1))) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test5.*end$"); } _ => panic!("expected UpToMatch pattern"), @@ -277,35 +277,35 @@ mod tests { assert_eq!(patterns.len(), 5); match patterns.get(0) { Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(1))) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test1.*end$"); } _ => panic!("expected SkipToMatch pattern"), }; match patterns.get(1) { Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Always)) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test2.*end$"); } _ => panic!("expected SkipToMatch pattern"), }; match patterns.get(2) { Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(5))) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test3.*end$"); } _ => panic!("expected SkipToMatch pattern"), }; match patterns.get(3) { Some(Pattern::SkipToMatch(reg, 3, ExecutePattern::Times(1))) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test4.*end$"); } _ => panic!("expected SkipToMatch pattern"), }; match patterns.get(4) { Some(Pattern::SkipToMatch(reg, -3, ExecutePattern::Times(1))) => { - let parsed_reg = format!("{}", reg); + let parsed_reg = format!("{reg}"); assert_eq!(parsed_reg, "test5.*end$"); } _ => panic!("expected SkipToMatch pattern"), diff --git a/src/uu/csplit/src/split_name.rs b/src/uu/csplit/src/split_name.rs index bcbdab701..19e3ac9c2 100644 --- a/src/uu/csplit/src/split_name.rs +++ b/src/uu/csplit/src/split_name.rs @@ -42,9 +42,7 @@ impl SplitName { .unwrap_or(2); // translate the custom format into a function let fn_split_name: Box String> = match format_opt { - None => Box::new(move |n: usize| -> String { - format!("{}{:0width$}", prefix, n, width = n_digits) - }), + None => Box::new(move |n: usize| -> String { format!("{prefix}{n:0n_digits$}") }), Some(custom) => { let spec = Regex::new(r"(?P%((?P[0#-])(?P\d+)?)?(?P[diuoxX]))") @@ -55,23 +53,23 @@ impl SplitName { let all = captures.name("ALL").unwrap(); let before = custom[0..all.start()].to_owned(); let after = custom[all.end()..].to_owned(); - let n_digits = match captures.name("WIDTH") { + let width = match captures.name("WIDTH") { None => 0, Some(m) => m.as_str().parse::().unwrap(), }; match (captures.name("FLAG"), captures.name("TYPE")) { (None, Some(ref t)) => match t.as_str() { "d" | "i" | "u" => Box::new(move |n: usize| -> String { - format!("{}{}{}{}", prefix, before, n, after) + format!("{prefix}{before}{n}{after}") }), "o" => Box::new(move |n: usize| -> String { - format!("{}{}{:o}{}", prefix, before, n, after) + format!("{prefix}{before}{n:o}{after}") }), "x" => Box::new(move |n: usize| -> String { - format!("{}{}{:x}{}", prefix, before, n, after) + format!("{prefix}{before}{n:x}{after}") }), "X" => Box::new(move |n: usize| -> String { - format!("{}{}{:X}{}", prefix, before, n, after) + format!("{prefix}{before}{n:X}{after}") }), _ => return Err(CsplitError::SuffixFormatIncorrect), }, @@ -82,47 +80,19 @@ impl SplitName { */ // decimal ("0", "d" | "i" | "u") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:0width$}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:0width$}{after}") }), // octal ("0", "o") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:0width$o}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:0width$o}{after}") }), // lower hexadecimal ("0", "x") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:0width$x}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:0width$x}{after}") }), // upper hexadecimal ("0", "X") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:0width$X}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:0width$X}{after}") }), /* @@ -130,36 +100,15 @@ impl SplitName { */ // octal ("#", "o") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:>#width$o}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:>#width$o}{after}") }), // lower hexadecimal ("#", "x") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:>#width$x}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:>#width$x}{after}") }), // upper hexadecimal ("#", "X") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:>#width$X}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:>#width$X}{after}") }), /* @@ -167,47 +116,19 @@ impl SplitName { */ // decimal ("-", "d" | "i" | "u") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:<#width$}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:<#width$}{after}") }), // octal ("-", "o") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:<#width$o}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:<#width$o}{after}") }), // lower hexadecimal ("-", "x") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:<#width$x}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:<#width$x}{after}") }), // upper hexadecimal ("-", "X") => Box::new(move |n: usize| -> String { - format!( - "{}{}{:<#width$X}{}", - prefix, - before, - n, - after, - width = n_digits - ) + format!("{prefix}{before}{n:<#width$X}{after}") }), _ => return Err(CsplitError::SuffixFormatIncorrect), diff --git a/src/uu/cut/Cargo.toml b/src/uu/cut/Cargo.toml index e8b5034ec..9a4a0b950 100644 --- a/src/uu/cut/Cargo.toml +++ b/src/uu/cut/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_cut" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "cut ~ (uutils) display byte/field columns of input lines" @@ -16,7 +16,7 @@ path = "src/cut.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } memchr = "2" bstr = "1.0" atty = "0.2" diff --git a/src/uu/cut/src/cut.rs b/src/uu/cut/src/cut.rs index 0cc1ec339..9db114fb2 100644 --- a/src/uu/cut/src/cut.rs +++ b/src/uu/cut/src/cut.rs @@ -16,14 +16,15 @@ use uucore::display::Quotable; use uucore::error::{FromIo, UResult, USimpleError}; use self::searcher::Searcher; +use matcher::{ExactMatcher, Matcher, WhitespaceMatcher}; use uucore::ranges::Range; use uucore::{format_usage, show, show_error, show_if_err}; +mod matcher; mod searcher; -static NAME: &str = "cut"; static USAGE: &str = - "{} [-d] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+"; + "{} [-d|-w] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+"; static ABOUT: &str = "Prints specified byte or field columns from each line of stdin or the input files"; static LONG_HELP: &str = " @@ -85,6 +86,11 @@ static LONG_HELP: &str = " --delimiter (-d) option. Setting the delimiter is optional. If not set, a default delimiter of Tab will be used. + If the -w option is provided, fields will be separated by any number + of whitespace characters (Space and Tab). The output delimiter will + be a Tab unless explicitly specified. Only one of -d or -w option can be specified. + This is an extension adopted from FreeBSD. + Optionally Filter based on delimiter If the --only-delimited (-s) flag is provided, only lines which contain the delimiter will be printed @@ -111,8 +117,13 @@ struct Options { zero_terminated: bool, } +enum Delimiter { + Whitespace, + String(String), // FIXME: use char? +} + struct FieldOptions { - delimiter: String, // one char long, String because of UTF8 representation + delimiter: Delimiter, out_delimiter: Option, only_delimited: bool, zero_terminated: bool, @@ -177,23 +188,22 @@ fn cut_bytes(reader: R, ranges: &[Range], opts: &Options) -> UResult<() Ok(()) } -#[allow(clippy::cognitive_complexity)] -fn cut_fields_delimiter( +// Output delimiter is explicitly specified +fn cut_fields_explicit_out_delim( reader: R, + matcher: &M, ranges: &[Range], - delim: &str, only_delimited: bool, newline_char: u8, out_delim: &str, ) -> UResult<()> { let mut buf_in = BufReader::new(reader); let mut out = stdout_writer(); - let input_delim_len = delim.len(); let result = buf_in.for_byte_record_with_terminator(newline_char, |line| { let mut fields_pos = 1; let mut low_idx = 0; - let mut delim_search = Searcher::new(line, delim.as_bytes()).peekable(); + let mut delim_search = Searcher::new(matcher, line).peekable(); let mut print_delim = false; if delim_search.peek().is_none() { @@ -209,13 +219,17 @@ fn cut_fields_delimiter( for &Range { low, high } in ranges { if low - fields_pos > 0 { + // current field is not in the range, so jump to the field corresponding to the + // beginning of the range if any low_idx = match delim_search.nth(low - fields_pos - 1) { - Some(index) => index + input_delim_len, + Some((_, last)) => last, None => break, }; } + // at this point, current field is the first in the range for _ in 0..=high - low { + // skip printing delimiter if this is the first matching field for this line if print_delim { out.write_all(out_delim.as_bytes())?; } else { @@ -223,15 +237,17 @@ fn cut_fields_delimiter( } match delim_search.next() { - Some(high_idx) => { - let segment = &line[low_idx..high_idx]; + // print the current field up to the next field delim + Some((first, last)) => { + let segment = &line[low_idx..first]; out.write_all(segment)?; - low_idx = high_idx + input_delim_len; + low_idx = last; fields_pos = high + 1; } None => { + // this is the last field in the line, so print the rest let segment = &line[low_idx..]; out.write_all(segment)?; @@ -256,32 +272,25 @@ fn cut_fields_delimiter( Ok(()) } -#[allow(clippy::cognitive_complexity)] -fn cut_fields(reader: R, ranges: &[Range], opts: &FieldOptions) -> UResult<()> { - let newline_char = if opts.zero_terminated { b'\0' } else { b'\n' }; - if let Some(ref o_delim) = opts.out_delimiter { - return cut_fields_delimiter( - reader, - ranges, - &opts.delimiter, - opts.only_delimited, - newline_char, - o_delim, - ); - } - +// Output delimiter is the same as input delimiter +fn cut_fields_implicit_out_delim( + reader: R, + matcher: &M, + ranges: &[Range], + only_delimited: bool, + newline_char: u8, +) -> UResult<()> { let mut buf_in = BufReader::new(reader); let mut out = stdout_writer(); - let delim_len = opts.delimiter.len(); let result = buf_in.for_byte_record_with_terminator(newline_char, |line| { let mut fields_pos = 1; let mut low_idx = 0; - let mut delim_search = Searcher::new(line, opts.delimiter.as_bytes()).peekable(); + let mut delim_search = Searcher::new(matcher, line).peekable(); let mut print_delim = false; if delim_search.peek().is_none() { - if !opts.only_delimited { + if !only_delimited { out.write_all(line)?; if line[line.len() - 1] != newline_char { out.write_all(&[newline_char])?; @@ -293,25 +302,21 @@ fn cut_fields(reader: R, ranges: &[Range], opts: &FieldOptions) -> URes for &Range { low, high } in ranges { if low - fields_pos > 0 { - if let Some(delim_pos) = delim_search.nth(low - fields_pos - 1) { - low_idx = if print_delim { - delim_pos - } else { - delim_pos + delim_len - } + if let Some((first, last)) = delim_search.nth(low - fields_pos - 1) { + low_idx = if print_delim { first } else { last } } else { break; } } match delim_search.nth(high - low) { - Some(high_idx) => { - let segment = &line[low_idx..high_idx]; + Some((first, _)) => { + let segment = &line[low_idx..first]; out.write_all(segment)?; print_delim = true; - low_idx = high_idx; + low_idx = first; fields_pos = high + 1; } None => { @@ -337,6 +342,44 @@ fn cut_fields(reader: R, ranges: &[Range], opts: &FieldOptions) -> URes Ok(()) } +fn cut_fields(reader: R, ranges: &[Range], opts: &FieldOptions) -> UResult<()> { + let newline_char = if opts.zero_terminated { b'\0' } else { b'\n' }; + match opts.delimiter { + Delimiter::String(ref delim) => { + let matcher = ExactMatcher::new(delim.as_bytes()); + match opts.out_delimiter { + Some(ref out_delim) => cut_fields_explicit_out_delim( + reader, + &matcher, + ranges, + opts.only_delimited, + newline_char, + out_delim, + ), + None => cut_fields_implicit_out_delim( + reader, + &matcher, + ranges, + opts.only_delimited, + newline_char, + ), + } + } + Delimiter::Whitespace => { + let matcher = WhitespaceMatcher {}; + let out_delim = opts.out_delimiter.as_deref().unwrap_or("\t"); + cut_fields_explicit_out_delim( + reader, + &matcher, + ranges, + opts.only_delimited, + newline_char, + out_delim, + ) + } + } +} + fn cut_files(mut filenames: Vec, mode: &Mode) { let mut stdin_read = false; @@ -387,6 +430,7 @@ mod options { pub const ZERO_TERMINATED: &str = "zero-terminated"; pub const ONLY_DELIMITED: &str = "only-delimited"; pub const OUTPUT_DELIMITER: &str = "output-delimiter"; + pub const WHITESPACE_DELIMITED: &str = "whitespace-delimited"; pub const COMPLEMENT: &str = "complement"; pub const FILE: &str = "file"; } @@ -449,9 +493,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; let only_delimited = matches.get_flag(options::ONLY_DELIMITED); + let whitespace_delimited = matches.get_flag(options::WHITESPACE_DELIMITED); let zero_terminated = matches.get_flag(options::ZERO_TERMINATED); match matches.get_one::(options::DELIMITER).map(|s| s.as_str()) { + Some(_) if whitespace_delimited => { + Err("invalid input: Only one of --delimiter (-d) or -w option can be specified".into()) + } Some(mut delim) => { // GNU's `cut` supports `-d=` to set the delimiter to `=`. // Clap parsing is limited in this situation, see: @@ -474,7 +522,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(Mode::Fields( ranges, FieldOptions { - delimiter: delim, + delimiter: Delimiter::String(delim), out_delimiter: out_delim, only_delimited, zero_terminated, @@ -485,7 +533,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { None => Ok(Mode::Fields( ranges, FieldOptions { - delimiter: "\t".to_owned(), + delimiter: match whitespace_delimited { + true => Delimiter::Whitespace, + false => Delimiter::String("\t".to_owned()), + }, out_delimiter: out_delim, only_delimited, zero_terminated, @@ -508,6 +559,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { { Err("invalid input: The '--delimiter' ('-d') option only usable if printing a sequence of fields".into()) } + Mode::Bytes(_, _) | Mode::Characters(_, _) + if matches.get_flag(options::WHITESPACE_DELIMITED) => + { + Err("invalid input: The '-w' option only usable if printing a sequence of fields".into()) + } Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.get_flag(options::ONLY_DELIMITED) => { @@ -534,7 +590,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .override_usage(format_usage(USAGE)) .about(ABOUT) @@ -563,6 +618,13 @@ pub fn uu_app() -> Command { .help("specify the delimiter character that separates fields in the input source. Defaults to Tab.") .value_name("DELIM"), ) + .arg( + Arg::new(options::WHITESPACE_DELIMITED) + .short('w') + .help("Use any number of whitespace (Space, Tab) to separate fields in the input source (FreeBSD extension).") + .value_name("WHITESPACE") + .action(ArgAction::SetTrue), + ) .arg( Arg::new(options::FIELDS) .short('f') diff --git a/src/uu/cut/src/matcher.rs b/src/uu/cut/src/matcher.rs new file mode 100644 index 000000000..953e083b1 --- /dev/null +++ b/src/uu/cut/src/matcher.rs @@ -0,0 +1,126 @@ +// This file is part of the uutils coreutils package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use memchr::{memchr, memchr2}; + +// Find the next matching byte sequence positions +// Return (first, last) where haystack[first..last] corresponds to the matched pattern +pub trait Matcher { + fn next_match(&self, haystack: &[u8]) -> Option<(usize, usize)>; +} + +// Matches for the exact byte sequence pattern +pub struct ExactMatcher<'a> { + needle: &'a [u8], +} + +impl<'a> ExactMatcher<'a> { + pub fn new(needle: &'a [u8]) -> Self { + assert!(!needle.is_empty()); + Self { needle } + } +} + +impl<'a> Matcher for ExactMatcher<'a> { + fn next_match(&self, haystack: &[u8]) -> Option<(usize, usize)> { + let mut pos = 0usize; + loop { + match memchr(self.needle[0], &haystack[pos..]) { + Some(match_idx) => { + let match_idx = match_idx + pos; // account for starting from pos + if self.needle.len() == 1 + || haystack[match_idx + 1..].starts_with(&self.needle[1..]) + { + return Some((match_idx, match_idx + self.needle.len())); + } else { + pos = match_idx + 1; + } + } + None => { + return None; + } + } + } + } +} + +// Matches for any number of SPACE or TAB +pub struct WhitespaceMatcher {} + +impl Matcher for WhitespaceMatcher { + fn next_match(&self, haystack: &[u8]) -> Option<(usize, usize)> { + match memchr2(b' ', b'\t', haystack) { + Some(match_idx) => { + let mut skip = match_idx + 1; + while skip < haystack.len() { + match haystack[skip] { + b' ' | b'\t' => skip += 1, + _ => break, + } + } + Some((match_idx, skip)) + } + None => None, + } + } +} + +#[cfg(test)] +mod matcher_tests { + + use super::*; + + #[test] + fn test_exact_matcher_single_byte() { + let matcher = ExactMatcher::new(":".as_bytes()); + // spell-checker:disable + assert_eq!(matcher.next_match("".as_bytes()), None); + assert_eq!(matcher.next_match(":".as_bytes()), Some((0, 1))); + assert_eq!(matcher.next_match(":abcxyz".as_bytes()), Some((0, 1))); + assert_eq!(matcher.next_match("abc:xyz".as_bytes()), Some((3, 4))); + assert_eq!(matcher.next_match("abcxyz:".as_bytes()), Some((6, 7))); + assert_eq!(matcher.next_match("abcxyz".as_bytes()), None); + // spell-checker:enable + } + + #[test] + fn test_exact_matcher_multi_bytes() { + let matcher = ExactMatcher::new("<>".as_bytes()); + // spell-checker:disable + assert_eq!(matcher.next_match("".as_bytes()), None); + assert_eq!(matcher.next_match("<>".as_bytes()), Some((0, 2))); + assert_eq!(matcher.next_match("<>abcxyz".as_bytes()), Some((0, 2))); + assert_eq!(matcher.next_match("abc<>xyz".as_bytes()), Some((3, 5))); + assert_eq!(matcher.next_match("abcxyz<>".as_bytes()), Some((6, 8))); + assert_eq!(matcher.next_match("abcxyz".as_bytes()), None); + // spell-checker:enable + } + + #[test] + fn test_whitespace_matcher_single_space() { + let matcher = WhitespaceMatcher {}; + // spell-checker:disable + assert_eq!(matcher.next_match("".as_bytes()), None); + assert_eq!(matcher.next_match(" ".as_bytes()), Some((0, 1))); + assert_eq!(matcher.next_match("\tabcxyz".as_bytes()), Some((0, 1))); + assert_eq!(matcher.next_match("abc\txyz".as_bytes()), Some((3, 4))); + assert_eq!(matcher.next_match("abcxyz ".as_bytes()), Some((6, 7))); + assert_eq!(matcher.next_match("abcxyz".as_bytes()), None); + // spell-checker:enable + } + + #[test] + fn test_whitespace_matcher_multi_spaces() { + let matcher = WhitespaceMatcher {}; + // spell-checker:disable + assert_eq!(matcher.next_match("".as_bytes()), None); + assert_eq!(matcher.next_match(" \t ".as_bytes()), Some((0, 3))); + assert_eq!(matcher.next_match("\t\tabcxyz".as_bytes()), Some((0, 2))); + assert_eq!(matcher.next_match("abc \txyz".as_bytes()), Some((3, 5))); + assert_eq!(matcher.next_match("abcxyz ".as_bytes()), Some((6, 8))); + assert_eq!(matcher.next_match("abcxyz".as_bytes()), None); + // spell-checker:enable + } +} diff --git a/src/uu/cut/src/searcher.rs b/src/uu/cut/src/searcher.rs index d8a040451..95d85c020 100644 --- a/src/uu/cut/src/searcher.rs +++ b/src/uu/cut/src/searcher.rs @@ -5,82 +5,77 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use memchr::memchr; +// spell-checker:ignore multispace -pub struct Searcher<'a> { - haystack: &'a [u8], - needle: &'a [u8], +use super::matcher::Matcher; + +// Generic searcher that relies on a specific matcher +pub struct Searcher<'a, 'b, M: Matcher> { + matcher: &'a M, + haystack: &'b [u8], position: usize, } -impl<'a> Searcher<'a> { - pub fn new(haystack: &'a [u8], needle: &'a [u8]) -> Searcher<'a> { - assert!(!needle.is_empty()); - Searcher { +impl<'a, 'b, M: Matcher> Searcher<'a, 'b, M> { + pub fn new(matcher: &'a M, haystack: &'b [u8]) -> Self { + Self { + matcher, haystack, - needle, position: 0, } } } -impl<'a> Iterator for Searcher<'a> { - type Item = usize; +// Iterate over field delimiters +// Returns (first, last) positions of each sequence, where `haystack[first..last]` +// corresponds to the delimiter. +impl<'a, 'b, M: Matcher> Iterator for Searcher<'a, 'b, M> { + type Item = (usize, usize); fn next(&mut self) -> Option { - loop { - if let Some(match_idx) = memchr(self.needle[0], self.haystack) { - if self.needle.len() == 1 - || self.haystack[match_idx + 1..].starts_with(&self.needle[1..]) - { - let match_pos = self.position + match_idx; - let skip = match_idx + self.needle.len(); - self.haystack = &self.haystack[skip..]; - self.position += skip; - return Some(match_pos); - } else { - let skip = match_idx + 1; - self.haystack = &self.haystack[skip..]; - self.position += skip; - // continue - } - } else { - return None; + match self.matcher.next_match(&self.haystack[self.position..]) { + Some((first, last)) => { + let result = (first + self.position, last + self.position); + self.position += last; + Some(result) } + None => None, } } } #[cfg(test)] -mod tests { +mod exact_searcher_tests { + use super::super::matcher::ExactMatcher; use super::*; - const NEEDLE: &[u8] = "ab".as_bytes(); - #[test] fn test_normal() { - let iter = Searcher::new("a.a.a".as_bytes(), "a".as_bytes()); - let items: Vec = iter.collect(); - assert_eq!(vec![0, 2, 4], items); + let matcher = ExactMatcher::new("a".as_bytes()); + let iter = Searcher::new(&matcher, "a.a.a".as_bytes()); + let items: Vec<(usize, usize)> = iter.collect(); + assert_eq!(vec![(0, 1), (2, 3), (4, 5)], items); } #[test] fn test_empty() { - let iter = Searcher::new("".as_bytes(), "a".as_bytes()); - let items: Vec = iter.collect(); - assert_eq!(vec![] as Vec, items); + let matcher = ExactMatcher::new("a".as_bytes()); + let iter = Searcher::new(&matcher, "".as_bytes()); + let items: Vec<(usize, usize)> = iter.collect(); + assert_eq!(vec![] as Vec<(usize, usize)>, items); } - fn test_multibyte(line: &[u8], expected: &[usize]) { - let iter = Searcher::new(line, NEEDLE); - let items: Vec = iter.collect(); + fn test_multibyte(line: &[u8], expected: &[(usize, usize)]) { + let matcher = ExactMatcher::new("ab".as_bytes()); + let iter = Searcher::new(&matcher, line); + let items: Vec<(usize, usize)> = iter.collect(); assert_eq!(expected, items); } #[test] fn test_multibyte_normal() { - test_multibyte("...ab...ab...".as_bytes(), &[3, 8]); + test_multibyte("...ab...ab...".as_bytes(), &[(3, 5), (8, 10)]); } #[test] @@ -90,16 +85,101 @@ mod tests { #[test] fn test_multibyte_starting_needle() { - test_multibyte("ab...ab...".as_bytes(), &[0, 5]); + test_multibyte("ab...ab...".as_bytes(), &[(0, 2), (5, 7)]); } #[test] fn test_multibyte_trailing_needle() { - test_multibyte("...ab...ab".as_bytes(), &[3, 8]); + test_multibyte("...ab...ab".as_bytes(), &[(3, 5), (8, 10)]); } #[test] fn test_multibyte_first_byte_false_match() { - test_multibyte("aA..aCaC..ab..aD".as_bytes(), &[10]); + test_multibyte("aA..aCaC..ab..aD".as_bytes(), &[(10, 12)]); + } + + #[test] + fn test_searcher_with_exact_matcher() { + let matcher = ExactMatcher::new("<>".as_bytes()); + let haystack = "<><>a<>b<><>cd<><>".as_bytes(); + let mut searcher = Searcher::new(&matcher, haystack); + assert_eq!(searcher.next(), Some((0, 2))); + assert_eq!(searcher.next(), Some((2, 4))); + assert_eq!(searcher.next(), Some((5, 7))); + assert_eq!(searcher.next(), Some((8, 10))); + assert_eq!(searcher.next(), Some((10, 12))); + assert_eq!(searcher.next(), Some((14, 16))); + assert_eq!(searcher.next(), Some((16, 18))); + assert_eq!(searcher.next(), None); + assert_eq!(searcher.next(), None); + } +} + +#[cfg(test)] +mod whitespace_searcher_tests { + + use super::super::matcher::WhitespaceMatcher; + use super::*; + + #[test] + fn test_space() { + let matcher = WhitespaceMatcher {}; + let iter = Searcher::new(&matcher, " . . ".as_bytes()); + let items: Vec<(usize, usize)> = iter.collect(); + assert_eq!(vec![(0, 1), (2, 3), (4, 5)], items); + } + + #[test] + fn test_tab() { + let matcher = WhitespaceMatcher {}; + let iter = Searcher::new(&matcher, "\t.\t.\t".as_bytes()); + let items: Vec<(usize, usize)> = iter.collect(); + assert_eq!(vec![(0, 1), (2, 3), (4, 5)], items); + } + + #[test] + fn test_empty() { + let matcher = WhitespaceMatcher {}; + let iter = Searcher::new(&matcher, "".as_bytes()); + let items: Vec<(usize, usize)> = iter.collect(); + assert_eq!(vec![] as Vec<(usize, usize)>, items); + } + + fn test_multispace(line: &[u8], expected: &[(usize, usize)]) { + let matcher = WhitespaceMatcher {}; + let iter = Searcher::new(&matcher, line); + let items: Vec<(usize, usize)> = iter.collect(); + assert_eq!(expected, items); + } + + #[test] + fn test_multispace_normal() { + test_multispace( + "... ... \t...\t ... \t ...".as_bytes(), + &[(3, 5), (8, 10), (13, 15), (18, 21)], + ); + } + + #[test] + fn test_multispace_begin() { + test_multispace(" \t\t...".as_bytes(), &[(0, 3)]); + } + + #[test] + fn test_multispace_end() { + test_multispace("...\t ".as_bytes(), &[(3, 6)]); + } + + #[test] + fn test_searcher_with_whitespace_matcher() { + let matcher = WhitespaceMatcher {}; + let haystack = "\t a b \t cd\t\t".as_bytes(); + let mut searcher = Searcher::new(&matcher, haystack); + assert_eq!(searcher.next(), Some((0, 2))); + assert_eq!(searcher.next(), Some((3, 4))); + assert_eq!(searcher.next(), Some((5, 8))); + assert_eq!(searcher.next(), Some((10, 12))); + assert_eq!(searcher.next(), None); + assert_eq!(searcher.next(), None); } } diff --git a/src/uu/date/Cargo.toml b/src/uu/date/Cargo.toml index 1f3777487..0bedeabb9 100644 --- a/src/uu/date/Cargo.toml +++ b/src/uu/date/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_date" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "date ~ (uutils) display or set the current time" @@ -17,7 +17,7 @@ path = "src/date.rs" [dependencies] chrono = { version="^0.4.23", default-features=false, features=["std", "alloc", "clock"]} clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 03da2e46d..e02d91f1b 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -117,7 +117,7 @@ impl<'a> From<&'a str> for Iso8601Format { NS => Self::Ns, DATE => Self::Date, // Should be caught by clap - _ => panic!("Invalid format: {}", s), + _ => panic!("Invalid format: {s}"), } } } @@ -135,7 +135,7 @@ impl<'a> From<&'a str> for Rfc3339Format { SECONDS | SECOND => Self::Seconds, NS => Self::Ns, // Should be caught by clap - _ => panic!("Invalid format: {}", s), + _ => panic!("Invalid format: {s}"), } } } @@ -257,7 +257,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .format_with_items(format_items) .to_string() .replace("%f", "%N"); - println!("{}", formatted); + println!("{formatted}"); } Err((input, _err)) => show_error!("invalid date {}", input.quote()), } diff --git a/src/uu/dd/Cargo.toml b/src/uu/dd/Cargo.toml index 89e28e138..10f08d8c3 100644 --- a/src/uu/dd/Cargo.toml +++ b/src/uu/dd/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_dd" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "dd ~ (uutils) copy and convert files" @@ -18,7 +18,7 @@ path = "src/dd.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } gcd = "2.0" libc = "0.2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] signal-hook = "0.3.14" diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 555ae0ac0..813d60ceb 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -491,8 +491,8 @@ impl<'a> Output<'a> { // These objects are counters, initialized to zero. After each // iteration of the main loop, each will be incremented by the // number of blocks read and written, respectively. - let mut rstat = Default::default(); - let mut wstat = Default::default(); + let mut rstat = ReadStat::default(); + let mut wstat = WriteStat::default(); // The time at which the main loop starts executing. // @@ -772,9 +772,7 @@ fn is_stdout_redirected_to_seekable_file() -> bool { let p = Path::new(&s); match File::open(p) { Ok(mut f) => { - f.seek(SeekFrom::Current(0)).is_ok() - && f.seek(SeekFrom::End(0)).is_ok() - && f.seek(SeekFrom::Start(0)).is_ok() + f.stream_position().is_ok() && f.seek(SeekFrom::End(0)).is_ok() && f.rewind().is_ok() } Err(_) => false, } diff --git a/src/uu/dd/src/numbers.rs b/src/uu/dd/src/numbers.rs index 1a32180b7..0cab572b4 100644 --- a/src/uu/dd/src/numbers.rs +++ b/src/uu/dd/src/numbers.rs @@ -80,7 +80,7 @@ pub(crate) fn to_magnitude_and_suffix(n: u128, suffix_type: SuffixType) -> Strin // let quotient = (n as f64) / (base as f64); if quotient < 10.0 { - format!("{:.1} {}", quotient, suffix) + format!("{quotient:.1} {suffix}") } else { format!("{} {}", quotient.round(), suffix) } diff --git a/src/uu/dd/src/parseargs.rs b/src/uu/dd/src/parseargs.rs index 657d29e46..96f6ebfaa 100644 --- a/src/uu/dd/src/parseargs.rs +++ b/src/uu/dd/src/parseargs.rs @@ -394,7 +394,7 @@ impl std::fmt::Display for ParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::UnrecognizedOperand(arg) => { - write!(f, "Unrecognized operand '{}'", arg) + write!(f, "Unrecognized operand '{arg}'") } Self::MultipleFmtTable => { write!( @@ -415,37 +415,37 @@ impl std::fmt::Display for ParseError { // Additional message about 'dd --help' is displayed only in this situation. write!( f, - "invalid input flag: ‘{}’\nTry 'dd --help' for more information.", - arg + "invalid input flag: ‘{}’\nTry '{} --help' for more information.", + arg, + uucore::execution_phrase() ) } Self::ConvFlagNoMatch(arg) => { - write!(f, "Unrecognized conv=CONV -> {}", arg) + write!(f, "Unrecognized conv=CONV -> {arg}") } Self::MultiplierStringParseFailure(arg) => { - write!(f, "Unrecognized byte multiplier -> {}", arg) + write!(f, "Unrecognized byte multiplier -> {arg}") } Self::MultiplierStringOverflow(arg) => { write!( f, - "Multiplier string would overflow on current system -> {}", - arg + "Multiplier string would overflow on current system -> {arg}" ) } Self::BlockUnblockWithoutCBS => { write!(f, "conv=block or conv=unblock specified without cbs=N") } Self::StatusLevelNotRecognized(arg) => { - write!(f, "status=LEVEL not recognized -> {}", arg) + write!(f, "status=LEVEL not recognized -> {arg}") } Self::BsOutOfRange(arg) => { - write!(f, "{}=N cannot fit into memory", arg) + write!(f, "{arg}=N cannot fit into memory") } Self::Unimplemented(arg) => { - write!(f, "feature not implemented on this system -> {}", arg) + write!(f, "feature not implemented on this system -> {arg}") } Self::InvalidNumber(arg) => { - write!(f, "invalid number: ‘{}’", arg) + write!(f, "invalid number: ‘{arg}’") } } } @@ -501,6 +501,7 @@ fn parse_bytes_only(s: &str) -> Result { fn parse_bytes_no_x(full: &str, s: &str) -> Result { let parser = SizeParser { capital_b_bytes: true, + ..Default::default() }; let (num, multiplier) = match (s.find('c'), s.rfind('w'), s.rfind('b')) { (None, None, None) => match parser.parse(s) { diff --git a/src/uu/dd/src/parseargs/unit_tests.rs b/src/uu/dd/src/parseargs/unit_tests.rs index 7084f8114..a135c3572 100644 --- a/src/uu/dd/src/parseargs/unit_tests.rs +++ b/src/uu/dd/src/parseargs/unit_tests.rs @@ -56,29 +56,28 @@ fn unimplemented_flags_should_error() { // The following flags are not implemented for flag in ["cio", "nocache", "nolinks", "text", "binary"] { - let args = vec![format!("iflag={}", flag)]; + let args = vec![format!("iflag={flag}")]; if Parser::new() .parse(&args.iter().map(AsRef::as_ref).collect::>()[..]) .is_ok() { - succeeded.push(format!("iflag={}", flag)); + succeeded.push(format!("iflag={flag}")); } - let args = vec![format!("oflag={}", flag)]; + let args = vec![format!("oflag={flag}")]; if Parser::new() .parse(&args.iter().map(AsRef::as_ref).collect::>()[..]) .is_ok() { - succeeded.push(format!("iflag={}", flag)); + succeeded.push(format!("iflag={flag}")); } } assert!( succeeded.is_empty(), - "The following flags did not panic as expected: {:?}", - succeeded + "The following flags did not panic as expected: {succeeded:?}" ); } diff --git a/src/uu/dd/src/progress.rs b/src/uu/dd/src/progress.rs index 9302bc7a6..6afd841d2 100644 --- a/src/uu/dd/src/progress.rs +++ b/src/uu/dd/src/progress.rs @@ -100,7 +100,7 @@ impl ProgUpdate { match self.read_stat.records_truncated { 0 => {} 1 => writeln!(w, "1 truncated record")?, - n => writeln!(w, "{} truncated records", n)?, + n => writeln!(w, "{n} truncated records")?, } Ok(()) } @@ -154,29 +154,19 @@ impl ProgUpdate { match btotal { 1 => write!( w, - "{}{} byte copied, {:.1} s, {}/s{}", - carriage_return, btotal, duration, transfer_rate, newline, + "{carriage_return}{btotal} byte copied, {duration:.1} s, {transfer_rate}/s{newline}", ), 0..=999 => write!( w, - "{}{} bytes copied, {:.1} s, {}/s{}", - carriage_return, btotal, duration, transfer_rate, newline, + "{carriage_return}{btotal} bytes copied, {duration:.1} s, {transfer_rate}/s{newline}", ), 1000..=1023 => write!( w, - "{}{} bytes ({}) copied, {:.1} s, {}/s{}", - carriage_return, btotal, btotal_metric, duration, transfer_rate, newline, + "{carriage_return}{btotal} bytes ({btotal_metric}) copied, {duration:.1} s, {transfer_rate}/s{newline}", ), _ => write!( w, - "{}{} bytes ({}, {}) copied, {:.1} s, {}/s{}", - carriage_return, - btotal, - btotal_metric, - btotal_bin, - duration, - transfer_rate, - newline, + "{carriage_return}{btotal} bytes ({btotal_metric}, {btotal_bin}) copied, {duration:.1} s, {transfer_rate}/s{newline}", ), } } @@ -455,10 +445,7 @@ pub(crate) fn gen_prog_updater( register_linux_signal_handler(sigval.clone()).unwrap_or_else(|e| { if Some(StatusLevel::None) != print_level { - eprintln!( - "Internal dd Warning: Unable to register signal handler \n\t{}", - e - ); + eprintln!("Internal dd Warning: Unable to register signal handler \n\t{e}"); } }); diff --git a/src/uu/df/Cargo.toml b/src/uu/df/Cargo.toml index e0e15304f..0a229415c 100644 --- a/src/uu/df/Cargo.toml +++ b/src/uu/df/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_df" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "df ~ (uutils) display file system information" @@ -16,7 +16,7 @@ path = "src/df.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["libc", "fsext"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["libc", "fsext"] } unicode-width = "0.1.9" [[bin]] diff --git a/src/uu/df/src/blocks.rs b/src/uu/df/src/blocks.rs index 79151f817..f48d2ffd2 100644 --- a/src/uu/df/src/blocks.rs +++ b/src/uu/df/src/blocks.rs @@ -91,12 +91,12 @@ pub(crate) fn to_magnitude_and_suffix(n: u128, suffix_type: SuffixType) -> Strin let suffix = suffixes[i]; if rem == 0 { - format!("{}{}", quot, suffix) + format!("{quot}{suffix}") } else { let tenths_place = rem / (bases[i] / 10); if rem % (bases[i] / 10) == 0 { - format!("{}.{}{}", quot, tenths_place, suffix) + format!("{quot}.{tenths_place}{suffix}") } else if tenths_place + 1 == 10 || quot >= 10 { format!("{}{}", quot + 1, suffix) } else { @@ -205,7 +205,7 @@ impl fmt::Display for BlockSize { to_magnitude_and_suffix(*n as u128, SuffixType::Si) }; - write!(f, "{}", s) + write!(f, "{s}") } } } diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index 8cefd642f..b3692f481 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -105,11 +105,11 @@ impl Default for Options { Self { show_local_fs: Default::default(), show_all_fs: Default::default(), - block_size: Default::default(), - human_readable: Default::default(), - header_mode: Default::default(), - include: Default::default(), - exclude: Default::default(), + block_size: BlockSize::default(), + human_readable: Option::default(), + header_mode: HeaderMode::default(), + include: Option::default(), + exclude: Option::default(), sync: Default::default(), show_total: Default::default(), columns: vec![ @@ -146,10 +146,10 @@ impl fmt::Display for OptionsError { } // TODO This needs to vary based on whether `--block-size` // or `-B` were provided. - Self::InvalidBlockSize(s) => write!(f, "invalid --block-size argument {}", s), + Self::InvalidBlockSize(s) => write!(f, "invalid --block-size argument {s}"), // TODO This needs to vary based on whether `--block-size` // or `-B` were provided. - Self::InvalidSuffix(s) => write!(f, "invalid suffix in --block-size argument {}", s), + Self::InvalidSuffix(s) => write!(f, "invalid suffix in --block-size argument {s}"), Self::ColumnError(ColumnError::MultipleColumns(s)) => write!( f, "option --output: field {} used more than once", diff --git a/src/uu/df/src/table.rs b/src/uu/df/src/table.rs index 63a135831..a1a58792d 100644 --- a/src/uu/df/src/table.rs +++ b/src/uu/df/src/table.rs @@ -438,7 +438,7 @@ impl fmt::Display for Table { Alignment::Left => { if is_last_col { // no trailing spaces in last column - write!(f, "{}", elem)?; + write!(f, "{elem}")?; } else { write!(f, "{: UResult<()> { ), )); } - println!("{}", INTERNAL_DB); + println!("{INTERNAL_DB}"); return Ok(()); } @@ -157,7 +157,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { match result { Ok(s) => { - println!("{}", s); + println!("{s}"); Ok(()) } Err(s) => { @@ -368,23 +368,23 @@ where if state != ParseState::Pass { if key.starts_with('.') { if *fmt == OutputFmt::Display { - result.push_str(format!("\x1b[{1}m*{0}\t{1}\x1b[0m\n", key, val).as_str()); + result.push_str(format!("\x1b[{val}m*{key}\t{val}\x1b[0m\n").as_str()); } else { - result.push_str(format!("*{}={}:", key, val).as_str()); + result.push_str(format!("*{key}={val}:").as_str()); } } else if key.starts_with('*') { if *fmt == OutputFmt::Display { - result.push_str(format!("\x1b[{1}m{0}\t{1}\x1b[0m\n", key, val).as_str()); + result.push_str(format!("\x1b[{val}m{key}\t{val}\x1b[0m\n").as_str()); } else { - result.push_str(format!("{}={}:", key, val).as_str()); + result.push_str(format!("{key}={val}:").as_str()); } } else if lower == "options" || lower == "color" || lower == "eightbit" { // Slackware only. Ignore } else if let Some(s) = table.get(lower.as_str()) { if *fmt == OutputFmt::Display { - result.push_str(format!("\x1b[{1}m{0}\t{1}\x1b[0m\n", s, val).as_str()); + result.push_str(format!("\x1b[{val}m{s}\t{val}\x1b[0m\n").as_str()); } else { - result.push_str(format!("{}={}:", s, val).as_str()); + result.push_str(format!("{s}={val}:").as_str()); } } else { return Err(format!( diff --git a/src/uu/dirname/Cargo.toml b/src/uu/dirname/Cargo.toml index 4b0320360..9a23d50b9 100644 --- a/src/uu/dirname/Cargo.toml +++ b/src/uu/dirname/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_dirname" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "dirname ~ (uutils) display parent directory of PATHNAME" @@ -16,7 +16,7 @@ path = "src/dirname.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "dirname" diff --git a/src/uu/dirname/src/dirname.rs b/src/uu/dirname/src/dirname.rs index 1f15ccdca..99495f88d 100644 --- a/src/uu/dirname/src/dirname.rs +++ b/src/uu/dirname/src/dirname.rs @@ -63,7 +63,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } } - print!("{}", separator); + print!("{separator}"); } } else { return Err(UUsageError::new(1, "missing operand")); diff --git a/src/uu/du/Cargo.toml b/src/uu/du/Cargo.toml index 3a188e0c3..57855b886 100644 --- a/src/uu/du/Cargo.toml +++ b/src/uu/du/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_du" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "du ~ (uutils) display disk usage" @@ -19,7 +19,7 @@ chrono = { version="^0.4.23", default-features=false, features=["std", "alloc", # For the --exclude & --exclude-from options glob = "0.3.0" clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Storage_FileSystem", "Win32_Foundation"] } diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index f65afa32f..9d1bb776f 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -389,7 +389,7 @@ fn convert_size_human(size: u64, multiplier: u64, _block_size: u64) -> String { if size == 0 { return "0".to_string(); } - format!("{}B", size) + format!("{size}B") } fn convert_size_b(size: u64, _multiplier: u64, _block_size: u64) -> String { @@ -448,7 +448,7 @@ Try '{} --help' for more information.", 'birth' and 'creation' arguments are not supported on this platform.", s.quote() ), - Self::InvalidGlob(s) => write!(f, "Invalid exclude syntax: {}", s), + Self::InvalidGlob(s) => write!(f, "Invalid exclude syntax: {s}"), } } } @@ -650,12 +650,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let time_str = tm.format(time_format_str).to_string(); print!("{}\t{}\t", convert_size(size), time_str); print_verbatim(stat.path).unwrap(); - print!("{}", line_separator); + print!("{line_separator}"); } } else if !summarize || index == len - 1 { print!("{}\t", convert_size(size)); print_verbatim(stat.path).unwrap(); - print!("{}", line_separator); + print!("{line_separator}"); } if options.total && index == (len - 1) { // The last element will be the total size of the the path under @@ -674,7 +674,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if options.total { print!("{}\ttotal", convert_size(grand_total)); - print!("{}", line_separator); + print!("{line_separator}"); } Ok(()) diff --git a/src/uu/echo/Cargo.toml b/src/uu/echo/Cargo.toml index 870a134b5..a241c1427 100644 --- a/src/uu/echo/Cargo.toml +++ b/src/uu/echo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_echo" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "echo ~ (uutils) display TEXT" @@ -16,7 +16,7 @@ path = "src/echo.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "echo" diff --git a/src/uu/echo/src/echo.rs b/src/uu/echo/src/echo.rs index 3a397d6af..e6608682b 100644 --- a/src/uu/echo/src/echo.rs +++ b/src/uu/echo/src/echo.rs @@ -13,7 +13,6 @@ use std::str::Chars; use uucore::error::{FromIo, UResult}; use uucore::format_usage; -const NAME: &str = "echo"; const ABOUT: &str = "display a line of text"; const USAGE: &str = "{} [OPTIONS]... [STRING]..."; const AFTER_HELP: &str = r#" @@ -104,7 +103,7 @@ fn print_escaped(input: &str, mut output: impl Write) -> io::Result { // because printing char slices is apparently not available in the standard library for ch in &buffer[start..] { - write!(output, "{}", ch)?; + write!(output, "{ch}")?; } } @@ -129,7 +128,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) // TrailingVarArg specifies the final positional argument is a VarArg // and it doesn't attempts the parse any further args. // Final argument must have multiple(true) or the usage string equivalent. @@ -175,7 +173,7 @@ fn execute(no_newline: bool, escaped: bool, free: &[String]) -> io::Result<()> { break; } } else { - write!(output, "{}", input)?; + write!(output, "{input}")?; } } diff --git a/src/uu/env/Cargo.toml b/src/uu/env/Cargo.toml index da9cdeab6..311d34c06 100644 --- a/src/uu/env/Cargo.toml +++ b/src/uu/env/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_env" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND" @@ -17,7 +17,7 @@ path = "src/env.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } rust-ini = "0.18.0" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["signals"]} +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["signals"]} [target.'cfg(unix)'.dependencies] nix = { version = "0.25", default-features = false, features = ["signal"] } diff --git a/src/uu/env/src/env.rs b/src/uu/env/src/env.rs index 0776a6b12..a38e04348 100644 --- a/src/uu/env/src/env.rs +++ b/src/uu/env/src/env.rs @@ -210,7 +210,7 @@ fn run_env(args: impl uucore::Args) -> UResult<()> { Err(error) => { return Err(USimpleError::new( 125, - format!("cannot change directory to \"{}\": {}", d, error), + format!("cannot change directory to \"{d}\": {error}"), )); } }; diff --git a/src/uu/expand/Cargo.toml b/src/uu/expand/Cargo.toml index 65660d50e..cac1f173f 100644 --- a/src/uu/expand/Cargo.toml +++ b/src/uu/expand/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_expand" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "expand ~ (uutils) convert input tabs to spaces" @@ -17,7 +17,7 @@ path = "src/expand.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } unicode-width = "0.1.5" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "expand" diff --git a/src/uu/expand/src/expand.rs b/src/uu/expand/src/expand.rs index 63de76fbd..cbb5593f9 100644 --- a/src/uu/expand/src/expand.rs +++ b/src/uu/expand/src/expand.rs @@ -255,7 +255,7 @@ fn expand_shortcuts(args: &[String]) -> Vec { arg[1..] .split(',') .filter(|s| !s.is_empty()) - .for_each(|s| processed_args.push(format!("--tabs={}", s))); + .for_each(|s| processed_args.push(format!("--tabs={s}"))); } else { processed_args.push(arg.to_string()); } diff --git a/src/uu/expr/Cargo.toml b/src/uu/expr/Cargo.toml index e3f8b1d57..18de38a7c 100644 --- a/src/uu/expr/Cargo.toml +++ b/src/uu/expr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_expr" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "expr ~ (uutils) display the value of EXPRESSION" @@ -19,7 +19,7 @@ clap = { version = "4.0", features = ["wrap_help", "cargo"] } num-bigint = "0.4.0" num-traits = "0.2.15" onig = { version = "~6.4", default-features = false } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "expr" diff --git a/src/uu/expr/src/expr.rs b/src/uu/expr/src/expr.rs index 508359e52..a5fab19f2 100644 --- a/src/uu/expr/src/expr.rs +++ b/src/uu/expr/src/expr.rs @@ -73,8 +73,8 @@ fn process_expr(token_strings: &[&str]) -> Result { } fn print_expr_ok(expr_result: &str) -> UResult<()> { - println!("{}", expr_result); - if expr_result == "0" || expr_result.is_empty() { + println!("{expr_result}"); + if expr_result.parse::() == Ok(0) || expr_result.is_empty() { Err(1.into()) } else { Ok(()) diff --git a/src/uu/expr/src/syntax_tree.rs b/src/uu/expr/src/syntax_tree.rs index dbd197017..936760f27 100644 --- a/src/uu/expr/src/syntax_tree.rs +++ b/src/uu/expr/src/syntax_tree.rs @@ -151,7 +151,7 @@ impl AstNode { "index" => Ok(prefix_operator_index(&operand_values)), "substr" => Ok(prefix_operator_substr(&operand_values)), - _ => Err(format!("operation not implemented: {}", op_type)), + _ => Err(format!("operation not implemented: {op_type}")), }, }, } @@ -204,7 +204,7 @@ fn maybe_dump_ast(result: &Result, String>) { println!("EXPR_DEBUG_AST"); match result { Ok(ast) => ast.debug_dump(), - Err(reason) => println!("\terr: {:?}", reason), + Err(reason) => println!("\terr: {reason:?}"), } } } @@ -217,7 +217,7 @@ fn maybe_dump_rpn(rpn: &TokenStack) { if debug_var == "1" { println!("EXPR_DEBUG_RPN"); for token in rpn { - println!("\t{:?}", token); + println!("\t{token:?}"); } } } @@ -238,7 +238,7 @@ fn ast_from_rpn(rpn: &mut TokenStack) -> Result, String> { } Some((token_idx, unexpected_token)) => { - panic!("unexpected token at #{} {:?}", token_idx, unexpected_token) + panic!("unexpected token at #{token_idx} {unexpected_token:?}") } } } @@ -266,14 +266,12 @@ fn move_rest_of_ops_to_out( None => return Ok(()), Some((token_idx, Token::ParOpen)) => { return Err(format!( - "syntax error (Mismatched open-parenthesis at #{})", - token_idx + "syntax error (Mismatched open-parenthesis at #{token_idx})" )) } Some((token_idx, Token::ParClose)) => { return Err(format!( - "syntax error (Mismatched close-parenthesis at #{})", - token_idx + "syntax error (Mismatched close-parenthesis at #{token_idx})" )) } Some(other) => out_stack.push(other), @@ -325,10 +323,10 @@ fn maybe_dump_shunting_yard_step( if let Ok(debug_var) = env::var("EXPR_DEBUG_SYA_STEP") { if debug_var == "1" { println!("EXPR_DEBUG_SYA_STEP"); - println!("\t{} => {:?}", token_idx, token); - println!("\t\tout: {:?}", out_stack); - println!("\t\top : {:?}", op_stack); - println!("\t\tresult: {:?}", result); + println!("\t{token_idx} => {token:?}"); + println!("\t\tout: {out_stack:?}"); + println!("\t\top : {op_stack:?}"); + println!("\t\tresult: {result:?}"); } } } @@ -478,7 +476,7 @@ fn prefix_operator_index(values: &[String]) -> String { for (current_idx, ch_h) in haystack.chars().enumerate() { for ch_n in needles.chars() { if ch_n == ch_h { - return current_idx.to_string(); + return (current_idx + 1).to_string(); } } } diff --git a/src/uu/expr/src/tokens.rs b/src/uu/expr/src/tokens.rs index 6ff930f81..21220d7dc 100644 --- a/src/uu/expr/src/tokens.rs +++ b/src/uu/expr/src/tokens.rs @@ -122,7 +122,7 @@ fn maybe_dump_tokens_acc(tokens_acc: &[(usize, Token)]) { if debug_var == "1" { println!("EXPR_DEBUG_TOKENS"); for token in tokens_acc { - println!("\t{:?}", token); + println!("\t{token:?}"); } } } diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index b5b091b45..06175a515 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_factor" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "factor ~ (uutils) display the prime factors of each NUMBER" @@ -20,7 +20,7 @@ coz = { version = "0.1.3", optional = true } num-traits = "0.2.15" # Needs at least version 0.2.15 for "OverflowingAdd" rand = { version = "0.8", features = ["small_rng"] } smallvec = { version = "1.10", features = ["union"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [dev-dependencies] paste = "1.0.6" diff --git a/src/uu/factor/build.rs b/src/uu/factor/build.rs index aad2aac77..bdd132094 100644 --- a/src/uu/factor/build.rs +++ b/src/uu/factor/build.rs @@ -46,7 +46,7 @@ fn main() { .and_then(|s| s.parse::().ok()) .unwrap_or(DEFAULT_SIZE); - write!(file, "{}", PREAMBLE).unwrap(); + write!(file, "{PREAMBLE}").unwrap(); let mut cols = 3; // we want a total of n + 1 values @@ -60,10 +60,10 @@ fn main() { // format the table let output = format!("({}, {}, {}),", x, modular_inverse(x), std::u64::MAX / x); if cols + output.len() > MAX_WIDTH { - write!(file, "\n {}", output).unwrap(); + write!(file, "\n {output}").unwrap(); cols = 4 + output.len(); } else { - write!(file, " {}", output).unwrap(); + write!(file, " {output}").unwrap(); cols += 1 + output.len(); } @@ -72,8 +72,7 @@ fn main() { write!( file, - "\n];\n\n#[allow(dead_code)]\npub const NEXT_PRIME: u64 = {};\n", - x + "\n];\n\n#[allow(dead_code)]\npub const NEXT_PRIME: u64 = {x};\n" ) .unwrap(); } diff --git a/src/uu/factor/src/factor.rs b/src/uu/factor/src/factor.rs index c776f95ea..5d1615342 100644 --- a/src/uu/factor/src/factor.rs +++ b/src/uu/factor/src/factor.rs @@ -99,7 +99,7 @@ impl fmt::Display for Factors { for (p, exp) in v.iter() { for _ in 0..*exp { - write!(f, " {}", p)?; + write!(f, " {p}")?; } } diff --git a/src/uu/factor/src/miller_rabin.rs b/src/uu/factor/src/miller_rabin.rs index 8906abf59..4908959fb 100644 --- a/src/uu/factor/src/miller_rabin.rs +++ b/src/uu/factor/src/miller_rabin.rs @@ -153,8 +153,7 @@ mod tests { for p in odd_primes() { assert!( test(Montgomery::::new(p)).is_prime(), - "{} reported composite", - p + "{p} reported composite" ); } } @@ -173,7 +172,7 @@ mod tests { fn first_composites() { for (p, q) in primes().zip(odd_primes()) { for i in p + 1..q { - assert!(!is_prime(i), "{} reported prime", i); + assert!(!is_prime(i), "{i} reported prime"); } } } @@ -192,7 +191,7 @@ mod tests { for q in odd_primes().take_while(|q| *q <= p) { let n = p * q; let m = Montgomery::::new(n); - assert!(!test(m).is_prime(), "{} = {} × {} reported prime", n, p, q); + assert!(!test(m).is_prime(), "{n} = {p} × {q} reported prime"); } } } diff --git a/src/uu/factor/src/numeric/gcd.rs b/src/uu/factor/src/numeric/gcd.rs index 089318f48..05eb20cb0 100644 --- a/src/uu/factor/src/numeric/gcd.rs +++ b/src/uu/factor/src/numeric/gcd.rs @@ -32,8 +32,8 @@ pub fn gcd(mut u: u64, mut v: u64) -> u64 { loop { // Loop invariant: u and v are odd - debug_assert!(u % 2 == 1, "u = {} is even", u); - debug_assert!(v % 2 == 1, "v = {} is even", v); + debug_assert!(u % 2 == 1, "u = {u} is even"); + debug_assert!(v % 2 == 1, "v = {v} is even"); // gcd(u, v) = gcd(|u - v|, min(u, v)) if u > v { diff --git a/src/uu/factor/src/numeric/modular_inverse.rs b/src/uu/factor/src/numeric/modular_inverse.rs index 5b37a9782..edf3c6cce 100644 --- a/src/uu/factor/src/numeric/modular_inverse.rs +++ b/src/uu/factor/src/numeric/modular_inverse.rs @@ -13,7 +13,7 @@ use super::traits::Int; pub(crate) fn modular_inverse(a: T) -> T { let zero = T::zero(); let one = T::one(); - debug_assert!(a % (one + one) == one, "{:?} is not odd", a); + debug_assert!(a % (one + one) == one, "{a:?} is not odd"); let mut t = zero; let mut new_t = one; diff --git a/src/uu/factor/src/numeric/montgomery.rs b/src/uu/factor/src/numeric/montgomery.rs index 368a71182..e07b95358 100644 --- a/src/uu/factor/src/numeric/montgomery.rs +++ b/src/uu/factor/src/numeric/montgomery.rs @@ -192,7 +192,7 @@ mod tests { let m_x = m.to_mod(x); for y in 0..=x { let m_y = m.to_mod(y); - println!("{n:?}, {x:?}, {y:?}", n = n, x = x, y = y); + println!("{n:?}, {x:?}, {y:?}"); assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y))); } } diff --git a/src/uu/false/Cargo.toml b/src/uu/false/Cargo.toml index 1bc1f848e..848d872aa 100644 --- a/src/uu/false/Cargo.toml +++ b/src/uu/false/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_false" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "false ~ (uutils) do nothing and fail" @@ -16,7 +16,7 @@ path = "src/false.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "false" diff --git a/src/uu/fmt/Cargo.toml b/src/uu/fmt/Cargo.toml index 0e0445853..5f6449508 100644 --- a/src/uu/fmt/Cargo.toml +++ b/src/uu/fmt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_fmt" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "fmt ~ (uutils) reformat each paragraph of input" @@ -17,7 +17,7 @@ path = "src/fmt.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } unicode-width = "0.1.5" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "fmt" diff --git a/src/uu/fmt/src/linebreak.rs b/src/uu/fmt/src/linebreak.rs index 75a5f81ac..75cd633bb 100644 --- a/src/uu/fmt/src/linebreak.rs +++ b/src/uu/fmt/src/linebreak.rs @@ -27,7 +27,7 @@ struct BreakArgs<'a> { } impl<'a> BreakArgs<'a> { - fn compute_width<'b>(&self, winfo: &WordInfo<'b>, posn: usize, fresh: bool) -> usize { + fn compute_width(&self, winfo: &WordInfo, posn: usize, fresh: bool) -> usize { if fresh { 0 } else { diff --git a/src/uu/fold/Cargo.toml b/src/uu/fold/Cargo.toml index e0f91af8c..44fe202f9 100644 --- a/src/uu/fold/Cargo.toml +++ b/src/uu/fold/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_fold" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "fold ~ (uutils) wrap each line of input" @@ -16,7 +16,7 @@ path = "src/fold.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "fold" diff --git a/src/uu/fold/src/fold.rs b/src/uu/fold/src/fold.rs index 77ec359ef..dee30b258 100644 --- a/src/uu/fold/src/fold.rs +++ b/src/uu/fold/src/fold.rs @@ -17,7 +17,6 @@ use uucore::format_usage; const TAB_WIDTH: usize = 8; -static NAME: &str = "fold"; 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"; @@ -63,7 +62,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .override_usage(format_usage(USAGE)) .about(ABOUT) @@ -190,9 +188,9 @@ fn fold_file_bytewise(mut file: BufReader, spaces: bool, width: usiz let at_eol = i >= len; if at_eol { - print!("{}", slice); + print!("{slice}"); } else { - println!("{}", slice); + println!("{slice}"); } } @@ -287,7 +285,7 @@ fn fold_file(mut file: BufReader, spaces: bool, width: usize) -> URe } if !output.is_empty() { - print!("{}", output); + print!("{output}"); output.truncate(0); } diff --git a/src/uu/groups/Cargo.toml b/src/uu/groups/Cargo.toml index a1bacbb47..3dec2ca9a 100644 --- a/src/uu/groups/Cargo.toml +++ b/src/uu/groups/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_groups" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "groups ~ (uutils) display group memberships for USERNAME" @@ -16,7 +16,7 @@ path = "src/groups.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "process"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "process"] } [[bin]] name = "groups" diff --git a/src/uu/groups/src/groups.rs b/src/uu/groups/src/groups.rs index 4fa53a232..c866d0e1b 100644 --- a/src/uu/groups/src/groups.rs +++ b/src/uu/groups/src/groups.rs @@ -49,7 +49,7 @@ impl Display for GroupsError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::GetGroupsFailed => write!(f, "failed to fetch groups"), - Self::GroupNotFound(gid) => write!(f, "cannot find name for group ID {}", gid), + Self::GroupNotFound(gid) => write!(f, "cannot find name for group ID {gid}"), Self::UserNotFound(user) => write!(f, "{}: no such user", user.quote()), } } diff --git a/src/uu/hashsum/Cargo.toml b/src/uu/hashsum/Cargo.toml index 21e760296..38c5e7278 100644 --- a/src/uu/hashsum/Cargo.toml +++ b/src/uu/hashsum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_hashsum" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "hashsum ~ (uutils) display or check input digests" @@ -26,7 +26,7 @@ sha2 = "0.10.2" sha3 = "0.10.6" blake2b_simd = "1.0.0" blake3 = "1.3.2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "hashsum" diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 5e0973a16..3271425bc 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -520,13 +520,12 @@ where // where `n` is the number of bytes. let bytes = options.digest.output_bits() / 4; let modifier = if bytes > 0 { - format!("{{{}}}", bytes) + format!("{{{bytes}}}") } else { "+".to_string() }; let gnu_re = Regex::new(&format!( - r"^(?P[a-fA-F0-9]{}) (?P[ \*])(?P.*)", - modifier, + r"^(?P[a-fA-F0-9]{modifier}) (?P[ \*])(?P.*)", )) .map_err(|_| HashsumError::InvalidRegex)?; let bsd_re = Regex::new(&format!( @@ -579,7 +578,7 @@ where uucore::util_name(), ck_filename ); - println!("{}: FAILED open or read", ck_filename); + println!("{ck_filename}: FAILED open or read"); continue; } Ok(file) => file, @@ -604,11 +603,11 @@ where // easier (and more important) on Unix than on Windows. if sum == real_sum { if !options.quiet { - println!("{}: OK", ck_filename); + println!("{ck_filename}: OK"); } } else { if !options.status { - println!("{}: FAILED", ck_filename); + println!("{ck_filename}: FAILED"); } failed_cksum += 1; } @@ -624,7 +623,7 @@ where if options.tag { println!("{} ({}) = {}", options.algoname, filename.display(), sum); } else if options.nonames { - println!("{}", sum); + println!("{sum}"); } else { println!("{} {}{}", sum, binary_marker, filename.display()); } diff --git a/src/uu/head/Cargo.toml b/src/uu/head/Cargo.toml index 8c9a6f884..3a4dd42f2 100644 --- a/src/uu/head/Cargo.toml +++ b/src/uu/head/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_head" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "head ~ (uutils) display the first lines of input" @@ -17,7 +17,7 @@ path = "src/head.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } memchr = "2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["ringbuffer", "lines"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["ringbuffer", "lines"] } [[bin]] name = "head" diff --git a/src/uu/head/src/head.rs b/src/uu/head/src/head.rs index 32a4ad376..48debc81f 100644 --- a/src/uu/head/src/head.rs +++ b/src/uu/head/src/head.rs @@ -134,7 +134,7 @@ impl Mode { fn from(matches: &ArgMatches) -> Result { if let Some(v) = matches.get_one::(options::BYTES_NAME) { let (n, all_but_last) = - parse::parse_num(v).map_err(|err| format!("invalid number of bytes: {}", err))?; + parse::parse_num(v).map_err(|err| format!("invalid number of bytes: {err}"))?; if all_but_last { Ok(Self::AllButLastBytes(n)) } else { @@ -142,14 +142,14 @@ impl Mode { } } else if let Some(v) = matches.get_one::(options::LINES_NAME) { let (n, all_but_last) = - parse::parse_num(v).map_err(|err| format!("invalid number of lines: {}", err))?; + parse::parse_num(v).map_err(|err| format!("invalid number of lines: {err}"))?; if all_but_last { Ok(Self::AllButLastLines(n)) } else { Ok(Self::FirstLines(n)) } } else { - Ok(Default::default()) + Ok(Self::default()) } } } @@ -387,13 +387,13 @@ where } // if it were just `n`, if lines == n + 1 { - input.seek(SeekFrom::Start(0))?; + input.rewind()?; return Ok(size - i); } i += 1; } if size - i == 0 { - input.seek(SeekFrom::Start(0))?; + input.rewind()?; return Ok(0); } } @@ -459,7 +459,7 @@ fn uu_head(options: &HeadOptions) -> UResult<()> { if let Err(e) = usize::try_from(n) { show!(USimpleError::new( 1, - format!("{}: number of bytes is too large", e) + format!("{e}: number of bytes is too large") )); continue; }; @@ -493,7 +493,7 @@ fn uu_head(options: &HeadOptions) -> UResult<()> { if !first { println!(); } - println!("==> {} <==", name); + println!("==> {name} <=="); } head_file(&mut file, options) } @@ -506,7 +506,7 @@ fn uu_head(options: &HeadOptions) -> UResult<()> { }; show!(USimpleError::new( 1, - format!("error reading {}: Input/output error", name) + format!("error reading {name}: Input/output error") )); } first = false; diff --git a/src/uu/head/src/parse.rs b/src/uu/head/src/parse.rs index 3b7c718ab..cbfc97152 100644 --- a/src/uu/head/src/parse.rs +++ b/src/uu/head/src/parse.rs @@ -79,10 +79,10 @@ pub fn parse_obsolete(src: &str) -> Option Some(n) => n, None => return Some(Err(ParseError::Overflow)), }; - options.push(OsString::from(format!("{}", num))); + options.push(OsString::from(format!("{num}"))); } else { options.push(OsString::from("-n")); - options.push(OsString::from(format!("{}", num))); + options.push(OsString::from(format!("{num}"))); } Some(Ok(options.into_iter())) } diff --git a/src/uu/hostid/Cargo.toml b/src/uu/hostid/Cargo.toml index 81dfb68d1..348e35723 100644 --- a/src/uu/hostid/Cargo.toml +++ b/src/uu/hostid/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_hostid" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "hostid ~ (uutils) display the numeric identifier of the current host" @@ -17,7 +17,7 @@ path = "src/hostid.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "hostid" diff --git a/src/uu/hostid/src/hostid.rs b/src/uu/hostid/src/hostid.rs index 293a9cacd..147c7c548 100644 --- a/src/uu/hostid/src/hostid.rs +++ b/src/uu/hostid/src/hostid.rs @@ -50,5 +50,5 @@ fn hostid() { let mask = 0xffff_ffff; result &= mask; - println!("{:0>8x}", result); + println!("{result:0>8x}"); } diff --git a/src/uu/hostname/Cargo.toml b/src/uu/hostname/Cargo.toml index f3563be2b..e4df40263 100644 --- a/src/uu/hostname/Cargo.toml +++ b/src/uu/hostname/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_hostname" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "hostname ~ (uutils) display or set the host name of the current host" @@ -17,7 +17,7 @@ path = "src/hostname.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } hostname = { version = "0.3", features = ["set"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["wide"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["wide"] } [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Networking_WinSock", "Win32_Foundation"] } diff --git a/src/uu/hostname/src/hostname.rs b/src/uu/hostname/src/hostname.rs index 92950f137..03e9fe2e0 100644 --- a/src/uu/hostname/src/hostname.rs +++ b/src/uu/hostname/src/hostname.rs @@ -164,7 +164,7 @@ fn display_hostname(matches: &ArgMatches) -> UResult<()> { } } - println!("{}", hostname); + println!("{hostname}"); Ok(()) } diff --git a/src/uu/id/Cargo.toml b/src/uu/id/Cargo.toml index 0329df212..4437b4898 100644 --- a/src/uu/id/Cargo.toml +++ b/src/uu/id/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_id" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "id ~ (uutils) display user and group information for USER" @@ -16,7 +16,7 @@ path = "src/id.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "process"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "process"] } selinux = { version="0.3", optional = true } [[bin]] diff --git a/src/uu/id/src/id.rs b/src/uu/id/src/id.rs index a26034f47..9aa6e2f31 100644 --- a/src/uu/id/src/id.rs +++ b/src/uu/id/src/id.rs @@ -326,7 +326,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if default_format { id_print(&mut state, &groups); } - print!("{}", line_ending); + print!("{line_ending}"); if i + 1 >= users.len() { break; @@ -468,11 +468,11 @@ fn pretty(possible_pw: Option) { let rid = getuid(); if let Ok(p) = Passwd::locate(rid) { if login == p.name { - println!("login\t{}", login); + println!("login\t{login}"); } println!("uid\t{}", p.name); } else { - println!("uid\t{}", rid); + println!("uid\t{rid}"); } let eid = getegid(); @@ -480,7 +480,7 @@ fn pretty(possible_pw: Option) { if let Ok(p) = Passwd::locate(eid) { println!("euid\t{}", p.name); } else { - println!("euid\t{}", eid); + println!("euid\t{eid}"); } } @@ -489,7 +489,7 @@ fn pretty(possible_pw: Option) { if let Ok(g) = Group::locate(rid) { println!("euid\t{}", g.name); } else { - println!("euid\t{}", rid); + println!("euid\t{rid}"); } } diff --git a/src/uu/install/Cargo.toml b/src/uu/install/Cargo.toml index 8766c3786..b51f2bbd2 100644 --- a/src/uu/install/Cargo.toml +++ b/src/uu/install/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_install" -version = "0.0.16" +version = "0.0.17" authors = [ "Ben Eills ", "uutils developers", @@ -22,7 +22,7 @@ clap = { version = "4.0", features = ["wrap_help", "cargo"] } filetime = "0.2" file_diff = "1.0.0" libc = ">= 0.2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs", "mode", "perms", "entries"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs", "mode", "perms", "entries"] } [dev-dependencies] time = "0.3" diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index db9fe7d3c..597eacc67 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -87,7 +87,7 @@ impl Error for InstallError {} impl Display for InstallError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Unimplemented(opt) => write!(f, "Unimplemented feature: {}", opt), + Self::Unimplemented(opt) => write!(f, "Unimplemented feature: {opt}"), Self::DirNeedsArg() => { write!( f, @@ -115,7 +115,7 @@ impl Display for InstallError { &uio_error!(e, "cannot install {} to {}", from.quote(), to.quote()), f, ), - Self::StripProgramFailed(msg) => write!(f, "strip program failed: {}", msg), + Self::StripProgramFailed(msg) => write!(f, "strip program failed: {msg}"), Self::MetadataFailed(e) => Display::fmt(&uio_error!(e, ""), f), Self::NoSuchUser(user) => write!(f, "no such user: {}", user.maybe_quote()), Self::NoSuchGroup(group) => write!(f, "no such group: {}", group.maybe_quote()), diff --git a/src/uu/join/Cargo.toml b/src/uu/join/Cargo.toml index 0d9e700ac..3b8231185 100644 --- a/src/uu/join/Cargo.toml +++ b/src/uu/join/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_join" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "join ~ (uutils) merge lines from inputs with matching join fields" @@ -16,7 +16,7 @@ path = "src/join.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } memchr = "2" [[bin]] diff --git a/src/uu/join/src/join.rs b/src/uu/join/src/join.rs index 396ed6a6d..ffcf6fdcd 100644 --- a/src/uu/join/src/join.rs +++ b/src/uu/join/src/join.rs @@ -24,8 +24,6 @@ use uucore::display::Quotable; use uucore::error::{set_exit_code, UError, UResult, USimpleError}; use uucore::{crash, crash_if_err}; -static NAME: &str = "join"; - #[derive(Debug)] enum JoinError { IOError(std::io::Error), @@ -43,7 +41,7 @@ impl Error for JoinError {} impl Display for JoinError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::IOError(e) => write!(f, "io error: {}", e), + Self::IOError(e) => write!(f, "io error: {e}"), Self::UnorderedInput(e) => f.write_str(e), } } @@ -606,7 +604,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let key1 = parse_field_number_option(matches.get_one::("1").map(|s| s.as_str()))?; let key2 = parse_field_number_option(matches.get_one::("2").map(|s| s.as_str()))?; - let mut settings: Settings = Default::default(); + let mut settings = Settings::default(); let v_values = matches.get_many::("v"); if v_values.is_some() { @@ -694,12 +692,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { match exec(file1, file2, settings) { Ok(_) => Ok(()), - Err(e) => Err(USimpleError::new(1, format!("{}", e))), + Err(e) => Err(USimpleError::new(1, format!("{e}"))), } } pub fn uu_app() -> Command { - Command::new(NAME) + Command::new(uucore::util_name()) .version(crate_version!()) .about( "For each pair of input lines with identical join fields, write a line to diff --git a/src/uu/kill/Cargo.toml b/src/uu/kill/Cargo.toml index cc8d960a4..21431e3fe 100644 --- a/src/uu/kill/Cargo.toml +++ b/src/uu/kill/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_kill" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "kill ~ (uutils) send a signal to a process" @@ -17,7 +17,7 @@ path = "src/kill.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } nix = { version = "0.25", features = ["signal"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["signals"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["signals"] } [[bin]] name = "kill" diff --git a/src/uu/kill/src/kill.rs b/src/uu/kill/src/kill.rs index 3e55f8166..c14023e82 100644 --- a/src/uu/kill/src/kill.rs +++ b/src/uu/kill/src/kill.rs @@ -146,11 +146,11 @@ fn table() { fn print_signal(signal_name_or_value: &str) -> UResult<()> { for (value, &signal) in ALL_SIGNALS.iter().enumerate() { - if signal == signal_name_or_value || (format!("SIG{}", signal)) == signal_name_or_value { - println!("{}", value); + if signal == signal_name_or_value || (format!("SIG{signal}")) == signal_name_or_value { + println!("{value}"); return Ok(()); } else if signal_name_or_value == value.to_string() { - println!("{}", signal); + println!("{signal}"); return Ok(()); } } @@ -165,7 +165,7 @@ fn print_signals() { if idx > 0 { print!(" "); } - print!("{}", signal); + print!("{signal}"); } println!(); } @@ -205,7 +205,7 @@ fn kill(sig: Signal, pids: &[i32]) { for &pid in pids { if let Err(e) = signal::kill(Pid::from_raw(pid), sig) { show!(Error::from_raw_os_error(e as i32) - .map_err_context(|| format!("sending signal to {} failed", pid))); + .map_err_context(|| format!("sending signal to {pid} failed"))); } } } diff --git a/src/uu/link/Cargo.toml b/src/uu/link/Cargo.toml index 6b4e218da..5a8984f1f 100644 --- a/src/uu/link/Cargo.toml +++ b/src/uu/link/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_link" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "link ~ (uutils) create a hard (file system) link to FILE" @@ -16,7 +16,7 @@ path = "src/link.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "link" diff --git a/src/uu/ln/Cargo.toml b/src/uu/ln/Cargo.toml index 33a300ee1..2f07c8c4d 100644 --- a/src/uu/ln/Cargo.toml +++ b/src/uu/ln/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_ln" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "ln ~ (uutils) create a (file system) link to TARGET" @@ -16,7 +16,7 @@ path = "src/ln.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "ln" diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index 6ba8a98e8..55bc34f8a 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -466,7 +466,7 @@ fn simple_backup_path(path: &Path, suffix: &str) -> PathBuf { fn numbered_backup_path(path: &Path) -> PathBuf { let mut i: u64 = 1; loop { - let new_path = simple_backup_path(path, &format!(".~{}~", i)); + let new_path = simple_backup_path(path, &format!(".~{i}~")); if !new_path.exists() { return new_path; } diff --git a/src/uu/logname/Cargo.toml b/src/uu/logname/Cargo.toml index 72c264fe6..a75e5efa7 100644 --- a/src/uu/logname/Cargo.toml +++ b/src/uu/logname/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_logname" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "logname ~ (uutils) display the login name of the current user" @@ -17,7 +17,7 @@ path = "src/logname.rs" [dependencies] libc = "0.2.137" clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "logname" diff --git a/src/uu/logname/src/logname.rs b/src/uu/logname/src/logname.rs index ef6eb2940..fd5ab904e 100644 --- a/src/uu/logname/src/logname.rs +++ b/src/uu/logname/src/logname.rs @@ -38,7 +38,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let _ = uu_app().try_get_matches_from(args)?; match get_userlogin() { - Some(userlogin) => println!("{}", userlogin), + Some(userlogin) => println!("{userlogin}"), None => show_error!("no login name"), } diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index 5941b72a8..c68c6b5ae 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_ls" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "ls ~ (uutils) display directory contents" @@ -23,7 +23,7 @@ term_grid = "0.1.5" terminal_size = "0.2.2" glob = "0.3.0" lscolors = { version = "0.13.0", default-features=false, features = ["nu-ansi-term"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features = ["entries", "fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features = ["entries", "fs"] } once_cell = "1.13.1" atty = "0.2" selinux = { version="0.3", optional = true } diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index fdf368e4b..965248495 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -197,7 +197,7 @@ impl Display for LsError { ) } Self::InvalidLineWidth(s) => write!(f, "invalid line width: {}", s.quote()), - Self::IOError(e) => write!(f, "general io error: {}", e), + Self::IOError(e) => write!(f, "general io error: {e}"), Self::IOErrorContext(e, p, _) => { let error_kind = e.kind(); let errno = e.raw_os_error().unwrap_or(1i32); @@ -2067,11 +2067,11 @@ fn display_dir_entry_size( } fn pad_left(string: &str, count: usize) -> String { - format!("{:>width$}", string, width = count) + format!("{string:>count$}") } fn pad_right(string: &str, count: usize) -> String { - format!("{:) -> UResult<()> { @@ -2118,7 +2118,7 @@ fn display_additional_leading_info( }; // extra space is insert to align the sizes, as needed for all formats, except for the comma format. if config.format == Format::Commas { - write!(result, "{} ", s).unwrap(); + write!(result, "{s} ").unwrap(); } else { write!(result, "{} ", pad_left(&s, padding.block_size)).unwrap(); }; @@ -2139,13 +2139,13 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter { - write!(out, "{}", output)?; + write!(out, "{output}")?; } // Width is too small for the grid, so we fit it in one column None => { @@ -2440,7 +2440,7 @@ fn display_item_long( write!( out, "{}{} {}", - format_args!("{}?????????", leading_char), + format_args!("{leading_char}?????????"), if item.security_context.len() > 1 { // GNU `ls` uses a "." character to indicate a file with a security context, // but not other alternate access method. @@ -2875,7 +2875,7 @@ fn display_file_name( } else { path.security_context.to_owned() }; - name = format!("{} {}", security_context, name); + name = format!("{security_context} {name}"); width += security_context.len() + 1; } } diff --git a/src/uu/mkdir/Cargo.toml b/src/uu/mkdir/Cargo.toml index 54a644ca2..93aaea73f 100644 --- a/src/uu/mkdir/Cargo.toml +++ b/src/uu/mkdir/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mkdir" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "mkdir ~ (uutils) create DIRECTORY" @@ -16,7 +16,7 @@ path = "src/mkdir.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs", "mode"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs", "mode"] } [[bin]] name = "mkdir" diff --git a/src/uu/mkdir/src/mkdir.rs b/src/uu/mkdir/src/mkdir.rs index 038d688f9..046091b34 100644 --- a/src/uu/mkdir/src/mkdir.rs +++ b/src/uu/mkdir/src/mkdir.rs @@ -55,7 +55,7 @@ fn get_mode(matches: &ArgMatches, mode_had_minus_prefix: bool) -> Result UResult<()> { let mode = match matches.get_one::(options::MODE) { Some(m) => match usize::from_str_radix(m, 8) { Ok(m) => m, - Err(e) => return Err(USimpleError::new(1, format!("invalid mode: {}", e))), + Err(e) => return Err(USimpleError::new(1, format!("invalid mode: {e}"))), }, None => 0o666, }; @@ -67,7 +66,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .override_usage(format_usage(USAGE)) .about(ABOUT) diff --git a/src/uu/mknod/Cargo.toml b/src/uu/mknod/Cargo.toml index 03a09279f..8fbcc0777 100644 --- a/src/uu/mknod/Cargo.toml +++ b/src/uu/mknod/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mknod" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "mknod ~ (uutils) create special file NAME of TYPE" @@ -18,7 +18,7 @@ path = "src/mknod.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "^0.2.137" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["mode"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["mode"] } [[bin]] name = "mknod" diff --git a/src/uu/mknod/src/mknod.rs b/src/uu/mknod/src/mknod.rs index 2a1290d41..f4c6f5732 100644 --- a/src/uu/mknod/src/mknod.rs +++ b/src/uu/mknod/src/mknod.rs @@ -184,7 +184,7 @@ fn get_mode(matches: &ArgMatches) -> Result { match matches.get_one::("mode") { None => Ok(MODE_RW_UGO), Some(str_mode) => uucore::mode::parse_mode(str_mode) - .map_err(|e| format!("invalid mode ({})", e)) + .map_err(|e| format!("invalid mode ({e})")) .and_then(|mode| { if mode > 0o777 { Err("mode must specify only file permission bits".to_string()) diff --git a/src/uu/mktemp/Cargo.toml b/src/uu/mktemp/Cargo.toml index ddabaabcd..d00fb4c05 100644 --- a/src/uu/mktemp/Cargo.toml +++ b/src/uu/mktemp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mktemp" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "mktemp ~ (uutils) create and display a temporary file or directory from TEMPLATE" @@ -18,7 +18,7 @@ path = "src/mktemp.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } rand = "0.8" tempfile = "3" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "mktemp" diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 740644c95..d8056ffce 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -313,7 +313,7 @@ impl Params { // the template is "XXXabc", then `suffix` is "abc.txt". let suffix_from_option = options.suffix.unwrap_or_default(); let suffix_from_template = &options.template[j..]; - let suffix = format!("{}{}", suffix_from_template, suffix_from_option); + let suffix = format!("{suffix_from_template}{suffix_from_option}"); if suffix.contains(MAIN_SEPARATOR) { return Err(MkTempError::SuffixContainsDirSeparator(suffix)); } diff --git a/src/uu/more/Cargo.toml b/src/uu/more/Cargo.toml index 000e5620b..b52ed1880 100644 --- a/src/uu/more/Cargo.toml +++ b/src/uu/more/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_more" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "more ~ (uutils) input perusal filter" @@ -16,7 +16,7 @@ path = "src/more.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } crossterm = ">=0.19" atty = "0.2" unicode-width = "0.1.7" diff --git a/src/uu/more/src/more.rs b/src/uu/more/src/more.rs index a58e108ae..0309ad33e 100644 --- a/src/uu/more/src/more.rs +++ b/src/uu/more/src/more.rs @@ -383,9 +383,7 @@ impl<'a> Pager<'a> { .take(self.content_rows.into()); for line in displayed_lines { - stdout - .write_all(format!("\r{}\n", line).as_bytes()) - .unwrap(); + stdout.write_all(format!("\r{line}\n").as_bytes()).unwrap(); } } @@ -399,15 +397,14 @@ impl<'a> Pager<'a> { ) }; - let status = format!("--More--({})", status_inner); + let status = format!("--More--({status_inner})"); let banner = match (self.silent, wrong_key) { (true, Some(key)) => format!( - "{} [Unknown key: '{}'. Press 'h' for instructions. (unimplemented)]", - status, key + "{status} [Unknown key: '{key}'. Press 'h' for instructions. (unimplemented)]" ), - (true, None) => format!("{}[Press space to continue, 'q' to quit.]", status), - (false, Some(_)) => format!("{}{}", status, BELL), + (true, None) => format!("{status}[Press space to continue, 'q' to quit.]"), + (false, Some(_)) => format!("{status}{BELL}"), (false, None) => status, }; diff --git a/src/uu/mv/Cargo.toml b/src/uu/mv/Cargo.toml index 71caec101..7ef274153 100644 --- a/src/uu/mv/Cargo.toml +++ b/src/uu/mv/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_mv" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "mv ~ (uutils) move (rename) SOURCE to DESTINATION" @@ -19,7 +19,7 @@ clap = { version = "4.0", features = ["wrap_help", "cargo"] } fs_extra = "1.1.0" indicatif = "0.17" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "mv" diff --git a/src/uu/mv/src/error.rs b/src/uu/mv/src/error.rs index 77f777836..103c1116a 100644 --- a/src/uu/mv/src/error.rs +++ b/src/uu/mv/src/error.rs @@ -22,22 +22,19 @@ impl UError for MvError {} impl Display for MvError { fn fmt(&self, f: &mut Formatter) -> Result { match self { - Self::NoSuchFile(s) => write!(f, "cannot stat {}: No such file or directory", s), - Self::SameFile(s, t) => write!(f, "{} and {} are the same file", s, t), + Self::NoSuchFile(s) => write!(f, "cannot stat {s}: No such file or directory"), + Self::SameFile(s, t) => write!(f, "{s} and {t} are the same file"), Self::SelfSubdirectory(s) => write!( f, - "cannot move '{s}' to a subdirectory of itself, '{s}/{s}'", - s = s + "cannot move '{s}' to a subdirectory of itself, '{s}/{s}'" ), Self::DirectoryToNonDirectory(t) => { - write!(f, "cannot overwrite directory {} with non-directory", t) + write!(f, "cannot overwrite directory {t} with non-directory") } - Self::NonDirectoryToDirectory(s, t) => write!( - f, - "cannot overwrite non-directory {} with directory {}", - t, s - ), - Self::NotADirectory(t) => write!(f, "target {} is not a directory", t), + Self::NonDirectoryToDirectory(s, t) => { + write!(f, "cannot overwrite non-directory {t} with directory {s}") + } + Self::NotADirectory(t) => write!(f, "target {t} is not a directory"), } } } diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index d37bc06d5..0a1394594 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -91,8 +91,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { app.error( ErrorKind::TooFewValues, format!( - "The argument '<{}>...' requires at least 2 values, but only 1 was provided", - ARG_FILES + "The argument '<{ARG_FILES}>...' requires at least 2 values, but only 1 was provided" ), ) .exit(); @@ -284,12 +283,12 @@ fn exec(files: &[OsString], b: &Behavior) -> UResult<()> { if target.is_dir() { if b.no_target_dir { - if !source.is_dir() { - Err(MvError::DirectoryToNonDirectory(target.quote().to_string()).into()) - } else { + if source.is_dir() { rename(source, target, b, None).map_err_context(|| { format!("cannot move {} to {}", source.quote(), target.quote()) }) + } else { + Err(MvError::DirectoryToNonDirectory(target.quote().to_string()).into()) } } else { move_files_into_dir(&[source.clone()], target, b) @@ -310,7 +309,7 @@ fn exec(files: &[OsString], b: &Behavior) -> UResult<()> { ) .into()) } else { - rename(source, target, b, None).map_err(|e| USimpleError::new(1, format!("{}", e))) + rename(source, target, b, None).map_err(|e| USimpleError::new(1, format!("{e}"))) } } _ => { @@ -473,9 +472,9 @@ fn rename( match multi_progress { Some(pb) => pb.suspend(|| { - println!("{}", message); + println!("{message}"); }), - None => println!("{}", message), + None => println!("{message}"), }; } Ok(()) @@ -547,7 +546,7 @@ fn rename_with_fallback( io::ErrorKind::PermissionDenied, "Permission denied", )), - _ => Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", err))), + _ => Err(io::Error::new(io::ErrorKind::Other, format!("{err:?}"))), }; } } else { diff --git a/src/uu/nice/Cargo.toml b/src/uu/nice/Cargo.toml index f9ea3c38c..b3f013bde 100644 --- a/src/uu/nice/Cargo.toml +++ b/src/uu/nice/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_nice" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "nice ~ (uutils) run PROGRAM with modified scheduling priority" @@ -18,7 +18,7 @@ path = "src/nice.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" nix = { version = "0.25", default-features = false } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "nice" diff --git a/src/uu/nice/src/nice.rs b/src/uu/nice/src/nice.rs index a2c8ceeef..a059e13b7 100644 --- a/src/uu/nice/src/nice.rs +++ b/src/uu/nice/src/nice.rs @@ -8,14 +8,14 @@ // spell-checker:ignore (ToDO) getpriority execvp setpriority nstr PRIO cstrs ENOENT use libc::{c_char, c_int, execvp, PRIO_PROCESS}; -use std::ffi::CString; -use std::io::Error; +use std::ffi::{CString, OsString}; +use std::io::{Error, Write}; use std::ptr; use clap::{crate_version, Arg, ArgAction, Command}; use uucore::{ error::{set_exit_code, UClapError, UResult, USimpleError, UUsageError}, - format_usage, show_error, show_warning, + format_usage, show_error, }; pub mod options { @@ -30,8 +30,89 @@ const ABOUT: &str = "\ process)."; const USAGE: &str = "{} [OPTIONS] [COMMAND [ARGS]]"; +fn is_prefix_of(maybe_prefix: &str, target: &str, min_match: usize) -> bool { + if maybe_prefix.len() < min_match || maybe_prefix.len() > target.len() { + return false; + } + + &target[0..maybe_prefix.len()] == maybe_prefix +} + +/// Transform legacy arguments into a standardized form. +/// +/// The following are all legal argument sequences to GNU nice: +/// - "-1" +/// - "-n1" +/// - "-+1" +/// - "--1" +/// - "-n -1" +/// +/// It looks initially like we could add handling for "-{i}", "--{i}" +/// and "-+{i}" for integers {i} and process them normally using clap. +/// However, the meaning of "-1", for example, changes depending on +/// its context with legacy argument parsing. clap will not prioritize +/// hyphenated values to previous arguments over matching a known +/// argument. So "-n" "-1" in this case is picked up as two +/// arguments, not one argument with a value. +/// +/// Given this context dependency, and the deep hole we end up digging +/// with clap in this case, it's much simpler to just normalize the +/// arguments to nice before clap starts work. Here, we insert a +/// prefix of "-n" onto all arguments of the form "-{i}", "--{i}" and +/// "-+{i}" which are not already preceded by "-n". +fn standardize_nice_args(mut args: impl uucore::Args) -> impl uucore::Args { + let mut v = Vec::::new(); + let mut saw_n = false; + let mut saw_command = false; + if let Some(cmd) = args.next() { + v.push(cmd); + } + for s in args { + if saw_command { + v.push(s); + } else if saw_n { + let mut new_arg: OsString = "-n".into(); + new_arg.push(s); + v.push(new_arg); + saw_n = false; + } else if s.to_str() == Some("-n") + || s.to_str() + .map(|s| is_prefix_of(s, "--adjustment", "--a".len())) + .unwrap_or_default() + { + saw_n = true; + } else if let Ok(s) = s.clone().into_string() { + if let Some(stripped) = s.strip_prefix('-') { + match stripped.parse::() { + Ok(ix) => { + let mut new_arg: OsString = "-n".into(); + new_arg.push(ix.to_string()); + v.push(new_arg); + } + Err(_) => { + v.push(s.into()); + } + } + } else { + saw_command = true; + v.push(s.into()); + } + } else { + saw_command = true; + v.push(s); + } + } + if saw_n { + v.push("-n".into()); + } + + v.into_iter() +} + #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let args = standardize_nice_args(args); + let matches = uu_app().try_get_matches_from(args).with_exit_code(125)?; nix::errno::Errno::clear(); @@ -56,14 +137,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Err(e) => { return Err(USimpleError::new( 125, - format!("\"{}\" is not a valid number: {}", nstr, e), + format!("\"{nstr}\" is not a valid number: {e}"), )) } } } None => { if !matches.contains_id(options::COMMAND) { - println!("{}", niceness); + println!("{niceness}"); return Ok(()); } 10_i32 @@ -71,8 +152,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; niceness += adjustment; - if unsafe { libc::setpriority(PRIO_PROCESS, 0, niceness) } == -1 { - show_warning!("setpriority: {}", Error::last_os_error()); + // We can't use `show_warning` because that will panic if stderr + // isn't writable. The GNU test suite checks specifically that the + // exit code when failing to write the advisory is 125, but Rust + // will produce an exit code of 101 when it panics. + if unsafe { libc::setpriority(PRIO_PROCESS, 0, niceness) } == -1 + && write!( + std::io::stderr(), + "{}: warning: setpriority: {}", + uucore::util_name(), + Error::last_os_error() + ) + .is_err() + { + set_exit_code(125); + return Ok(()); } let cstrs: Vec = matches @@ -109,6 +203,8 @@ pub fn uu_app() -> Command { .short('n') .long(options::ADJUSTMENT) .help("add N to the niceness (default is 10)") + .action(ArgAction::Set) + .overrides_with(options::ADJUSTMENT) .allow_hyphen_values(true), ) .arg( diff --git a/src/uu/nl/Cargo.toml b/src/uu/nl/Cargo.toml index 8ad9697a0..0d3d03341 100644 --- a/src/uu/nl/Cargo.toml +++ b/src/uu/nl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_nl" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "nl ~ (uutils) display input with added line numbers" @@ -17,7 +17,7 @@ path = "src/nl.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } regex = "1.7.0" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "nl" diff --git a/src/uu/nl/src/nl.rs b/src/uu/nl/src/nl.rs index 451f77048..6243bef8d 100644 --- a/src/uu/nl/src/nl.rs +++ b/src/uu/nl/src/nl.rs @@ -18,7 +18,6 @@ use uucore::format_usage; mod helper; -static NAME: &str = "nl"; static ABOUT: &str = "number lines of files"; static USAGE: &str = "{} [OPTION]... [FILE]..."; @@ -141,7 +140,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .about(ABOUT) .version(crate_version!()) .override_usage(format_usage(USAGE)) @@ -351,7 +349,7 @@ fn nl(reader: &mut BufReader, settings: &Settings) -> UResult<()> { // want to print one in the first place, or it is a blank // line but we are still collecting more blank lines via // the option --join-blank-lines. - println!("{}", line); + println!("{line}"); continue; } // If we make it here, then either we are printing a non-empty diff --git a/src/uu/nohup/Cargo.toml b/src/uu/nohup/Cargo.toml index 883c90b9d..4ad495245 100644 --- a/src/uu/nohup/Cargo.toml +++ b/src/uu/nohup/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_nohup" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "nohup ~ (uutils) run COMMAND, ignoring hangup signals" @@ -18,7 +18,7 @@ path = "src/nohup.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" atty = "0.2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "nohup" diff --git a/src/uu/nohup/src/nohup.rs b/src/uu/nohup/src/nohup.rs index 1dc1cbdd0..789888ea4 100644 --- a/src/uu/nohup/src/nohup.rs +++ b/src/uu/nohup/src/nohup.rs @@ -65,7 +65,7 @@ impl Display for NohupError { fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { match self { Self::CannotDetach => write!(f, "Cannot detach from console"), - Self::CannotReplace(s, e) => write!(f, "Cannot replace {}: {}", s, e), + Self::CannotReplace(s, e) => write!(f, "Cannot replace {s}: {e}"), Self::OpenFailed(_, e) => { write!(f, "failed to open {}: {}", NOHUP_OUT.quote(), e) } diff --git a/src/uu/nproc/Cargo.toml b/src/uu/nproc/Cargo.toml index 45c1dd81f..c720990b4 100644 --- a/src/uu/nproc/Cargo.toml +++ b/src/uu/nproc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_nproc" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "nproc ~ (uutils) display the number of processing units available" @@ -18,7 +18,7 @@ path = "src/nproc.rs" libc = "0.2.137" num_cpus = "1.14" clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "nproc" diff --git a/src/uu/nproc/src/nproc.rs b/src/uu/nproc/src/nproc.rs index e74303dd8..960957df6 100644 --- a/src/uu/nproc/src/nproc.rs +++ b/src/uu/nproc/src/nproc.rs @@ -92,7 +92,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } else { cores -= ignore; } - println!("{}", cores); + println!("{cores}"); Ok(()) } diff --git a/src/uu/numfmt/Cargo.toml b/src/uu/numfmt/Cargo.toml index 491177016..c6358bd6f 100644 --- a/src/uu/numfmt/Cargo.toml +++ b/src/uu/numfmt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_numfmt" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "numfmt ~ (uutils) reformat NUMBER" @@ -16,7 +16,7 @@ path = "src/numfmt.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "numfmt" diff --git a/src/uu/numfmt/src/errors.rs b/src/uu/numfmt/src/errors.rs index c9f63f921..22c6962d6 100644 --- a/src/uu/numfmt/src/errors.rs +++ b/src/uu/numfmt/src/errors.rs @@ -32,7 +32,7 @@ impl Display for NumfmtError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::IoError(s) | Self::IllegalArgument(s) | Self::FormattingError(s) => { - write!(f, "{}", s) + write!(f, "{s}") } } } diff --git a/src/uu/numfmt/src/format.rs b/src/uu/numfmt/src/format.rs index b97993f21..3e20d00ee 100644 --- a/src/uu/numfmt/src/format.rs +++ b/src/uu/numfmt/src/format.rs @@ -135,13 +135,11 @@ fn remove_suffix(i: f64, s: Option, u: &Unit) -> Result { RawSuffix::Z => Ok(i * IEC_BASES[7]), RawSuffix::Y => Ok(i * IEC_BASES[8]), }, - (None, &Unit::Iec(true)) => Err(format!( - "missing 'i' suffix in input: '{}' (e.g Ki/Mi/Gi)", - i - )), + (None, &Unit::Iec(true)) => { + Err(format!("missing 'i' suffix in input: '{i}' (e.g Ki/Mi/Gi)")) + } (Some((raw_suffix, false)), &Unit::Iec(true)) => Err(format!( - "missing 'i' suffix in input: '{}{:?}' (e.g Ki/Mi/Gi)", - i, raw_suffix + "missing 'i' suffix in input: '{i}{raw_suffix:?}' (e.g Ki/Mi/Gi)" )), (Some((raw_suffix, with_i)), &Unit::None) => Err(format!( "rejecting suffix in input: '{}{:?}{}' (consider using --from)", @@ -320,7 +318,7 @@ fn format_string( // bring back the suffix before applying padding let number_with_suffix = match &options.suffix { - Some(suffix) => format!("{}{}", number, suffix), + Some(suffix) => format!("{number}{suffix}"), None => number, }; @@ -362,14 +360,14 @@ fn format_and_print_delimited(s: &str, options: &NumfmtOptions) -> Result<()> { // print delimiter before second and subsequent fields if n > 1 { - print!("{}", delimiter); + print!("{delimiter}"); } if field_selected { print!("{}", format_string(field.trim_start(), options, None)?); } else { // print unselected field without conversion - print!("{}", field); + print!("{field}"); } } @@ -402,7 +400,7 @@ fn format_and_print_whitespace(s: &str, options: &NumfmtOptions) -> Result<()> { print!("{}", format_string(field, options, implicit_padding)?); } else { // print unselected field without conversion - print!("{}{}", prefix, field); + print!("{prefix}{field}"); } } diff --git a/src/uu/numfmt/src/numfmt.rs b/src/uu/numfmt/src/numfmt.rs index 80b604e6d..8730c9f8d 100644 --- a/src/uu/numfmt/src/numfmt.rs +++ b/src/uu/numfmt/src/numfmt.rs @@ -46,7 +46,7 @@ where for (idx, line) in lines.by_ref().enumerate() { match line { Ok(l) if idx < options.header => { - println!("{}", l); + println!("{l}"); Ok(()) } Ok(l) => match format_and_print(&l, options) { @@ -403,8 +403,8 @@ mod tests { let mock_buffer = MockBuffer {}; let result = handle_buffer(BufReader::new(mock_buffer), &get_valid_options()) .expect_err("returned Ok after receiving IO error"); - let result_debug = format!("{:?}", result); - let result_display = format!("{}", result); + let result_debug = format!("{result:?}"); + let result_display = format!("{result}"); assert_eq!(result_debug, "IoError(\"broken pipe\")"); assert_eq!(result_display, "broken pipe"); assert_eq!(result.code(), 1); @@ -415,8 +415,8 @@ mod tests { let input_value = b"135\nhello"; let result = handle_buffer(BufReader::new(&input_value[..]), &get_valid_options()) .expect_err("returned Ok after receiving improperly formatted input"); - let result_debug = format!("{:?}", result); - let result_display = format!("{}", result); + let result_debug = format!("{result:?}"); + let result_display = format!("{result}"); assert_eq!( result_debug, "FormattingError(\"invalid suffix in input: 'hello'\")" diff --git a/src/uu/numfmt/src/options.rs b/src/uu/numfmt/src/options.rs index dc2b73925..79d7461ae 100644 --- a/src/uu/numfmt/src/options.rs +++ b/src/uu/numfmt/src/options.rs @@ -128,9 +128,9 @@ impl FromStr for FormatOptions { if iter.peek().is_none() { return if options.prefix == s { - Err(format!("format '{}' has no % directive", s)) + Err(format!("format '{s}' has no % directive")) } else { - Err(format!("format '{}' ends in %", s)) + Err(format!("format '{s}' ends in %")) }; } @@ -151,8 +151,7 @@ impl FromStr for FormatOptions { Some(c) if c.is_ascii_digit() => padding.push('-'), _ => { return Err(format!( - "invalid format '{}', directive must be %[0]['][-][N][.][N]f", - s + "invalid format '{s}', directive must be %[0]['][-][N][.][N]f" )) } } @@ -171,7 +170,7 @@ impl FromStr for FormatOptions { if let Ok(p) = padding.parse() { options.padding = Some(p); } else { - return Err(format!("invalid format '{}' (width overflow)", s)); + return Err(format!("invalid format '{s}' (width overflow)")); } } @@ -179,7 +178,7 @@ impl FromStr for FormatOptions { iter.next(); if matches!(iter.peek(), Some(' ' | '+' | '-')) { - return Err(format!("invalid precision in format '{}'", s)); + return Err(format!("invalid precision in format '{s}'")); } while let Some(c) = iter.peek() { @@ -195,7 +194,7 @@ impl FromStr for FormatOptions { if let Ok(p) = precision.parse() { options.precision = Some(p); } else { - return Err(format!("invalid precision in format '{}'", s)); + return Err(format!("invalid precision in format '{s}'")); } } else { options.precision = Some(0); @@ -206,8 +205,7 @@ impl FromStr for FormatOptions { iter.next(); } else { return Err(format!( - "invalid format '{}', directive must be %[0]['][-][N][.][N]f", - s + "invalid format '{s}', directive must be %[0]['][-][N][.][N]f" )); } @@ -222,7 +220,7 @@ impl FromStr for FormatOptions { } iter.next(); } else { - return Err(format!("format '{}' has too many % directives", s)); + return Err(format!("format '{s}' has too many % directives")); } } diff --git a/src/uu/od/Cargo.toml b/src/uu/od/Cargo.toml index fdd92721a..827436354 100644 --- a/src/uu/od/Cargo.toml +++ b/src/uu/od/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_od" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "od ~ (uutils) display formatted representation of input" @@ -18,7 +18,7 @@ path = "src/od.rs" byteorder = "1.3.2" clap = { version = "4.0", features = ["wrap_help", "cargo"] } half = "2.1" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "od" diff --git a/src/uu/od/src/formatteriteminfo.rs b/src/uu/od/src/formatteriteminfo.rs index 6d51fa3a3..00ee2ee20 100644 --- a/src/uu/od/src/formatteriteminfo.rs +++ b/src/uu/od/src/formatteriteminfo.rs @@ -22,9 +22,9 @@ impl PartialEq for FormatWriter { use crate::formatteriteminfo::FormatWriter::*; match (self, other) { - (&IntWriter(ref a), &IntWriter(ref b)) => a == b, - (&FloatWriter(ref a), &FloatWriter(ref b)) => a == b, - (&MultibyteWriter(ref a), &MultibyteWriter(ref b)) => *a as usize == *b as usize, + (IntWriter(a), IntWriter(b)) => a == b, + (FloatWriter(a), FloatWriter(b)) => a == b, + (MultibyteWriter(a), MultibyteWriter(b)) => *a as usize == *b as usize, _ => false, } } diff --git a/src/uu/od/src/inputdecoder.rs b/src/uu/od/src/inputdecoder.rs index c347ccc10..31e833698 100644 --- a/src/uu/od/src/inputdecoder.rs +++ b/src/uu/od/src/inputdecoder.rs @@ -136,7 +136,7 @@ impl<'a> MemoryDecoder<'a> { 2 => u64::from(self.byte_order.read_u16(&self.data[start..start + 2])), 4 => u64::from(self.byte_order.read_u32(&self.data[start..start + 4])), 8 => self.byte_order.read_u64(&self.data[start..start + 8]), - _ => panic!("Invalid byte_size: {}", byte_size), + _ => panic!("Invalid byte_size: {byte_size}"), } } @@ -148,7 +148,7 @@ impl<'a> MemoryDecoder<'a> { )), 4 => f64::from(self.byte_order.read_f32(&self.data[start..start + 4])), 8 => self.byte_order.read_f64(&self.data[start..start + 8]), - _ => panic!("Invalid byte_size: {}", byte_size), + _ => panic!("Invalid byte_size: {byte_size}"), } } } diff --git a/src/uu/od/src/inputoffset.rs b/src/uu/od/src/inputoffset.rs index 8aadf969d..ddaf747f1 100644 --- a/src/uu/od/src/inputoffset.rs +++ b/src/uu/od/src/inputoffset.rs @@ -50,7 +50,7 @@ impl InputOffset { (Radix::Octal, None) => format!("{:07o}", self.byte_pos), (Radix::Octal, Some(l)) => format!("{:07o} ({:07o})", self.byte_pos, l), (Radix::NoPrefix, None) => String::new(), - (Radix::NoPrefix, Some(l)) => format!("({:07o})", l), + (Radix::NoPrefix, Some(l)) => format!("({l:07o})"), } } diff --git a/src/uu/od/src/od.rs b/src/uu/od/src/od.rs index 63641d671..77480cb38 100644 --- a/src/uu/od/src/od.rs +++ b/src/uu/od/src/od.rs @@ -131,7 +131,7 @@ impl OdOptions { _ => { return Err(USimpleError::new( 1, - format!("Invalid argument --endian={}", s), + format!("Invalid argument --endian={s}"), )) } } @@ -155,7 +155,7 @@ impl OdOptions { let mut label: Option = None; let parsed_input = parse_inputs(matches) - .map_err(|e| USimpleError::new(1, format!("Invalid inputs: {}", e)))?; + .map_err(|e| USimpleError::new(1, format!("Invalid inputs: {e}")))?; let input_strings = match parsed_input { CommandLineInputs::FileNames(v) => v, CommandLineInputs::FileAndOffset((f, s, l)) => { @@ -173,7 +173,7 @@ impl OdOptions { if matches.value_source(options::WIDTH) == Some(ValueSource::CommandLine) { match parse_number_of_bytes(s) { Ok(n) => usize::try_from(n) - .map_err(|_| USimpleError::new(1, format!("‘{}‘ is too large", s)))?, + .map_err(|_| USimpleError::new(1, format!("‘{s}‘ is too large")))?, Err(e) => { return Err(USimpleError::new( 1, @@ -625,15 +625,15 @@ fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &Output } if first { - print!("{}", prefix); // print offset - // if printing in multiple formats offset is printed only once + print!("{prefix}"); // print offset + // if printing in multiple formats offset is printed only once first = false; } else { // this takes the space of the file offset on subsequent // lines of multi-format rasters. print!("{:>width$}", "", width = prefix.chars().count()); } - println!("{}", output_text); + println!("{output_text}"); } } diff --git a/src/uu/od/src/prn_char.rs b/src/uu/od/src/prn_char.rs index 742229dd7..495b8eace 100644 --- a/src/uu/od/src/prn_char.rs +++ b/src/uu/od/src/prn_char.rs @@ -48,8 +48,8 @@ fn format_item_c(bytes: &[u8]) -> String { if b & 0x80 == 0x00 { match C_CHARS.get(b as usize) { - Some(s) => format!("{:>4}", s), - None => format!("{:>4}", b), + Some(s) => format!("{s:>4}"), + None => format!("{b:>4}"), } } else if (b & 0xc0) == 0x80 { // second or subsequent octet of an utf-8 sequence @@ -57,24 +57,24 @@ fn format_item_c(bytes: &[u8]) -> String { } else if ((b & 0xe0) == 0xc0) && (bytes.len() >= 2) { // start of a 2 octet utf-8 sequence match from_utf8(&bytes[0..2]) { - Ok(s) => format!("{:>4}", s), - Err(_) => format!(" {:03o}", b), + Ok(s) => format!("{s:>4}"), + Err(_) => format!(" {b:03o}"), } } else if ((b & 0xf0) == 0xe0) && (bytes.len() >= 3) { // start of a 3 octet utf-8 sequence match from_utf8(&bytes[0..3]) { - Ok(s) => format!("{:>4}", s), - Err(_) => format!(" {:03o}", b), + Ok(s) => format!("{s:>4}"), + Err(_) => format!(" {b:03o}"), } } else if ((b & 0xf8) == 0xf0) && (bytes.len() >= 4) { // start of a 4 octet utf-8 sequence match from_utf8(&bytes[0..4]) { - Ok(s) => format!("{:>4}", s), - Err(_) => format!(" {:03o}", b), + Ok(s) => format!("{s:>4}"), + Err(_) => format!(" {b:03o}"), } } else { // invalid utf-8 - format!(" {:03o}", b) + format!(" {b:03o}") } } diff --git a/src/uu/od/src/prn_float.rs b/src/uu/od/src/prn_float.rs index a9bf1279e..be1463163 100644 --- a/src/uu/od/src/prn_float.rs +++ b/src/uu/od/src/prn_float.rs @@ -47,7 +47,7 @@ fn format_flo32(f: f32) -> String { if f.classify() == FpCategory::Subnormal { // subnormal numbers will be normal as f64, so will print with a wrong precision - format!("{:width$e}", f, width = width) // subnormal numbers + format!("{f:width$e}") // subnormal numbers } else { format_float(f64::from(f), width, precision) } @@ -60,12 +60,12 @@ fn format_flo64(f: f64) -> String { fn format_float(f: f64, width: usize, precision: usize) -> String { if !f.is_normal() { if f == -0.0 && f.is_sign_negative() { - return format!("{:>width$}", "-0", width = width); + return format!("{:>width$}", "-0"); } if f == 0.0 || !f.is_finite() { - return format!("{:width$}", f, width = width); + return format!("{f:width$}"); } - return format!("{:width$e}", f, width = width); // subnormal numbers + return format!("{f:width$e}"); // subnormal numbers } let mut l = f.abs().log10().floor() as i32; @@ -77,16 +77,11 @@ fn format_float(f: f64, width: usize, precision: usize) -> String { } if l >= 0 && l <= (precision as i32 - 1) { - format!( - "{:width$.dec$}", - f, - width = width, - dec = (precision - 1) - l as usize - ) + format!("{:width$.dec$}", f, dec = (precision - 1) - l as usize) } else if l == -1 { - format!("{:width$.dec$}", f, width = width, dec = precision) + format!("{f:width$.precision$}") } else { - format!("{:width$.dec$e}", f, width = width, dec = precision - 1) + format!("{:width$.dec$e}", f, dec = precision - 1) } } diff --git a/src/uu/paste/Cargo.toml b/src/uu/paste/Cargo.toml index a3625d2c5..4012f14ff 100644 --- a/src/uu/paste/Cargo.toml +++ b/src/uu/paste/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_paste" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "paste ~ (uutils) merge lines from inputs" @@ -16,7 +16,7 @@ path = "src/paste.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "paste" diff --git a/src/uu/pathchk/Cargo.toml b/src/uu/pathchk/Cargo.toml index 9c77eff09..f8a203a3f 100644 --- a/src/uu/pathchk/Cargo.toml +++ b/src/uu/pathchk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_pathchk" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "pathchk ~ (uutils) diagnose invalid or non-portable PATHNAME" @@ -17,7 +17,7 @@ path = "src/pathchk.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "pathchk" diff --git a/src/uu/pathchk/src/pathchk.rs b/src/uu/pathchk/src/pathchk.rs index 626596ab0..6dad9f79d 100644 --- a/src/uu/pathchk/src/pathchk.rs +++ b/src/uu/pathchk/src/pathchk.rs @@ -132,10 +132,7 @@ fn check_basic(path: &[String]) -> bool { if total_len > POSIX_PATH_MAX { writeln!( std::io::stderr(), - "limit {} exceeded by length {} of file name {}", - POSIX_PATH_MAX, - total_len, - joined_path + "limit {POSIX_PATH_MAX} exceeded by length {total_len} of file name {joined_path}" ); return false; } else if total_len == 0 { @@ -226,7 +223,7 @@ fn check_searchable(path: &str) -> bool { if e.kind() == ErrorKind::NotFound { true } else { - writeln!(std::io::stderr(), "{}", e); + writeln!(std::io::stderr(), "{e}"); false } } diff --git a/src/uu/pinky/Cargo.toml b/src/uu/pinky/Cargo.toml index 269316082..136ab48fc 100644 --- a/src/uu/pinky/Cargo.toml +++ b/src/uu/pinky/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_pinky" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "pinky ~ (uutils) display user information" @@ -16,7 +16,7 @@ path = "src/pinky.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["utmpx", "entries"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["utmpx", "entries"] } [[bin]] name = "pinky" diff --git a/src/uu/pinky/src/pinky.rs b/src/uu/pinky/src/pinky.rs index c4e68705e..8060565e4 100644 --- a/src/uu/pinky/src/pinky.rs +++ b/src/uu/pinky/src/pinky.rs @@ -241,11 +241,11 @@ fn idle_string(when: i64) -> String { // less than 1day let hours = duration / (60 * 60); let minutes = (duration % (60 * 60)) / 60; - format!("{:02}:{:02}", hours, minutes) + format!("{hours:02}:{minutes:02}") } else { // more than 1day let days = duration / (24 * 3600); - format!("{}d", days) + format!("{days}d") } }) } @@ -303,7 +303,7 @@ impl Pinky { None }; if let Some(fullname) = fullname { - print!(" {:<19.19}", fullname); + print!(" {fullname:<19.19}"); } else { print!(" {:19}", " ???"); } @@ -324,7 +324,7 @@ impl Pinky { let mut s = ut.host(); if self.include_where && !s.is_empty() { s = ut.canon_host()?; - print!(" {}", s); + print!(" {s}"); } println!(); @@ -363,15 +363,15 @@ impl Pinky { fn long_pinky(&self) { for u in &self.names { - print!("Login name: {:<28}In real life: ", u); + print!("Login name: {u:<28}In real life: "); if let Ok(pw) = Passwd::locate(u.as_str()) { let fullname = gecos_to_fullname(&pw).unwrap_or_default(); let user_dir = pw.user_dir.unwrap_or_default(); let user_shell = pw.user_shell.unwrap_or_default(); - println!(" {}", fullname); + println!(" {fullname}"); if self.include_home_and_shell { - print!("Directory: {:<29}", user_dir); - println!("Shell: {}", user_shell); + print!("Directory: {user_dir:<29}"); + println!("Shell: {user_shell}"); } if self.include_project { let mut p = PathBuf::from(&user_dir); diff --git a/src/uu/pr/Cargo.toml b/src/uu/pr/Cargo.toml index 2a6f12f3d..310ce07a2 100644 --- a/src/uu/pr/Cargo.toml +++ b/src/uu/pr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_pr" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "pr ~ (uutils) convert text files for printing" @@ -17,7 +17,7 @@ path = "src/pr.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } time = { version = "0.3", features = ["local-offset", "macros", "formatting"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries"] } quick-error = "2.0.1" itertools = "0.10.0" regex = "1.7" diff --git a/src/uu/pr/src/pr.rs b/src/uu/pr/src/pr.rs index b93b6f5b1..9f1b64483 100644 --- a/src/uu/pr/src/pr.rs +++ b/src/uu/pr/src/pr.rs @@ -305,8 +305,8 @@ pub fn uu_app() -> Command { .short('W') .long(options::PAGE_WIDTH) .help( - "set page width to PAGE_WIDTH (72) characters always, - truncate lines, except -J option is set, no interference + "set page width to PAGE_WIDTH (72) characters always, \ + truncate lines, except -J option is set, no interference \ with -S or -s", ) .value_name("width"), @@ -385,7 +385,7 @@ pub fn uu_app() -> Command { Arg::new(options::JOIN_LINES) .short('J') .help( - "merge full lines, turns off -W line truncation, no column + "merge full lines, turns off -W line truncation, no column \ alignment, --sep-string[=STRING] sets separators", ) .action(ArgAction::SetTrue), @@ -470,7 +470,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { fn recreate_arguments(args: &[String]) -> Vec { let column_page_option = Regex::new(r"^[-+]\d+.*").unwrap(); let num_regex = Regex::new(r"^[^-]\d*$").unwrap(); - //let a_file: Regex = Regex::new(r"^[^-+].*").unwrap(); let n_regex = Regex::new(r"^-n\s*$").unwrap(); let mut arguments = args.to_owned(); let num_option = args.iter().find_position(|x| n_regex.is_match(x.trim())); @@ -492,7 +491,7 @@ fn recreate_arguments(args: &[String]) -> Vec { fn print_error(matches: &ArgMatches, err: &PrError) { if !matches.get_flag(options::NO_FILE_WARNINGS) { - eprintln!("{}", err); + eprintln!("{err}"); } } @@ -506,7 +505,7 @@ fn parse_usize(matches: &ArgMatches, opt: &str) -> Option }; matches .get_one::(opt) - .map(|i| (i.to_string(), format!("-{}", opt))) + .map(|i| (i.to_string(), format!("-{opt}"))) .map(from_parse_error_to_pr_error) } @@ -669,8 +668,7 @@ fn build_options( if let Some(end_page) = end_page { if start_page > end_page { return Err(PrError::EncounteredErrors(format!( - "invalid --pages argument '{}:{}'", - start_page, end_page + "invalid --pages argument '{start_page}:{end_page}'" ))); } } @@ -1201,11 +1199,10 @@ fn get_formatted_line_number(opts: &OutputOptions, line_number: usize, index: us format!( "{:>width$}{}", &line_str[line_str.len() - width..], - separator, - width = width + separator ) } else { - format!("{:>width$}{}", line_str, separator, width = width) + format!("{line_str:>width$}{separator}") } } else { String::new() diff --git a/src/uu/printenv/Cargo.toml b/src/uu/printenv/Cargo.toml index 99f673cbf..b81c3906d 100644 --- a/src/uu/printenv/Cargo.toml +++ b/src/uu/printenv/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_printenv" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "printenv ~ (uutils) display value of environment VAR" @@ -16,7 +16,7 @@ path = "src/printenv.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "printenv" diff --git a/src/uu/printenv/src/printenv.rs b/src/uu/printenv/src/printenv.rs index 3e7a7c5f9..dd58f4ee1 100644 --- a/src/uu/printenv/src/printenv.rs +++ b/src/uu/printenv/src/printenv.rs @@ -35,7 +35,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if variables.is_empty() { for (env_var, value) in env::vars() { - print!("{}={}{}", env_var, value, separator); + print!("{env_var}={value}{separator}"); } return Ok(()); } @@ -48,7 +48,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { continue; } if let Ok(var) = env::var(env_var) { - print!("{}{}", var, separator); + print!("{var}{separator}"); } else { error_found = true; } diff --git a/src/uu/printf/Cargo.toml b/src/uu/printf/Cargo.toml index 3575e5d6a..548641b76 100644 --- a/src/uu/printf/Cargo.toml +++ b/src/uu/printf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_printf" -version = "0.0.16" +version = "0.0.17" authors = [ "Nathan Ross", "uutils developers", @@ -19,7 +19,7 @@ path = "src/printf.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["memo"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["memo"] } [[bin]] name = "printf" diff --git a/src/uu/ptx/Cargo.toml b/src/uu/ptx/Cargo.toml index 96de27526..d26c54d46 100644 --- a/src/uu/ptx/Cargo.toml +++ b/src/uu/ptx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_ptx" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "ptx ~ (uutils) display a permuted index of input" @@ -17,7 +17,7 @@ path = "src/ptx.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } regex = "1.7.0" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "ptx" diff --git a/src/uu/ptx/src/ptx.rs b/src/uu/ptx/src/ptx.rs index 965b4ba8e..3790c4e11 100644 --- a/src/uu/ptx/src/ptx.rs +++ b/src/uu/ptx/src/ptx.rs @@ -21,7 +21,6 @@ use uucore::display::Quotable; use uucore::error::{FromIo, UError, UResult}; use uucore::format_usage; -static NAME: &str = "ptx"; const USAGE: &str = "\ {} [OPTION]... [INPUT]... {} -G [OPTION]... [INPUT [OUTPUT]]"; @@ -171,7 +170,7 @@ impl WordFilter { .unwrap() .into_iter() .map(|c| if REGEX_CHARCLASS.contains(c) { - format!("\\{}", c) + format!("\\{c}") } else { c.to_string() }) @@ -221,14 +220,14 @@ impl Display for PtxError { Self::DumbFormat => { write!(f, "There is no dumb format with GNU extensions disabled") } - Self::NotImplemented(s) => write!(f, "{} not implemented yet", s), + Self::NotImplemented(s) => write!(f, "{s} not implemented yet"), Self::ParseError(e) => e.fmt(f), } } } fn get_config(matches: &clap::ArgMatches) -> UResult { - let mut config: Config = Default::default(); + let mut config = Config::default(); let err_msg = "parsing options failed"; if matches.get_flag(options::TRADITIONAL) { config.gnu_ext = false; @@ -554,8 +553,8 @@ fn get_output_chunks( fn tex_mapper(x: char) -> String { match x { '\\' => "\\backslash{}".to_owned(), - '$' | '%' | '#' | '&' | '_' => format!("\\{}", x), - '}' | '{' => format!("$\\{}$", x), + '$' | '%' | '#' | '&' | '_' => format!("\\{x}"), + '}' | '{' => format!("$\\{x}$"), _ => x.to_string(), } } @@ -697,7 +696,7 @@ fn write_traditional_output( return Err(PtxError::DumbFormat.into()); } }; - writeln!(writer, "{}", output_line).map_err_context(String::new)?; + writeln!(writer, "{output_line}").map_err_context(String::new)?; } Ok(()) } @@ -747,7 +746,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .about(ABOUT) .version(crate_version!()) .override_usage(format_usage(USAGE)) diff --git a/src/uu/pwd/Cargo.toml b/src/uu/pwd/Cargo.toml index 5c75a7056..1886ddeac 100644 --- a/src/uu/pwd/Cargo.toml +++ b/src/uu/pwd/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_pwd" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "pwd ~ (uutils) display current working directory" @@ -16,7 +16,7 @@ path = "src/pwd.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "pwd" diff --git a/src/uu/readlink/Cargo.toml b/src/uu/readlink/Cargo.toml index e84dc0a7c..a7a28b1d6 100644 --- a/src/uu/readlink/Cargo.toml +++ b/src/uu/readlink/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_readlink" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "readlink ~ (uutils) display resolved path of PATHNAME" @@ -16,7 +16,7 @@ path = "src/readlink.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "readlink" diff --git a/src/uu/readlink/src/readlink.rs b/src/uu/readlink/src/readlink.rs index a0be0d270..8afb184be 100644 --- a/src/uu/readlink/src/readlink.rs +++ b/src/uu/readlink/src/readlink.rs @@ -176,11 +176,11 @@ pub fn uu_app() -> Command { fn show(path: &Path, no_trailing_delimiter: bool, use_zero: bool) -> std::io::Result<()> { let path = path.to_str().unwrap(); if no_trailing_delimiter { - print!("{}", path); + print!("{path}"); } else if use_zero { - print!("{}\0", path); + print!("{path}\0"); } else { - println!("{}", path); + println!("{path}"); } stdout().flush() } diff --git a/src/uu/realpath/Cargo.toml b/src/uu/realpath/Cargo.toml index fdc410b72..a077778e4 100644 --- a/src/uu/realpath/Cargo.toml +++ b/src/uu/realpath/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_realpath" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "realpath ~ (uutils) display resolved absolute path of PATHNAME" @@ -16,7 +16,7 @@ path = "src/realpath.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "realpath" diff --git a/src/uu/relpath/Cargo.toml b/src/uu/relpath/Cargo.toml index 0af624c4f..c37e98d86 100644 --- a/src/uu/relpath/Cargo.toml +++ b/src/uu/relpath/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_relpath" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "relpath ~ (uutils) display relative path of PATHNAME_TO from PATHNAME_FROM" @@ -16,7 +16,7 @@ path = "src/relpath.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "relpath" diff --git a/src/uu/rm/Cargo.toml b/src/uu/rm/Cargo.toml index 3cd49b11b..9f169b1c0 100644 --- a/src/uu/rm/Cargo.toml +++ b/src/uu/rm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_rm" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "rm ~ (uutils) remove PATHNAME" @@ -18,7 +18,7 @@ path = "src/rm.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } walkdir = "2.2" remove_dir_all = "0.7.0" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [target.'cfg(unix)'.dependencies] libc = "0.2.137" diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 08d7f0ac5..39b177bcf 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -117,7 +117,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { val => { return Err(USimpleError::new( 1, - format!("Invalid argument to interactive ({})", val), + format!("Invalid argument to interactive ({val})"), )) } } diff --git a/src/uu/rmdir/Cargo.toml b/src/uu/rmdir/Cargo.toml index 5616742a5..e804f7fa5 100644 --- a/src/uu/rmdir/Cargo.toml +++ b/src/uu/rmdir/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_rmdir" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "rmdir ~ (uutils) remove empty DIRECTORY" @@ -16,7 +16,7 @@ path = "src/rmdir.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } libc = "0.2.137" [[bin]] diff --git a/src/uu/runcon/Cargo.toml b/src/uu/runcon/Cargo.toml index fe92ca1f1..74fcdf2cf 100644 --- a/src/uu/runcon/Cargo.toml +++ b/src/uu/runcon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_runcon" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "runcon ~ (uutils) run command with specified security context" diff --git a/src/uu/runcon/src/errors.rs b/src/uu/runcon/src/errors.rs index 18f06deb9..b96cc8743 100644 --- a/src/uu/runcon/src/errors.rs +++ b/src/uu/runcon/src/errors.rs @@ -77,11 +77,11 @@ pub(crate) fn write_full_error(writer: &mut W, err: &dyn std::error::Error) - where W: Write, { - write!(writer, "{}", err)?; + write!(writer, "{err}")?; let mut err = err; while let Some(source) = err.source() { err = source; - write!(writer, ": {}", err)?; + write!(writer, ": {err}")?; } write!(writer, ".")?; Ok(()) diff --git a/src/uu/runcon/src/runcon.rs b/src/uu/runcon/src/runcon.rs index 101cd3bee..365038907 100644 --- a/src/uu/runcon/src/runcon.rs +++ b/src/uu/runcon/src/runcon.rs @@ -52,7 +52,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { match r.kind() { clap::error::ErrorKind::DisplayHelp | clap::error::ErrorKind::DisplayVersion => { - println!("{}", r); + println!("{r}"); return Ok(()); } _ => {} @@ -60,7 +60,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } return Err(UUsageError::new( error_exit_status::ANOTHER_ERROR, - format!("{}", r), + format!("{r}"), )); } }; @@ -264,7 +264,7 @@ fn print_current_context() -> Result<()> { if let Some(context) = context { let context = context.as_ref().to_str()?; - println!("{}", context); + println!("{context}"); } else { println!(); } diff --git a/src/uu/seq/Cargo.toml b/src/uu/seq/Cargo.toml index cd9b1a7ce..07f88fb00 100644 --- a/src/uu/seq/Cargo.toml +++ b/src/uu/seq/Cargo.toml @@ -1,7 +1,7 @@ # spell-checker:ignore bigdecimal [package] name = "uu_seq" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "seq ~ (uutils) display a sequence of numbers" @@ -20,7 +20,7 @@ bigdecimal = "0.3" clap = { version = "4.0", features = ["wrap_help", "cargo"] } num-bigint = "0.4.0" num-traits = "0.2.15" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["memo"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["memo"] } [[bin]] name = "seq" diff --git a/src/uu/seq/src/seq.rs b/src/uu/seq/src/seq.rs index 1109bd093..40bac8449 100644 --- a/src/uu/seq/src/seq.rs +++ b/src/uu/seq/src/seq.rs @@ -210,21 +210,11 @@ fn write_value_float( ) -> std::io::Result<()> { let value_as_str = if *value == ExtendedBigDecimal::Infinity || *value == ExtendedBigDecimal::MinusInfinity { - format!( - "{value:>width$.precision$}", - value = value, - width = width, - precision = precision, - ) + format!("{value:>width$.precision$}") } else { - format!( - "{value:>0width$.precision$}", - value = value, - width = width, - precision = precision, - ) + format!("{value:>0width$.precision$}") }; - write!(writer, "{}", value_as_str) + write!(writer, "{value_as_str}") } /// Write a big int formatted according to the given parameters. @@ -237,16 +227,16 @@ fn write_value_int( ) -> std::io::Result<()> { let value_as_str = if pad { if *value == ExtendedBigInt::MinusZero && is_first_iteration { - format!("-{value:>0width$}", value = value, width = width - 1,) + format!("-{value:>0width$}", width = width - 1) } else { - format!("{value:>0width$}", value = value, width = width,) + format!("{value:>0width$}") } } else if *value == ExtendedBigInt::MinusZero && is_first_iteration { - format!("-{}", value) + format!("-{value}") } else { - format!("{}", value) + format!("{value}") }; - write!(writer, "{}", value_as_str) + write!(writer, "{value_as_str}") } // TODO `print_seq()` and `print_seq_integers()` are nearly identical, @@ -270,7 +260,7 @@ fn print_seq( let mut is_first_iteration = true; while !done_printing(&value, &increment, &last) { if !is_first_iteration { - write!(stdout, "{}", separator)?; + write!(stdout, "{separator}")?; } // If there was an argument `-f FORMAT`, then use that format // template instead of the default formatting strategy. @@ -286,7 +276,7 @@ fn print_seq( // strings. match format { Some(f) => { - let s = format!("{}", value); + let s = format!("{value}"); if let Err(x) = printf(f, &[s]) { show!(x); exit(1); @@ -305,7 +295,7 @@ fn print_seq( is_first_iteration = false; } if !is_first_iteration { - write!(stdout, "{}", terminator)?; + write!(stdout, "{terminator}")?; } stdout.flush()?; Ok(()) @@ -340,7 +330,7 @@ fn print_seq_integers( let mut is_first_iteration = true; while !done_printing(&value, &increment, &last) { if !is_first_iteration { - write!(stdout, "{}", separator)?; + write!(stdout, "{separator}")?; } // If there was an argument `-f FORMAT`, then use that format // template instead of the default formatting strategy. @@ -351,7 +341,7 @@ fn print_seq_integers( // TODO See similar comment about formatting in `print_seq()`. match format { Some(f) => { - let s = format!("{}", value); + let s = format!("{value}"); if let Err(x) = printf(f, &[s]) { show!(x); exit(1); @@ -365,7 +355,7 @@ fn print_seq_integers( } if !is_first_iteration { - write!(stdout, "{}", terminator)?; + write!(stdout, "{terminator}")?; } Ok(()) } diff --git a/src/uu/shred/Cargo.toml b/src/uu/shred/Cargo.toml index c4334f21f..957abf766 100644 --- a/src/uu/shred/Cargo.toml +++ b/src/uu/shred/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_shred" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "shred ~ (uutils) hide former FILE contents with repeated overwrites" @@ -17,7 +17,7 @@ path = "src/shred.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } rand = "0.8" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "shred" diff --git a/src/uu/shred/src/shred.rs b/src/uu/shred/src/shred.rs index de1af9e30..55a36bfe2 100644 --- a/src/uu/shred/src/shred.rs +++ b/src/uu/shred/src/shred.rs @@ -16,7 +16,6 @@ use std::fs; use std::fs::{File, OpenOptions}; use std::io; use std::io::prelude::*; -use std::io::SeekFrom; use std::path::{Path, PathBuf}; use uucore::display::Quotable; use uucore::error::{FromIo, UResult, USimpleError, UUsageError}; @@ -424,7 +423,7 @@ fn pass_name(pass_type: PassType) -> String { let mut s: String = String::new(); while s.len() < 6 { for b in bytes { - let readable: String = format!("{:x}", b); + let readable: String = format!("{b:x}"); s.push_str(&readable); } } @@ -560,7 +559,7 @@ fn do_pass<'a>( generator_type: PassType<'a>, given_file_size: Option, ) -> Result<(), io::Error> { - file.seek(SeekFrom::Start(0))?; + file.rewind()?; // Use the given size or the whole file if not specified let size: u64 = given_file_size.unwrap_or(get_file_size(path)?); diff --git a/src/uu/shuf/Cargo.toml b/src/uu/shuf/Cargo.toml index 8efa0023f..98159b8c3 100644 --- a/src/uu/shuf/Cargo.toml +++ b/src/uu/shuf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_shuf" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "shuf ~ (uutils) display random permutations of input lines" @@ -19,7 +19,7 @@ clap = { version = "4.0", features = ["wrap_help", "cargo"] } memchr = "2.5.0" rand = "0.8" rand_core = "0.6" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "shuf" diff --git a/src/uu/shuf/src/rand_read_adapter.rs b/src/uu/shuf/src/rand_read_adapter.rs index fd8998c10..9cf0ee8a4 100644 --- a/src/uu/shuf/src/rand_read_adapter.rs +++ b/src/uu/shuf/src/rand_read_adapter.rs @@ -54,10 +54,7 @@ impl RngCore for ReadRng { fn fill_bytes(&mut self, dest: &mut [u8]) { self.try_fill_bytes(dest).unwrap_or_else(|err| { - panic!( - "reading random bytes from Read implementation failed; error: {}", - err - ); + panic!("reading random bytes from Read implementation failed; error: {err}"); }); } diff --git a/src/uu/shuf/src/shuf.rs b/src/uu/shuf/src/shuf.rs index f78f8c425..d0022f5f5 100644 --- a/src/uu/shuf/src/shuf.rs +++ b/src/uu/shuf/src/shuf.rs @@ -25,7 +25,6 @@ enum Mode { InputRange((usize, usize)), } -static NAME: &str = "shuf"; static USAGE: &str = "\ {} [OPTION]... [FILE] {} -e [OPTION]... [ARG]... @@ -110,7 +109,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { shuf_bytes(&mut evec, options)?; } Mode::InputRange((b, e)) => { - let rvec = (b..e).map(|x| format!("{}", x)).collect::>(); + let rvec = (b..e).map(|x| format!("{x}")).collect::>(); let mut rvec = rvec.iter().map(String::as_bytes).collect::>(); shuf_bytes(&mut rvec, options)?; } @@ -127,7 +126,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .about(ABOUT) .version(crate_version!()) .override_usage(format_usage(USAGE)) diff --git a/src/uu/sleep/Cargo.toml b/src/uu/sleep/Cargo.toml index dc0152fd5..8c21c895e 100644 --- a/src/uu/sleep/Cargo.toml +++ b/src/uu/sleep/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_sleep" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "sleep ~ (uutils) pause for DURATION" @@ -16,7 +16,7 @@ path = "src/sleep.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "sleep" diff --git a/src/uu/sleep/src/sleep.rs b/src/uu/sleep/src/sleep.rs index a39e9ce6f..d34cbe942 100644 --- a/src/uu/sleep/src/sleep.rs +++ b/src/uu/sleep/src/sleep.rs @@ -9,8 +9,8 @@ use std::thread; use std::time::Duration; use uucore::{ - error::{UResult, UUsageError}, - format_usage, + error::{UResult, USimpleError, UUsageError}, + format_usage, show, }; use clap::{crate_version, Arg, ArgAction, Command}; @@ -33,12 +33,21 @@ mod options { pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; - if let Some(values) = matches.get_many::(options::NUMBER) { - let numbers = values.map(|s| s.as_str()).collect::>(); - return sleep(&numbers); - } + let numbers = matches + .get_many::(options::NUMBER) + .ok_or_else(|| { + USimpleError::new( + 1, + format!( + "missing operand\nTry '{} --help' for more information.", + uucore::execution_phrase() + ), + ) + })? + .map(|s| s.as_str()) + .collect::>(); - Ok(()) + return sleep(&numbers); } pub fn uu_app() -> Command { @@ -52,20 +61,24 @@ pub fn uu_app() -> Command { Arg::new(options::NUMBER) .help("pause for NUMBER seconds") .value_name(options::NUMBER) - .action(ArgAction::Append) - .required(true), + .action(ArgAction::Append), ) } fn sleep(args: &[&str]) -> UResult<()> { - let sleep_dur = - args.iter().try_fold( - Duration::new(0, 0), - |result, arg| match uucore::parse_time::from_str(&arg[..]) { - Ok(m) => Ok(m.saturating_add(result)), - Err(f) => Err(UUsageError::new(1, f)), - }, - )?; + let mut arg_error = false; + let intervals = args.iter().map(|s| match uucore::parse_time::from_str(s) { + Ok(result) => result, + Err(err) => { + arg_error = true; + show!(USimpleError::new(1, err)); + Duration::new(0, 0) + } + }); + let sleep_dur = intervals.fold(Duration::new(0, 0), |acc, n| acc + n); + if arg_error { + return Err(UUsageError::new(1, "")); + }; thread::sleep(sleep_dur); Ok(()) } diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index 2dcf8b2c8..d12dd57cf 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_sort" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "sort ~ (uutils) sort input lines" @@ -27,7 +27,7 @@ rand = "0.8" rayon = "1.5" tempfile = "3" unicode-width = "0.1.8" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "sort" diff --git a/src/uu/sort/src/ext_sort.rs b/src/uu/sort/src/ext_sort.rs index fbb9c16d7..45ddc7304 100644 --- a/src/uu/sort/src/ext_sort.rs +++ b/src/uu/sort/src/ext_sort.rs @@ -278,7 +278,7 @@ fn write( tmp_file.finished_writing() } -fn write_lines<'a, T: Write>(lines: &[Line<'a>], writer: &mut T, separator: u8) { +fn write_lines(lines: &[Line], writer: &mut T, separator: u8) { for s in lines { writer.write_all(s.line.as_bytes()).unwrap(); writer.write_all(&[separator]).unwrap(); diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index dc5cfd91e..a681026f6 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -46,7 +46,7 @@ use unicode_width::UnicodeWidthStr; use uucore::display::Quotable; use uucore::error::{set_exit_code, strip_errno, UError, UResult, USimpleError, UUsageError}; use uucore::format_usage; -use uucore::parse_size::{parse_size, ParseSizeError}; +use uucore::parse_size::{ParseSizeError, Parser}; use uucore::version_cmp::version_cmp; use crate::tmp_dir::TmpDirWrapper; @@ -220,13 +220,13 @@ impl Display for SortError { write!(f, "failed to open temporary file: {}", strip_errno(error)) } Self::CompressProgExecutionFailed { code } => { - write!(f, "couldn't execute compress program: errno {}", code) + write!(f, "couldn't execute compress program: errno {code}") } Self::CompressProgTerminatedAbnormally { prog } => { write!(f, "{} terminated abnormally", prog.quote()) } Self::TmpDirCreationFailed => write!(f, "could not create temporary directory"), - Self::Uft8Error { error } => write!(f, "{}", error), + Self::Uft8Error { error } => write!(f, "{error}"), } } } @@ -342,30 +342,17 @@ impl GlobalSettings { fn parse_byte_count(input: &str) -> Result { // GNU sort (8.32) valid: 1b, k, K, m, M, g, G, t, T, P, E, Z, Y // GNU sort (8.32) invalid: b, B, 1B, p, e, z, y - const ALLOW_LIST: &[char] = &[ - 'b', 'k', 'K', 'm', 'M', 'g', 'G', 't', 'T', 'P', 'E', 'Z', 'Y', - ]; - let mut size_string = input.trim().to_string(); + let size = Parser::default() + .with_allow_list(&[ + "b", "k", "K", "m", "M", "g", "G", "t", "T", "P", "E", "Z", "Y", + ]) + .with_default_unit("K") + .with_b_byte_count(true) + .parse(input.trim())?; - if size_string.ends_with(|c: char| ALLOW_LIST.contains(&c) || c.is_ascii_digit()) { - // b 1, K 1024 (default) - if size_string.ends_with(|c: char| c.is_ascii_digit()) { - size_string.push('K'); - } else if size_string.ends_with('b') { - size_string.pop(); - } - let size = parse_size(&size_string)?; - usize::try_from(size).map_err(|_| { - ParseSizeError::SizeTooBig(format!( - "Buffer size {} does not fit in address space", - size - )) - }) - } else if size_string.starts_with(|c: char| c.is_ascii_digit()) { - Err(ParseSizeError::InvalidSuffix("invalid suffix".to_string())) - } else { - Err(ParseSizeError::ParseFailure("parse failure".to_string())) - } + usize::try_from(size).map_err(|_| { + ParseSizeError::SizeTooBig(format!("Buffer size {size} does not fit in address space")) + }) } /// Precompute some data needed for sorting. @@ -573,7 +560,7 @@ impl<'a> Line<'a> { // optimizations here. let line = self.line.replace('\t', ">"); - writeln!(writer, "{}", line)?; + writeln!(writer, "{line}")?; let mut fields = vec![]; tokenize(self.line, settings.separator, &mut fields); @@ -686,7 +673,7 @@ impl<'a> Line<'a> { || settings .selectors .last() - .map_or(true, |selector| selector != &Default::default())) + .map_or(true, |selector| selector != &FieldSelector::default())) { // A last resort comparator is in use, underline the whole line. if self.line.is_empty() { @@ -876,7 +863,7 @@ impl FieldSelector { 'R' => key_settings.set_sort_mode(SortMode::Random)?, 'r' => key_settings.reverse = true, 'V' => key_settings.set_sort_mode(SortMode::Version)?, - c => return Err(format!("invalid option: '{}'", c)), + c => return Err(format!("invalid option: '{c}'")), } } Ok(ignore_blanks) @@ -952,7 +939,7 @@ impl FieldSelector { /// Look up the range in the line that corresponds to this selector. /// If needs_fields returned false, tokens must be None. - fn get_range<'a>(&self, line: &'a str, tokens: Option<&[Field]>) -> Range { + fn get_range(&self, line: &str, tokens: Option<&[Field]>) -> Range { enum Resolution { // The start index of the resolved character, inclusive StartOfChar(usize), @@ -1059,7 +1046,7 @@ fn make_sort_mode_arg(mode: &'static str, short: char, help: &'static str) -> Ar #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args.collect_ignore(); - let mut settings: GlobalSettings = Default::default(); + let mut settings = GlobalSettings::default(); let matches = match uu_app().try_get_matches_from(args) { Ok(t) => t, @@ -1771,7 +1758,7 @@ fn get_rand_string() -> [u8; 16] { } fn get_hash(t: &T) -> u64 { - let mut s: FnvHasher = Default::default(); + let mut s = FnvHasher::default(); t.hash(&mut s); s.finish() } diff --git a/src/uu/sort/src/tmp_dir.rs b/src/uu/sort/src/tmp_dir.rs index bf5ce9fb3..ff14442b5 100644 --- a/src/uu/sort/src/tmp_dir.rs +++ b/src/uu/sort/src/tmp_dir.rs @@ -31,7 +31,7 @@ impl TmpDirWrapper { parent_path: path, size: 0, temp_dir: None, - lock: Default::default(), + lock: Arc::default(), } } @@ -56,7 +56,7 @@ impl TmpDirWrapper { } std::process::exit(2) }) - .map_err(|e| USimpleError::new(2, format!("failed to set up signal handler: {}", e))) + .map_err(|e| USimpleError::new(2, format!("failed to set up signal handler: {e}"))) } pub fn next_file(&mut self) -> UResult<(File, PathBuf)> { diff --git a/src/uu/split/Cargo.toml b/src/uu/split/Cargo.toml index 88c88554f..9d5a9e3ba 100644 --- a/src/uu/split/Cargo.toml +++ b/src/uu/split/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_split" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "split ~ (uutils) split input into output files" @@ -17,7 +17,7 @@ path = "src/split.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } memchr = "2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "split" diff --git a/src/uu/split/src/number.rs b/src/uu/split/src/number.rs index 00a536af5..778e24f7c 100644 --- a/src/uu/split/src/number.rs +++ b/src/uu/split/src/number.rs @@ -245,7 +245,7 @@ impl Display for FixedWidthNumber { .iter() .map(|d| map_digit(self.radix, *d)) .collect(); - write!(f, "{}", digits) + write!(f, "{digits}") } } diff --git a/src/uu/split/src/platform/unix.rs b/src/uu/split/src/platform/unix.rs index 46f89eff5..fedd66dc8 100644 --- a/src/uu/split/src/platform/unix.rs +++ b/src/uu/split/src/platform/unix.rs @@ -121,7 +121,7 @@ pub fn instantiate_current_writer( .map_err(|_| { Error::new( ErrorKind::Other, - format!("unable to open '{}'; aborting", filename), + format!("unable to open '{filename}'; aborting"), ) })?, ) as Box)), diff --git a/src/uu/split/src/platform/windows.rs b/src/uu/split/src/platform/windows.rs index 4b0dfbdfc..a2711fd3a 100644 --- a/src/uu/split/src/platform/windows.rs +++ b/src/uu/split/src/platform/windows.rs @@ -21,7 +21,7 @@ pub fn instantiate_current_writer( .map_err(|_| { Error::new( ErrorKind::Other, - format!("'{}' would overwrite input; aborting", filename), + format!("'{filename}' would overwrite input; aborting"), ) })?, ) as Box)) diff --git a/src/uu/split/src/split.rs b/src/uu/split/src/split.rs index 36200b2bd..d737c8513 100644 --- a/src/uu/split/src/split.rs +++ b/src/uu/split/src/split.rs @@ -58,8 +58,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; match Settings::from(&matches) { Ok(settings) => split(&settings), - Err(e) if e.requires_usage() => Err(UUsageError::new(1, format!("{}", e))), - Err(e) => Err(USimpleError::new(1, format!("{}", e))), + Err(e) if e.requires_usage() => Err(UUsageError::new(1, format!("{e}"))), + Err(e) => Err(USimpleError::new(1, format!("{e}"))), } } @@ -343,13 +343,13 @@ enum StrategyError { impl fmt::Display for StrategyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Self::Lines(e) => write!(f, "invalid number of lines: {}", e), - Self::Bytes(e) => write!(f, "invalid number of bytes: {}", e), + Self::Lines(e) => write!(f, "invalid number of lines: {e}"), + Self::Bytes(e) => write!(f, "invalid number of bytes: {e}"), Self::NumberType(NumberTypeError::NumberOfChunks(s)) => { - write!(f, "invalid number of chunks: {}", s) + write!(f, "invalid number of chunks: {s}") } Self::NumberType(NumberTypeError::ChunkNumber(s)) => { - write!(f, "invalid chunk number: {}", s) + write!(f, "invalid chunk number: {s}") } Self::MultipleWays => write!(f, "cannot split in more than one way"), } @@ -478,7 +478,7 @@ impl fmt::Display for SettingsError { match self { Self::Strategy(e) => e.fmt(f), Self::SuffixNotParsable(s) => write!(f, "invalid suffix length: {}", s.quote()), - Self::SuffixTooSmall(i) => write!(f, "the suffix length needs to be at least {}", i), + Self::SuffixTooSmall(i) => write!(f, "the suffix length needs to be at least {i}"), Self::SuffixContainsSeparator(s) => write!( f, "invalid suffix {}, contains directory separator", @@ -487,8 +487,7 @@ impl fmt::Display for SettingsError { #[cfg(windows)] Self::NotSupported => write!( f, - "{} is currently not supported in this platform", - OPT_FILTER + "{OPT_FILTER} is currently not supported in this platform" ), } } @@ -547,7 +546,7 @@ impl Settings { if platform::paths_refer_to_same_file(&self.input, filename) { return Err(io::Error::new( ErrorKind::Other, - format!("'{}' would overwrite input; aborting", filename), + format!("'{filename}' would overwrite input; aborting"), )); } @@ -1305,7 +1304,7 @@ fn split(settings: &Settings) -> UResult<()> { // allowable filenames, we use `ErrorKind::Other` to // indicate that. A special error message needs to be // printed in that case. - ErrorKind::Other => Err(USimpleError::new(1, format!("{}", e))), + ErrorKind::Other => Err(USimpleError::new(1, format!("{e}"))), ErrorKind::BrokenPipe => Ok(()), _ => Err(uio_error!(e, "input/output error")), }, @@ -1324,7 +1323,7 @@ fn split(settings: &Settings) -> UResult<()> { // allowable filenames, we use `ErrorKind::Other` to // indicate that. A special error message needs to be // printed in that case. - ErrorKind::Other => Err(USimpleError::new(1, format!("{}", e))), + ErrorKind::Other => Err(USimpleError::new(1, format!("{e}"))), ErrorKind::BrokenPipe => Ok(()), _ => Err(uio_error!(e, "input/output error")), }, @@ -1343,7 +1342,7 @@ fn split(settings: &Settings) -> UResult<()> { // allowable filenames, we use `ErrorKind::Other` to // indicate that. A special error message needs to be // printed in that case. - ErrorKind::Other => Err(USimpleError::new(1, format!("{}", e))), + ErrorKind::Other => Err(USimpleError::new(1, format!("{e}"))), ErrorKind::BrokenPipe => Ok(()), _ => Err(uio_error!(e, "input/output error")), }, diff --git a/src/uu/stat/Cargo.toml b/src/uu/stat/Cargo.toml index e6f7ff1c5..2f32abc51 100644 --- a/src/uu/stat/Cargo.toml +++ b/src/uu/stat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_stat" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "stat ~ (uutils) display FILE status" @@ -16,7 +16,7 @@ path = "src/stat.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "libc", "fs", "fsext"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "libc", "fs", "fsext"] } [[bin]] name = "stat" diff --git a/src/uu/stat/src/stat.rs b/src/uu/stat/src/stat.rs index 8fd9fecfa..119c9c7fb 100644 --- a/src/uu/stat/src/stat.rs +++ b/src/uu/stat/src/stat.rs @@ -535,7 +535,7 @@ impl Stater { for t in tokens.iter() { match *t { - Token::Char(c) => print!("{}", c), + Token::Char(c) => print!("{c}"), Token::Directive { flag, width, @@ -588,7 +588,7 @@ impl Stater { let dst = match fs::read_link(&file) { Ok(path) => path, Err(e) => { - println!("{}", e); + println!("{e}"); return 1; } }; @@ -668,7 +668,7 @@ impl Stater { for t in tokens.iter() { match *t { - Token::Char(c) => print!("{}", c), + Token::Char(c) => print!("{c}"), Token::Directive { flag, width, diff --git a/src/uu/stdbuf/Cargo.toml b/src/uu/stdbuf/Cargo.toml index 89047e446..aad0d29e1 100644 --- a/src/uu/stdbuf/Cargo.toml +++ b/src/uu/stdbuf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_stdbuf" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "stdbuf ~ (uutils) run COMMAND with modified standard stream buffering" @@ -17,10 +17,10 @@ path = "src/stdbuf.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } tempfile = "3" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [build-dependencies] -libstdbuf = { version="0.0.16", package="uu_stdbuf_libstdbuf", path="src/libstdbuf" } +libstdbuf = { version="0.0.17", package="uu_stdbuf_libstdbuf", path="src/libstdbuf" } [[bin]] name = "stdbuf" diff --git a/src/uu/stdbuf/src/libstdbuf/Cargo.toml b/src/uu/stdbuf/src/libstdbuf/Cargo.toml index ff446d7ea..c40f3aa86 100644 --- a/src/uu/stdbuf/src/libstdbuf/Cargo.toml +++ b/src/uu/stdbuf/src/libstdbuf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_stdbuf_libstdbuf" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "stdbuf/libstdbuf ~ (uutils); dynamic library required for stdbuf" @@ -19,7 +19,7 @@ crate-type = ["cdylib", "rlib"] # XXX: note: the rlib is just to prevent Cargo f [dependencies] cpp = "0.5" libc = "0.2" -uucore = { version=">=0.0.16", package="uucore", path="../../../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../../../uucore" } [build-dependencies] cpp_build = "0.5" diff --git a/src/uu/stdbuf/src/stdbuf.rs b/src/uu/stdbuf/src/stdbuf.rs index 97e06ad19..2bfb6f908 100644 --- a/src/uu/stdbuf/src/stdbuf.rs +++ b/src/uu/stdbuf/src/stdbuf.rs @@ -120,8 +120,7 @@ fn check_option(matches: &ArgMatches, name: &str) -> Result nix::Result<()> { target_os = "netbsd", target_os = "openbsd" ))] - print!("speed {} baud; ", speed); + print!("speed {speed} baud; "); // Other platforms need to use the baud rate enum, so printing the right value // becomes slightly more complicated. @@ -210,7 +209,7 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> { )))] for (text, baud_rate) in BAUD_RATES { if *baud_rate == speed { - print!("speed {} baud; ", text); + print!("speed {text} baud; "); break; } } @@ -227,7 +226,7 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> { // so we get the underlying libc::termios struct to get that information. let libc_termios: nix::libc::termios = termios.clone().into(); let line = libc_termios.c_line; - print!("line = {};", line); + print!("line = {line};"); } println!(); @@ -259,14 +258,14 @@ fn print_flags(termios: &Termios, opts: &Options, flags: &[Flag< let val = flag.is_in(termios, group); if group.is_some() { if val && (!sane || opts.all) { - print!("{} ", name); + print!("{name} "); printed = true; } } else if opts.all || val != sane { if !val { print!("-"); } - print!("{} ", name); + print!("{name} "); printed = true; } } @@ -324,7 +323,6 @@ fn apply_flag( pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .override_usage(format_usage(USAGE)) .about(SUMMARY) diff --git a/src/uu/sum/Cargo.toml b/src/uu/sum/Cargo.toml index 7087d0023..bcc53d11c 100644 --- a/src/uu/sum/Cargo.toml +++ b/src/uu/sum/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_sum" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "sum ~ (uutils) display checksum and block counts for input" @@ -16,7 +16,7 @@ path = "src/sum.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "sum" diff --git a/src/uu/sum/src/sum.rs b/src/uu/sum/src/sum.rs index 11fef32c7..1134f2444 100644 --- a/src/uu/sum/src/sum.rs +++ b/src/uu/sum/src/sum.rs @@ -15,10 +15,9 @@ use uucore::display::Quotable; use uucore::error::{FromIo, UResult, USimpleError}; use uucore::{format_usage, show}; -static NAME: &str = "sum"; static USAGE: &str = "{} [OPTION]... [FILE]..."; -static ABOUT: &str = r#"Checksum and count the blocks in a file. - With no FILE, or when FILE is -, read standard input."#; +static ABOUT: &str = "Checksum and count the blocks in a file.\n\n\ + With no FILE, or when FILE is -, read standard input."; // This can be replaced with usize::div_ceil once it is stabilized. // This implementation approach is optimized for when `b` is a constant, @@ -117,11 +116,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let sysv = matches.get_flag(options::SYSTEM_V_COMPATIBLE); - let print_names = if sysv { - files.len() > 1 || files[0] != "-" - } else { - files.len() > 1 - }; + let print_names = files.len() > 1 || files[0] != "-"; + let width = if sysv { 1 } else { 5 }; for file in &files { let reader = match open(file) { @@ -138,9 +134,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; if print_names { - println!("{} {} {}", sum, blocks, file); + println!("{sum:0width$} {blocks:width$} {file}"); } else { - println!("{} {}", sum, blocks); + println!("{sum:0width$} {blocks:width$}"); } } Ok(()) @@ -148,7 +144,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .override_usage(format_usage(USAGE)) .about(ABOUT) diff --git a/src/uu/sync/Cargo.toml b/src/uu/sync/Cargo.toml index 3558868a5..f357cdc62 100644 --- a/src/uu/sync/Cargo.toml +++ b/src/uu/sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_sync" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "sync ~ (uutils) synchronize cache writes to storage" @@ -17,7 +17,7 @@ path = "src/sync.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["wide"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["wide"] } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] nix = "0.25" diff --git a/src/uu/tac/Cargo.toml b/src/uu/tac/Cargo.toml index bd00ffe5e..31a177e4a 100644 --- a/src/uu/tac/Cargo.toml +++ b/src/uu/tac/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "uu_tac" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "tac ~ (uutils) concatenate and display input lines in reverse order" @@ -21,7 +21,7 @@ memchr = "2" memmap2 = "0.5" regex = "1" clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "tac" diff --git a/src/uu/tac/src/error.rs b/src/uu/tac/src/error.rs index 52c668516..43b03b970 100644 --- a/src/uu/tac/src/error.rs +++ b/src/uu/tac/src/error.rs @@ -44,7 +44,7 @@ impl Error for TacError {} impl Display for TacError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::InvalidRegex(e) => write!(f, "invalid regular expression: {}", e), + Self::InvalidRegex(e) => write!(f, "invalid regular expression: {e}"), Self::InvalidArgument(s) => { write!(f, "{}: read error: Invalid argument", s.maybe_quote()) } @@ -53,8 +53,8 @@ impl Display for TacError { "failed to open {} for reading: No such file or directory", s.quote() ), - Self::ReadError(s, e) => write!(f, "failed to read from {}: {}", s, e), - Self::WriteError(e) => write!(f, "failed to write to stdout: {}", e), + Self::ReadError(s, e) => write!(f, "failed to read from {s}: {e}"), + Self::WriteError(e) => write!(f, "failed to write to stdout: {e}"), } } } diff --git a/src/uu/tac/src/tac.rs b/src/uu/tac/src/tac.rs index 7a448ca3d..b0d79e6da 100644 --- a/src/uu/tac/src/tac.rs +++ b/src/uu/tac/src/tac.rs @@ -23,7 +23,6 @@ use uucore::{format_usage, show}; use crate::error::TacError; -static NAME: &str = "tac"; static USAGE: &str = "{} [OPTION]... [FILE]..."; static ABOUT: &str = "Write each file to standard output, last line first."; @@ -62,7 +61,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .override_usage(format_usage(USAGE)) .about(ABOUT) diff --git a/src/uu/tail/Cargo.toml b/src/uu/tail/Cargo.toml index 3f7b00436..9ad6d8609 100644 --- a/src/uu/tail/Cargo.toml +++ b/src/uu/tail/Cargo.toml @@ -1,7 +1,7 @@ # spell-checker:ignore (libs) kqueue [package] name = "uu_tail" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "tail ~ (uutils) display the last lines of input" @@ -20,7 +20,7 @@ clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" memchr = "2.5.0" notify = { version = "=5.0.0", features=["macos_kqueue"]} -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["ringbuffer", "lines"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["ringbuffer", "lines"] } same-file = "1.0.6" atty = "0.2" diff --git a/src/uu/tail/src/args.rs b/src/uu/tail/src/args.rs index 6e972d25f..5f7ea1028 100644 --- a/src/uu/tail/src/args.rs +++ b/src/uu/tail/src/args.rs @@ -69,12 +69,7 @@ impl FilterMode { let mode = if let Some(arg) = matches.get_one::(options::BYTES) { match parse_num(arg) { Ok(signum) => Self::Bytes(signum), - Err(e) => { - return Err(UUsageError::new( - 1, - format!("invalid number of bytes: {}", e), - )) - } + Err(e) => return Err(UUsageError::new(1, format!("invalid number of bytes: {e}"))), } } else if let Some(arg) = matches.get_one::(options::LINES) { match parse_num(arg) { @@ -82,12 +77,7 @@ impl FilterMode { let delimiter = if zero_term { 0 } else { b'\n' }; Self::Lines(signum, delimiter) } - Err(e) => { - return Err(UUsageError::new( - 1, - format!("invalid number of lines: {}", e), - )) - } + Err(e) => return Err(UUsageError::new(1, format!("invalid number of lines: {e}"))), } } else if zero_term { Self::default_zero() diff --git a/src/uu/tail/src/chunks.rs b/src/uu/tail/src/chunks.rs index 7ad2e153b..4b934c1d7 100644 --- a/src/uu/tail/src/chunks.rs +++ b/src/uu/tail/src/chunks.rs @@ -48,7 +48,7 @@ pub struct ReverseChunks<'a> { impl<'a> ReverseChunks<'a> { pub fn new(file: &'a mut File) -> ReverseChunks<'a> { let current = if cfg!(unix) { - file.seek(SeekFrom::Current(0)).unwrap() + file.stream_position().unwrap() } else { 0 }; diff --git a/src/uu/tail/src/follow/watch.rs b/src/uu/tail/src/follow/watch.rs index 31a6d70cb..2c3cf10b8 100644 --- a/src/uu/tail/src/follow/watch.rs +++ b/src/uu/tail/src/follow/watch.rs @@ -566,11 +566,11 @@ pub fn follow(mut observer: Observer, settings: &Settings) -> UResult<()> { format!("{} resources exhausted", text::BACKEND), )) } - Ok(Err(e)) => return Err(USimpleError::new(1, format!("NotifyError: {}", e))), + Ok(Err(e)) => return Err(USimpleError::new(1, format!("NotifyError: {e}"))), Err(mpsc::RecvTimeoutError::Timeout) => { _timeout_counter += 1; } - Err(e) => return Err(USimpleError::new(1, format!("RecvTimeoutError: {}", e))), + Err(e) => return Err(USimpleError::new(1, format!("RecvTimeoutError: {e}"))), } if observer.use_polling && settings.follow.is_some() { diff --git a/src/uu/tail/src/parse.rs b/src/uu/tail/src/parse.rs index 7511f2405..2129d8e29 100644 --- a/src/uu/tail/src/parse.rs +++ b/src/uu/tail/src/parse.rs @@ -78,10 +78,10 @@ pub fn parse_obsolete(src: &str) -> Option Some(n) => n, None => return Some(Err(ParseError::Overflow)), }; - options.push(OsString::from(format!("{}", num))); + options.push(OsString::from(format!("{num}"))); } else { options.push(OsString::from("-n")); - options.push(OsString::from(format!("{}", num))); + options.push(OsString::from(format!("{num}"))); } Some(Ok(options.into_iter())) } diff --git a/src/uu/tail/src/paths.rs b/src/uu/tail/src/paths.rs index 03656d036..d8e6ece9a 100644 --- a/src/uu/tail/src/paths.rs +++ b/src/uu/tail/src/paths.rs @@ -132,7 +132,7 @@ impl FileExtTail for File { /// Test if File is seekable. /// Set the current position offset to `current_offset`. fn is_seekable(&mut self, current_offset: u64) -> bool { - self.seek(SeekFrom::Current(0)).is_ok() + self.stream_position().is_ok() && self.seek(SeekFrom::End(0)).is_ok() && self.seek(SeekFrom::Start(current_offset)).is_ok() } diff --git a/src/uu/tail/src/tail.rs b/src/uu/tail/src/tail.rs index 2a5a94352..9e3273638 100644 --- a/src/uu/tail/src/tail.rs +++ b/src/uu/tail/src/tail.rs @@ -198,7 +198,7 @@ fn tail_stdin( // Save the current seek position/offset of a stdin redirected file. // This is needed to pass "gnu/tests/tail-2/start-middle.sh" if let Ok(mut stdin_handle) = Handle::stdin() { - if let Ok(offset) = stdin_handle.as_file_mut().seek(SeekFrom::Current(0)) { + if let Ok(offset) = stdin_handle.as_file_mut().stream_position() { stdin_offset = offset; } } diff --git a/src/uu/tee/Cargo.toml b/src/uu/tee/Cargo.toml index b9c6a36a9..139e3df3c 100644 --- a/src/uu/tee/Cargo.toml +++ b/src/uu/tee/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_tee" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "tee ~ (uutils) display input and copy to FILE" @@ -18,7 +18,7 @@ path = "src/tee.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" retain_mut = "=0.1.7" # ToDO: [2021-01-01; rivy; maint/MinSRV] ~ v0.1.5 uses const generics which aren't stabilized until rust v1.51.0 -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["libc"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["libc"] } [[bin]] name = "tee" diff --git a/src/uu/test/Cargo.toml b/src/uu/test/Cargo.toml index f1ae083e0..396373f49 100644 --- a/src/uu/test/Cargo.toml +++ b/src/uu/test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_test" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "test ~ (uutils) evaluate comparison and file type expressions" @@ -17,7 +17,7 @@ path = "src/test.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [target.'cfg(target_os = "redox")'.dependencies] redox_syscall = "0.2" diff --git a/src/uu/test/src/parser.rs b/src/uu/test/src/parser.rs index 1177f49ea..b76333930 100644 --- a/src/uu/test/src/parser.rs +++ b/src/uu/test/src/parser.rs @@ -142,7 +142,7 @@ impl Parser { fn expect(&mut self, value: &str) { match self.next_token() { Symbol::Literal(s) if s == value => (), - _ => panic!("expected ‘{}’", value), + _ => panic!("expected ‘{value}’"), } } @@ -383,7 +383,7 @@ impl Parser { let op = self.next_token(); match self.next_token() { - Symbol::None => panic!("missing argument after {:?}", op), + Symbol::None => panic!("missing argument after {op:?}"), token => self.stack.push(token.into_literal()), } diff --git a/src/uu/test/src/test.rs b/src/uu/test/src/test.rs index bc274bc8b..8ce4564a3 100644 --- a/src/uu/test/src/test.rs +++ b/src/uu/test/src/test.rs @@ -186,7 +186,7 @@ fn eval(stack: &mut Vec) -> Result { return Ok(true); } _ => { - return Err(format!("missing argument after '{:?}'", op)); + return Err(format!("missing argument after '{op:?}'")); } }; diff --git a/src/uu/timeout/Cargo.toml b/src/uu/timeout/Cargo.toml index 6c42553a9..ab71bad9a 100644 --- a/src/uu/timeout/Cargo.toml +++ b/src/uu/timeout/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_timeout" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "timeout ~ (uutils) run COMMAND with a DURATION time limit" @@ -18,7 +18,7 @@ path = "src/timeout.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" nix = { version = "0.25", default-features = false, features = ["signal"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["process", "signals"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["process", "signals"] } [[bin]] name = "timeout" diff --git a/src/uu/timeout/src/timeout.rs b/src/uu/timeout/src/timeout.rs index 246537a30..26235e0df 100644 --- a/src/uu/timeout/src/timeout.rs +++ b/src/uu/timeout/src/timeout.rs @@ -314,7 +314,7 @@ fn timeout( // FIXME: this may not be 100% correct... 126 }; - USimpleError::new(status_code, format!("failed to execute process: {}", err)) + USimpleError::new(status_code, format!("failed to execute process: {err}")) })?; unblock_sigchld(); // Wait for the child process for the specified time period. @@ -355,7 +355,7 @@ fn timeout( Ok(status) => Err(status.into()), Err(e) => Err(USimpleError::new( ExitStatus::TimeoutFailed.into(), - format!("{}", e), + format!("{e}"), )), } } @@ -365,9 +365,9 @@ fn timeout( // 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)) - })?; + process + .send_signal(signal) + .map_err(|e| USimpleError::new(ExitStatus::TimeoutFailed.into(), format!("{e}")))?; Err(ExitStatus::TimeoutFailed.into()) } } diff --git a/src/uu/touch/Cargo.toml b/src/uu/touch/Cargo.toml index 7aae33ccf..40ee899af 100644 --- a/src/uu/touch/Cargo.toml +++ b/src/uu/touch/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_touch" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "touch ~ (uutils) change FILE timestamps" @@ -18,7 +18,7 @@ path = "src/touch.rs" filetime = "0.2.18" clap = { version = "4.0", features = ["wrap_help", "cargo"] } time = { version = "0.3", features = ["parsing", "formatting", "local-offset", "macros"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["libc"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["libc"] } [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Storage_FileSystem", "Win32_Foundation"] } diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index c898d8924..a7d3557bd 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -46,7 +46,7 @@ fn to_local(tm: time::PrimitiveDateTime) -> time::OffsetDateTime { let offset = match time::OffsetDateTime::now_local() { Ok(lo) => lo.offset(), Err(e) => { - panic!("error: {}", e); + panic!("error: {e}"); } }; tm.assume_offset(offset) @@ -71,8 +71,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let files = matches.get_many::(ARG_FILES).ok_or_else(|| { USimpleError::new( 1, - r##"missing file operand -Try 'touch --help' for more information."##, + format!( + "missing file operand\nTry '{} --help' for more information.", + uucore::execution_phrase() + ), ) })?; let (mut atime, mut mtime) = @@ -436,7 +438,7 @@ fn parse_date(s: &str) -> UResult { return Ok(local_dt_to_filetime(diff)); } - Err(USimpleError::new(1, format!("Unable to parse date: {}", s))) + Err(USimpleError::new(1, format!("Unable to parse date: {s}"))) } fn parse_timestamp(s: &str) -> UResult { @@ -556,7 +558,7 @@ fn pathbuf_from_stdout() -> UResult { ERROR_PATH_NOT_FOUND | ERROR_NOT_ENOUGH_MEMORY | ERROR_INVALID_PARAMETER => { return Err(USimpleError::new( 1, - format!("GetFinalPathNameByHandleW failed with code {}", ret), + format!("GetFinalPathNameByHandleW failed with code {ret}"), )) } e if e == 0 => { diff --git a/src/uu/tr/Cargo.toml b/src/uu/tr/Cargo.toml index 3c69b4f30..992423999 100644 --- a/src/uu/tr/Cargo.toml +++ b/src/uu/tr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_tr" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "tr ~ (uutils) translate characters within input and display" @@ -17,7 +17,7 @@ path = "src/tr.rs" [dependencies] nom = "7.1.1" clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "tr" diff --git a/src/uu/tr/src/operation.rs b/src/uu/tr/src/operation.rs index 0bc8005fe..03cea92e7 100644 --- a/src/uu/tr/src/operation.rs +++ b/src/uu/tr/src/operation.rs @@ -48,7 +48,7 @@ impl Display for BadSequence { writeln!(f, "the [c*] repeat construct may not appear in string1") } Self::InvalidRepeatCount(count) => { - writeln!(f, "invalid repeat count '{}' in [c*n] construct", count) + writeln!(f, "invalid repeat count '{count}' in [c*n] construct") } Self::EmptySet2WhenNotTruncatingSet1 => { writeln!(f, "when not truncating set1, string2 must be non-empty") diff --git a/src/uu/true/Cargo.toml b/src/uu/true/Cargo.toml index cc7269b30..ef92d33a4 100644 --- a/src/uu/true/Cargo.toml +++ b/src/uu/true/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_true" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "true ~ (uutils) do nothing and succeed" @@ -16,7 +16,7 @@ path = "src/true.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "true" diff --git a/src/uu/truncate/Cargo.toml b/src/uu/truncate/Cargo.toml index 0f07e6804..919ab4fab 100644 --- a/src/uu/truncate/Cargo.toml +++ b/src/uu/truncate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_truncate" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "truncate ~ (uutils) truncate (or extend) FILE to SIZE" @@ -16,7 +16,7 @@ path = "src/truncate.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "truncate" diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index 517d766e3..5a5ef0a97 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -231,7 +231,7 @@ fn truncate_reference_and_size( create: bool, ) -> UResult<()> { let mode = match parse_mode_and_size(size_string) { - Err(e) => return Err(USimpleError::new(1, format!("Invalid number: {}", e))), + Err(e) => return Err(USimpleError::new(1, format!("Invalid number: {e}"))), Ok(TruncateMode::Absolute(_)) => { return Err(USimpleError::new( 1, @@ -338,7 +338,7 @@ fn truncate_reference_file_only( /// If at least one file is a named pipe (also known as a fifo). fn truncate_size_only(size_string: &str, filenames: &[String], create: bool) -> UResult<()> { let mode = parse_mode_and_size(size_string) - .map_err(|e| USimpleError::new(1, format!("Invalid number: {}", e)))?; + .map_err(|e| USimpleError::new(1, format!("Invalid number: {e}")))?; if let TruncateMode::RoundDown(0) | TruncateMode::RoundUp(0) = mode { return Err(USimpleError::new(1, "division by zero")); } diff --git a/src/uu/tsort/Cargo.toml b/src/uu/tsort/Cargo.toml index d48dcc149..63eeb111a 100644 --- a/src/uu/tsort/Cargo.toml +++ b/src/uu/tsort/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_tsort" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "tsort ~ (uutils) topologically sort input (partially ordered) pairs" @@ -16,7 +16,7 @@ path = "src/tsort.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "tsort" diff --git a/src/uu/tsort/src/tsort.rs b/src/uu/tsort/src/tsort.rs index 1ef853706..cb179699d 100644 --- a/src/uu/tsort/src/tsort.rs +++ b/src/uu/tsort/src/tsort.rs @@ -76,12 +76,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if !g.is_acyclic() { return Err(USimpleError::new( 1, - format!("{}, input contains a loop:", input), + format!("{input}, input contains a loop:"), )); } for x in &g.result { - println!("{}", x); + println!("{x}"); } Ok(()) diff --git a/src/uu/tty/Cargo.toml b/src/uu/tty/Cargo.toml index d419a6664..d71f08d10 100644 --- a/src/uu/tty/Cargo.toml +++ b/src/uu/tty/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_tty" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "tty ~ (uutils) display the name of the terminal connected to standard input" @@ -18,7 +18,7 @@ path = "src/tty.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } nix = "0.25" atty = "0.2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["fs"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["fs"] } [[bin]] name = "tty" diff --git a/src/uu/uname/Cargo.toml b/src/uu/uname/Cargo.toml index cc7b5f43b..bcd68f1e8 100644 --- a/src/uu/uname/Cargo.toml +++ b/src/uu/uname/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_uname" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "uname ~ (uutils) display system information" @@ -15,9 +15,9 @@ edition = "2021" path = "src/uname.rs" [dependencies] -platform-info = "1.0.1" +platform-info = "1.0.2" clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "uname" diff --git a/src/uu/uname/src/uname.rs b/src/uu/uname/src/uname.rs index e89cb3efe..f74f18772 100644 --- a/src/uu/uname/src/uname.rs +++ b/src/uu/uname/src/uname.rs @@ -8,7 +8,7 @@ // last synced with: uname (GNU coreutils) 8.21 -// spell-checker:ignore (ToDO) nodename kernelname kernelrelease kernelversion sysname hwplatform mnrsv +// spell-checker:ignore (API) nodename osname sysname (options) mnrsv mnrsvo use clap::{crate_version, Arg, ArgAction, Command}; use platform_info::*; @@ -23,37 +23,16 @@ const USAGE: &str = "{} [OPTION]..."; pub mod options { pub static ALL: &str = "all"; - pub static KERNELNAME: &str = "kernel-name"; + pub static KERNEL_NAME: &str = "kernel-name"; pub static NODENAME: &str = "nodename"; - pub static KERNELVERSION: &str = "kernel-version"; - pub static KERNELRELEASE: &str = "kernel-release"; + pub static KERNEL_VERSION: &str = "kernel-version"; + pub static KERNEL_RELEASE: &str = "kernel-release"; pub static MACHINE: &str = "machine"; pub static PROCESSOR: &str = "processor"; - pub static HWPLATFORM: &str = "hardware-platform"; + pub static HARDWARE_PLATFORM: &str = "hardware-platform"; pub static OS: &str = "operating-system"; } -#[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "")))] -const HOST_OS: &str = "GNU/Linux"; -#[cfg(all(target_os = "linux", not(any(target_env = "gnu", target_env = ""))))] -const HOST_OS: &str = "Linux"; -#[cfg(target_os = "android")] -const HOST_OS: &str = "Android"; -#[cfg(target_os = "windows")] -const HOST_OS: &str = "Windows NT"; -#[cfg(target_os = "freebsd")] -const HOST_OS: &str = "FreeBSD"; -#[cfg(target_os = "netbsd")] -const HOST_OS: &str = "NetBSD"; -#[cfg(target_os = "openbsd")] -const HOST_OS: &str = "OpenBSD"; -#[cfg(target_vendor = "apple")] -const HOST_OS: &str = "Darwin"; -#[cfg(target_os = "fuchsia")] -const HOST_OS: &str = "Fuchsia"; -#[cfg(target_os = "redox")] -const HOST_OS: &str = "Redox"; - #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().try_get_matches_from(args)?; @@ -63,41 +42,42 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let mut output = String::new(); let all = matches.get_flag(options::ALL); - let kernelname = matches.get_flag(options::KERNELNAME); + let kernel_name = matches.get_flag(options::KERNEL_NAME); let nodename = matches.get_flag(options::NODENAME); - let kernelrelease = matches.get_flag(options::KERNELRELEASE); - let kernelversion = matches.get_flag(options::KERNELVERSION); + let kernel_release = matches.get_flag(options::KERNEL_RELEASE); + let kernel_version = matches.get_flag(options::KERNEL_VERSION); let machine = matches.get_flag(options::MACHINE); let processor = matches.get_flag(options::PROCESSOR); - let hwplatform = matches.get_flag(options::HWPLATFORM); + let hardware_platform = matches.get_flag(options::HARDWARE_PLATFORM); let os = matches.get_flag(options::OS); let none = !(all - || kernelname + || kernel_name || nodename - || kernelrelease - || kernelversion + || kernel_release + || kernel_version || machine || os || processor - || hwplatform); + || hardware_platform); - if kernelname || all || none { + if kernel_name || all || none { output.push_str(&uname.sysname()); output.push(' '); } if nodename || all { - output.push_str(&uname.nodename()); + // maint: [2023-01-14; rivy] remove `.trim_end_matches('\0')` when platform-info nodename-NUL bug is fixed (see GH:uutils/platform-info/issues/32) + output.push_str(uname.nodename().trim_end_matches('\0')); output.push(' '); } - if kernelrelease || all { + if kernel_release || all { output.push_str(&uname.release()); output.push(' '); } - if kernelversion || all { + if kernel_version || all { output.push_str(&uname.version()); output.push(' '); } @@ -108,7 +88,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } if os || all { - output.push_str(HOST_OS); + output.push_str(&uname.osname()); output.push(' '); } @@ -121,7 +101,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { // This option is unsupported on modern Linux systems // See: https://lists.gnu.org/archive/html/bug-coreutils/2005-09/msg00063.html - if hwplatform { + if hardware_platform { output.push_str("unknown"); output.push(' '); } @@ -141,13 +121,13 @@ pub fn uu_app() -> Command { Arg::new(options::ALL) .short('a') .long(options::ALL) - .help("Behave as though all of the options -mnrsv were specified.") + .help("Behave as though all of the options -mnrsvo were specified.") .action(ArgAction::SetTrue), ) .arg( - Arg::new(options::KERNELNAME) + Arg::new(options::KERNEL_NAME) .short('s') - .long(options::KERNELNAME) + .long(options::KERNEL_NAME) .alias("sysname") // Obsolescent option in GNU uname .help("print the kernel name.") .action(ArgAction::SetTrue), @@ -163,17 +143,17 @@ pub fn uu_app() -> Command { .action(ArgAction::SetTrue), ) .arg( - Arg::new(options::KERNELRELEASE) + Arg::new(options::KERNEL_RELEASE) .short('r') - .long(options::KERNELRELEASE) + .long(options::KERNEL_RELEASE) .alias("release") // Obsolescent option in GNU uname .help("print the operating system release.") .action(ArgAction::SetTrue), ) .arg( - Arg::new(options::KERNELVERSION) + Arg::new(options::KERNEL_VERSION) .short('v') - .long(options::KERNELVERSION) + .long(options::KERNEL_VERSION) .help("print the operating system version.") .action(ArgAction::SetTrue), ) @@ -200,9 +180,9 @@ pub fn uu_app() -> Command { .hide(true), ) .arg( - Arg::new(options::HWPLATFORM) + Arg::new(options::HARDWARE_PLATFORM) .short('i') - .long(options::HWPLATFORM) + .long(options::HARDWARE_PLATFORM) .help("print the hardware platform (non-portable)") .action(ArgAction::SetTrue) .hide(true), diff --git a/src/uu/unexpand/Cargo.toml b/src/uu/unexpand/Cargo.toml index 24620e934..bd858732e 100644 --- a/src/uu/unexpand/Cargo.toml +++ b/src/uu/unexpand/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_unexpand" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "unexpand ~ (uutils) convert input spaces to tabs" @@ -17,7 +17,7 @@ path = "src/unexpand.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } unicode-width = "0.1.5" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "unexpand" diff --git a/src/uu/unexpand/src/unexpand.rs b/src/uu/unexpand/src/unexpand.rs index 22e4aa08e..df2348a8c 100644 --- a/src/uu/unexpand/src/unexpand.rs +++ b/src/uu/unexpand/src/unexpand.rs @@ -21,10 +21,9 @@ use uucore::display::Quotable; use uucore::error::{FromIo, UError, UResult}; use uucore::{crash, crash_if_err, format_usage}; -static NAME: &str = "unexpand"; static USAGE: &str = "{} [OPTION]... [FILE]..."; -static ABOUT: &str = r#"Convert blanks in each FILE to tabs, writing to standard output. - With no FILE, or when FILE is -, read standard input."#; +static ABOUT: &str = "Convert blanks in each FILE to tabs, writing to standard output.\n\n\ + With no FILE, or when FILE is -, read standard input."; const DEFAULT_TABSTOP: usize = 8; @@ -143,7 +142,7 @@ fn expand_shortcuts(args: &[String]) -> Vec { arg[1..] .split(',') .filter(|s| !s.is_empty()) - .for_each(|s| processed_args.push(format!("--tabs={}", s))); + .for_each(|s| processed_args.push(format!("--tabs={s}"))); has_shortcuts = true; } else { processed_args.push(arg.to_string()); @@ -172,7 +171,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app() -> Command { Command::new(uucore::util_name()) - .name(NAME) .version(crate_version!()) .override_usage(format_usage(USAGE)) .about(ABOUT) diff --git a/src/uu/uniq/Cargo.toml b/src/uu/uniq/Cargo.toml index cd0fdad6f..98432caf0 100644 --- a/src/uu/uniq/Cargo.toml +++ b/src/uu/uniq/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_uniq" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "uniq ~ (uutils) filter identical adjacent lines from input" @@ -18,7 +18,7 @@ path = "src/uniq.rs" clap = { version = "4.0", features = ["wrap_help", "cargo"] } strum = "0.24.1" strum_macros = "0.24.2" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "uniq" diff --git a/src/uu/uniq/src/uniq.rs b/src/uu/uniq/src/uniq.rs index a66393acb..cbbd988cb 100644 --- a/src/uu/uniq/src/uniq.rs +++ b/src/uu/uniq/src/uniq.rs @@ -212,7 +212,7 @@ impl Uniq { } if self.show_counts { - writer.write_all(format!("{:7} {}", count, line).as_bytes()) + writer.write_all(format!("{count:7} {line}").as_bytes()) } else { writer.write_all(line.as_bytes()) } @@ -225,7 +225,7 @@ impl Uniq { fn get_line_string(io_line: io::Result>) -> UResult { let line_bytes = io_line.map_err_context(|| "failed to split lines".to_string())?; String::from_utf8(line_bytes) - .map_err(|e| USimpleError::new(1, format!("failed to convert line to utf8: {}", e))) + .map_err(|e| USimpleError::new(1, format!("failed to convert line to utf8: {e}"))) } fn opt_parsed(opt_name: &str, matches: &ArgMatches) -> UResult> { diff --git a/src/uu/unlink/Cargo.toml b/src/uu/unlink/Cargo.toml index c26678ec5..f63757fba 100644 --- a/src/uu/unlink/Cargo.toml +++ b/src/uu/unlink/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_unlink" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "unlink ~ (uutils) remove a (file system) link to FILE" @@ -16,7 +16,7 @@ path = "src/unlink.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore" } [[bin]] name = "unlink" diff --git a/src/uu/uptime/Cargo.toml b/src/uu/uptime/Cargo.toml index 367256814..99d60c309 100644 --- a/src/uu/uptime/Cargo.toml +++ b/src/uu/uptime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_uptime" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "uptime ~ (uutils) display dynamic system information" @@ -17,7 +17,7 @@ path = "src/uptime.rs" [dependencies] chrono = { version="^0.4.23", default-features=false, features=["std", "alloc", "clock"]} clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["libc", "utmpx"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["libc", "utmpx"] } [[bin]] name = "uptime" diff --git a/src/uu/uptime/src/uptime.rs b/src/uu/uptime/src/uptime.rs index 0751cbe9d..d13445f60 100644 --- a/src/uu/uptime/src/uptime.rs +++ b/src/uu/uptime/src/uptime.rs @@ -133,7 +133,7 @@ fn process_utmpx() -> (Option, usize) { fn print_nusers(nusers: usize) { match nusers.cmp(&1) { std::cmp::Ordering::Equal => print!("1 user, "), - std::cmp::Ordering::Greater => print!("{} users, ", nusers), + std::cmp::Ordering::Greater => print!("{nusers} users, "), _ => {} }; } @@ -180,10 +180,10 @@ fn print_uptime(upsecs: i64) { let uphours = (upsecs - (updays * 86400)) / 3600; let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60; match updays.cmp(&1) { - std::cmp::Ordering::Equal => print!("up {:1} day, {:2}:{:02}, ", updays, uphours, upmins), + std::cmp::Ordering::Equal => print!("up {updays:1} day, {uphours:2}:{upmins:02}, "), std::cmp::Ordering::Greater => { - print!("up {:1} days, {:2}:{:02}, ", updays, uphours, upmins); + print!("up {updays:1} days, {uphours:2}:{upmins:02}, "); } - _ => print!("up {:2}:{:02}, ", uphours, upmins), + _ => print!("up {uphours:2}:{upmins:02}, "), }; } diff --git a/src/uu/users/Cargo.toml b/src/uu/users/Cargo.toml index 101af11e3..658c3c25a 100644 --- a/src/uu/users/Cargo.toml +++ b/src/uu/users/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_users" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "users ~ (uutils) display names of currently logged-in users" @@ -16,7 +16,7 @@ path = "src/users.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["utmpx"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["utmpx"] } [[bin]] name = "users" diff --git a/src/uu/vdir/Cargo.toml b/src/uu/vdir/Cargo.toml index d62b20b39..9576770ab 100644 --- a/src/uu/vdir/Cargo.toml +++ b/src/uu/vdir/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_vdir" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "shortcut to ls -l -b" @@ -16,8 +16,8 @@ path = "src/vdir.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo", "env"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } -uu_ls = { version = ">=0.0.16", path="../ls"} +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "fs"] } +uu_ls = { version = ">=0.0.17", path="../ls"} [[bin]] name = "vdir" diff --git a/src/uu/wc/Cargo.toml b/src/uu/wc/Cargo.toml index 2eeeb8799..6d30267a8 100644 --- a/src/uu/wc/Cargo.toml +++ b/src/uu/wc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_wc" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "wc ~ (uutils) display newline, word, and byte counts for input" @@ -16,7 +16,7 @@ path = "src/wc.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["pipes"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["pipes"] } bytecount = "0.6.3" utf-8 = "0.7.6" unicode-width = "0.1.8" diff --git a/src/uu/wc/src/wc.rs b/src/uu/wc/src/wc.rs index 135575d71..4a4838350 100644 --- a/src/uu/wc/src/wc.rs +++ b/src/uu/wc/src/wc.rs @@ -185,7 +185,7 @@ impl Display for WcError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::FilesDisabled(message) | Self::StdinReprNotAllowed(message) => { - write!(f, "{}", message) + write!(f, "{message}") } } } @@ -613,7 +613,7 @@ fn wc(inputs: &[Input], settings: &Settings) -> UResult<()> { if let Err(err) = print_stats(settings, &total_result, number_width) { show!(USimpleError::new( 1, - format!("failed to print total: {}", err) + format!("failed to print total: {err}") )); } } diff --git a/src/uu/who/Cargo.toml b/src/uu/who/Cargo.toml index bfeffe352..cd1af860d 100644 --- a/src/uu/who/Cargo.toml +++ b/src/uu/who/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_who" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "who ~ (uutils) display information about currently logged-in users" @@ -16,7 +16,7 @@ path = "src/who.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["utmpx"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["utmpx"] } [[bin]] name = "who" diff --git a/src/uu/who/src/who.rs b/src/uu/who/src/who.rs index 85ad435e5..935319c31 100644 --- a/src/uu/who/src/who.rs +++ b/src/uu/who/src/who.rs @@ -392,7 +392,7 @@ impl Who { fn print_runlevel(&self, ut: &Utmpx) { let last = (ut.pid() / 256) as u8 as char; let curr = (ut.pid() % 256) as u8 as char; - let runlvline = format!("run-level {}", curr); + let runlvline = format!("run-level {curr}"); let comment = format!("last={}", if last == 'N' { 'S' } else { 'N' }); self.print_line( @@ -508,7 +508,7 @@ impl Who { } else { ut.host() }; - let hoststr = if s.is_empty() { s } else { format!("({})", s) }; + let hoststr = if s.is_empty() { s } else { format!("({s})") }; self.print_line( ut.user().as_ref(), @@ -539,24 +539,24 @@ impl Who { let mut buf = String::with_capacity(64); let msg = vec![' ', state].into_iter().collect::(); - write!(buf, "{:<8}", user).unwrap(); + write!(buf, "{user:<8}").unwrap(); if self.include_mesg { buf.push_str(&msg); } - write!(buf, " {:<12}", line).unwrap(); + write!(buf, " {line:<12}").unwrap(); // "%b %e %H:%M" (LC_ALL=C) let time_size = 3 + 2 + 2 + 1 + 2; - write!(buf, " {:<1$}", time, time_size).unwrap(); + write!(buf, " {time:10}", pid).unwrap(); + write!(buf, " {pid:>10}").unwrap(); } - write!(buf, " {:<8}", comment).unwrap(); + write!(buf, " {comment:<8}").unwrap(); if self.include_exit { - write!(buf, " {:<12}", exit).unwrap(); + write!(buf, " {exit:<12}").unwrap(); } println!("{}", buf.trim_end()); } diff --git a/src/uu/whoami/Cargo.toml b/src/uu/whoami/Cargo.toml index 4c1b5c2ab..9d576453f 100644 --- a/src/uu/whoami/Cargo.toml +++ b/src/uu/whoami/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_whoami" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "whoami ~ (uutils) display user name of current effective user ID" @@ -16,7 +16,7 @@ path = "src/whoami.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries"] } [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_NetworkManagement_NetManagement", "Win32_System_WindowsProgramming", "Win32_Foundation"] } diff --git a/src/uu/yes/Cargo.toml b/src/uu/yes/Cargo.toml index 1f2db513b..ff52de031 100644 --- a/src/uu/yes/Cargo.toml +++ b/src/uu/yes/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uu_yes" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "yes ~ (uutils) repeatedly display a line with STRING (or 'y')" @@ -17,7 +17,7 @@ path = "src/yes.rs" [dependencies] clap = { version = "4.0", features = ["wrap_help", "cargo"] } libc = "0.2.137" -uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["pipes"] } +uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["pipes"] } [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] nix = { version = "0.25", default-features = false } diff --git a/src/uu/yes/src/yes.rs b/src/uu/yes/src/yes.rs index cc04d26bc..09d4e5955 100644 --- a/src/uu/yes/src/yes.rs +++ b/src/uu/yes/src/yes.rs @@ -43,7 +43,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { match exec(bytes) { Ok(()) => Ok(()), Err(err) if err.kind() == io::ErrorKind::BrokenPipe => Ok(()), - Err(err) => Err(USimpleError::new(1, format!("standard output: {}", err))), + Err(err) => Err(USimpleError::new(1, format!("standard output: {err}"))), } } diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index fa1c1d74b..6264d7665 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "uucore" -version = "0.0.16" +version = "0.0.17" authors = ["uutils developers"] license = "MIT" description = "uutils ~ 'core' uutils code library (cross-platform)" @@ -18,7 +18,7 @@ edition = "2021" path="src/lib/lib.rs" [dependencies] -uucore_procs = { version=">=0.0.16", path="../uucore_procs" } +uucore_procs = { version=">=0.0.17", path="../uucore_procs" } clap = "4.0" dns-lookup = { version="1.0.5", optional=true } dunce = "1.0.3" diff --git a/src/uucore/src/lib/features/encoding.rs b/src/uucore/src/lib/features/encoding.rs index e99017070..db4c4c635 100644 --- a/src/uucore/src/lib/features/encoding.rs +++ b/src/uucore/src/lib/features/encoding.rs @@ -165,7 +165,7 @@ pub fn wrap_write(mut writer: W, line_wrap: usize, res: &str) -> io::R use std::cmp::min; if line_wrap == 0 { - return write!(writer, "{}", res); + return write!(writer, "{res}"); } let mut start = 0; diff --git a/src/uucore/src/lib/features/fs.rs b/src/uucore/src/lib/features/fs.rs index d5c7cbac1..43c21aa8d 100644 --- a/src/uucore/src/lib/features/fs.rs +++ b/src/uucore/src/lib/features/fs.rs @@ -115,6 +115,7 @@ impl FileInformation { not(target_os = "android"), not(target_os = "freebsd"), not(target_arch = "aarch64"), + not(target_arch = "riscv64"), target_pointer_width = "64" ))] return self.0.st_nlink; @@ -125,6 +126,7 @@ impl FileInformation { target_os = "android", target_os = "freebsd", target_arch = "aarch64", + target_arch = "riscv64", not(target_pointer_width = "64") ) ))] @@ -439,9 +441,9 @@ pub fn display_permissions(metadata: &fs::Metadata, display_file_type: bool) -> '-' }; - format!("{0}r{1}xr{1}xr{1}x", file_type, write) + format!("{file_type}r{write}xr{write}xr{write}x") } else { - format!("r{0}xr{0}xr{0}x", write) + format!("r{write}xr{write}xr{write}x") } } diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index fcace586d..927ae0f7a 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -619,6 +619,7 @@ impl FsMeta for StatFs { not(target_vendor = "apple"), not(target_os = "android"), not(target_os = "freebsd"), + not(target_arch = "s390x"), target_pointer_width = "64" ))] return self.f_bsize; @@ -626,6 +627,7 @@ impl FsMeta for StatFs { not(target_env = "musl"), not(target_os = "freebsd"), any( + target_arch = "s390x", target_vendor = "apple", target_os = "android", not(target_pointer_width = "64") @@ -681,6 +683,7 @@ impl FsMeta for StatFs { not(target_vendor = "apple"), not(target_os = "android"), not(target_os = "freebsd"), + not(target_arch = "s390x"), target_pointer_width = "64" ))] return self.f_type; @@ -690,6 +693,7 @@ impl FsMeta for StatFs { target_vendor = "apple", target_os = "android", target_os = "freebsd", + target_arch = "s390x", not(target_pointer_width = "64") ) ))] @@ -828,7 +832,7 @@ pub fn pretty_time(sec: i64, nsec: i64) -> String { let tm = match time::OffsetDateTime::from_unix_timestamp_nanos(ts_nanos) { Ok(tm) => tm, Err(e) => { - panic!("error: {}", e); + panic!("error: {e}"); } }; @@ -838,7 +842,7 @@ pub fn pretty_time(sec: i64, nsec: i64) -> String { let local_offset = match UtcOffset::local_offset_at(tm) { Ok(lo) => lo, Err(e) => { - panic!("error: {}", e); + panic!("error: {e}"); } }; @@ -993,7 +997,7 @@ pub fn pretty_fstype<'a>(fstype: i64) -> Cow<'a, str> { 0x5846_5342 => "xfs".into(), 0x012F_D16D => "xia".into(), 0x2FC1_2FC1 => "zfs".into(), - other => format!("UNKNOWN ({:#x})", other).into(), + other => format!("UNKNOWN ({other:#x})").into(), } // spell-checker:enable } diff --git a/src/uucore/src/lib/features/memo.rs b/src/uucore/src/lib/features/memo.rs index c61be8acf..517efc9e2 100644 --- a/src/uucore/src/lib/features/memo.rs +++ b/src/uucore/src/lib/features/memo.rs @@ -142,7 +142,7 @@ pub fn sprintf(format_string: &str, args: &[String]) -> UResult { Ok(s) => Ok(s), Err(e) => Err(USimpleError::new( 1, - format!("failed to parse formatted string as UTF-8: {}", e), + format!("failed to parse formatted string as UTF-8: {e}"), )), } } diff --git a/src/uucore/src/lib/features/mode.rs b/src/uucore/src/lib/features/mode.rs index c27464363..956981254 100644 --- a/src/uucore/src/lib/features/mode.rs +++ b/src/uucore/src/lib/features/mode.rs @@ -20,7 +20,7 @@ pub fn parse_numeric(fperm: u32, mut mode: &str, considering_dir: bool) -> Resul u32::from_str_radix(mode, 8).map_err(|e| e.to_string())? }; if change > 0o7777 { - Err(format!("mode is too large ({} > 7777", change)) + Err(format!("mode is too large ({change} > 7777")) } else { Ok(match op { Some('+') => fperm | change, @@ -42,7 +42,7 @@ pub fn parse_symbolic( ) -> Result { let (mask, pos) = parse_levels(mode); if pos == mode.len() { - return Err(format!("invalid mode ({})", mode)); + return Err(format!("invalid mode ({mode})")); } let respect_umask = pos == 0; mode = &mode[pos..]; @@ -97,8 +97,7 @@ fn parse_op(mode: &str) -> Result<(char, usize), String> { match ch { '+' | '-' | '=' => Ok((ch, 1)), _ => Err(format!( - "invalid operator (expected +, -, or =, but found {})", - ch + "invalid operator (expected +, -, or =, but found {ch})" )), } } diff --git a/src/uucore/src/lib/features/signals.rs b/src/uucore/src/lib/features/signals.rs index 55f9b4b79..b92ecf764 100644 --- a/src/uucore/src/lib/features/signals.rs +++ b/src/uucore/src/lib/features/signals.rs @@ -215,7 +215,7 @@ fn signal_by_short_name() { fn signal_by_long_name() { for (value, signal) in ALL_SIGNALS.iter().enumerate() { assert_eq!( - signal_by_name_or_value(&format!("SIG{}", signal)), + signal_by_name_or_value(&format!("SIG{signal}")), Some(value) ); } diff --git a/src/uucore/src/lib/features/tokenize/num_format/formatters/cninetyninehexfloatf.rs b/src/uucore/src/lib/features/tokenize/num_format/formatters/cninetyninehexfloatf.rs index 85396a2aa..a5c51153e 100644 --- a/src/uucore/src/lib/features/tokenize/num_format/formatters/cninetyninehexfloatf.rs +++ b/src/uucore/src/lib/features/tokenize/num_format/formatters/cninetyninehexfloatf.rs @@ -81,9 +81,9 @@ fn get_primitive_hex( let suffix = Some({ let ind = if capitalized { "P" } else { "p" }; if mantissa >= 0 { - format!("{}+{}", ind, mantissa) + format!("{ind}+{mantissa}") } else { - format!("{}{}", ind, mantissa) + format!("{ind}{mantissa}") } }); FormatPrimitive { diff --git a/src/uucore/src/lib/features/tokenize/num_format/formatters/float_common.rs b/src/uucore/src/lib/features/tokenize/num_format/formatters/float_common.rs index ba8d5f01d..c277e60a6 100644 --- a/src/uucore/src/lib/features/tokenize/num_format/formatters/float_common.rs +++ b/src/uucore/src/lib/features/tokenize/num_format/formatters/float_common.rs @@ -226,7 +226,7 @@ pub fn get_primitive_dec( last_dec_place: usize, sci_mode: Option, ) -> FormatPrimitive { - let mut f: FormatPrimitive = Default::default(); + let mut f = FormatPrimitive::default(); // add negative sign section if initial_prefix.sign == -1 { @@ -304,11 +304,11 @@ pub fn get_primitive_dec( mantissa += 1; } f.suffix = Some(if mantissa >= 0 { - format!("{}+{:02}", si_ind, mantissa) + format!("{si_ind}+{mantissa:02}") } else { // negative sign is considered in format!s // leading zeroes - format!("{}{:03}", si_ind, mantissa) + format!("{si_ind}{mantissa:03}") }); f.pre_decimal = Some(pre_dec_draft); } else if dec_place_chg { diff --git a/src/uucore/src/lib/features/tokenize/num_format/formatters/intf.rs b/src/uucore/src/lib/features/tokenize/num_format/formatters/intf.rs index 0b93d134c..e0eb0ffd3 100644 --- a/src/uucore/src/lib/features/tokenize/num_format/formatters/intf.rs +++ b/src/uucore/src/lib/features/tokenize/num_format/formatters/intf.rs @@ -121,7 +121,7 @@ impl Intf { // get a FormatPrimitive of the maximum value for the field char // and given sign fn get_max(field_char: char, sign: i8) -> FormatPrimitive { - let mut fmt_primitive: FormatPrimitive = Default::default(); + let mut fmt_primitive = FormatPrimitive::default(); fmt_primitive.pre_decimal = Some(String::from(match field_char { 'd' | 'i' => match sign { 1 => "9223372036854775807", @@ -160,24 +160,24 @@ impl Intf { match field_char { 'i' | 'd' => match i64::from_str_radix(segment, radix_in as u32) { Ok(i) => { - let mut fmt_prim: FormatPrimitive = Default::default(); + let mut fmt_prim = FormatPrimitive::default(); if sign == -1 { fmt_prim.prefix = Some(String::from("-")); } - fmt_prim.pre_decimal = Some(format!("{}", i)); + fmt_prim.pre_decimal = Some(format!("{i}")); fmt_prim } Err(_) => Self::get_max(field_char, sign), }, _ => match u64::from_str_radix(segment, radix_in as u32) { Ok(u) => { - let mut fmt_prim: FormatPrimitive = Default::default(); + let mut fmt_prim = FormatPrimitive::default(); let u_f = if sign == -1 { u64::MAX - (u - 1) } else { u }; fmt_prim.pre_decimal = Some(match field_char { - 'X' => format!("{:X}", u_f), - 'x' => format!("{:x}", u_f), - 'o' => format!("{:o}", u_f), - _ => format!("{}", u_f), + 'X' => format!("{u_f:X}"), + 'x' => format!("{u_f:x}"), + 'o' => format!("{u_f:o}"), + _ => format!("{u_f}"), }); fmt_prim } @@ -235,7 +235,7 @@ impl Formatter for Intf { ) } else { // otherwise just do a straight string copy. - let mut fmt_prim: FormatPrimitive = Default::default(); + let mut fmt_prim = FormatPrimitive::default(); // this is here and not earlier because // zero doesn't get a sign, and conv_from_segment diff --git a/src/uucore/src/lib/features/tokenize/num_format/num_format.rs b/src/uucore/src/lib/features/tokenize/num_format/num_format.rs index e313fe19b..9aa97f811 100644 --- a/src/uucore/src/lib/features/tokenize/num_format/num_format.rs +++ b/src/uucore/src/lib/features/tokenize/num_format/num_format.rs @@ -218,22 +218,22 @@ pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option { tmp.pre_decimal = Some( - format!("{}", provided_num)); + format!("{provided_num}")); }, 'x' | 'X' => { tmp.pre_decimal = Some( - format!("{:x}", provided_num)); + format!("{provided_num:x}")); }, 'o' => { tmp.pre_decimal = Some( - format!("{:o}", provided_num)); + format!("{provided_num:o}")); }, 'e' | 'E' | 'g' | 'G' => { - let as_str = format!("{}", provided_num); + let as_str = format!("{provided_num}"); let initial_prefix = get_initial_prefix( &as_str, field.field_type @@ -243,7 +243,7 @@ pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option { tmp.pre_decimal = Some( - format!("{}", provided_num)); + format!("{provided_num}")); tmp.post_decimal = Some(String::from("0")); } } diff --git a/src/uucore/src/lib/features/tokenize/sub.rs b/src/uucore/src/lib/features/tokenize/sub.rs index 00fd51efd..9312040e3 100644 --- a/src/uucore/src/lib/features/tokenize/sub.rs +++ b/src/uucore/src/lib/features/tokenize/sub.rs @@ -31,7 +31,7 @@ pub enum SubError { impl Display for SubError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - Self::InvalidSpec(s) => write!(f, "%{}: invalid conversion specification", s), + Self::InvalidSpec(s) => write!(f, "%{s}: invalid conversion specification"), } } } diff --git a/src/uucore/src/lib/features/tokenize/unescaped_text.rs b/src/uucore/src/lib/features/tokenize/unescaped_text.rs index 59624f143..e659b11b5 100644 --- a/src/uucore/src/lib/features/tokenize/unescaped_text.rs +++ b/src/uucore/src/lib/features/tokenize/unescaped_text.rs @@ -88,12 +88,9 @@ impl UnescapedText { } else { 4 }; - let err_msg = format!( - "invalid universal character name {0}{1:02$x}", - preface, val, leading_zeros - ); + let err_msg = format!("invalid universal character name {preface}{val:0leading_zeros$x}"); if (val < 159 && (val != 36 && val != 64 && val != 96)) || (val > 55296 && val < 57343) { - println!("{}", err_msg); //todo stderr + println!("{err_msg}"); //todo stderr exit(EXIT_ERR); } } diff --git a/src/uucore/src/lib/features/utmpx.rs b/src/uucore/src/lib/features/utmpx.rs index b31aadc25..ee8744721 100644 --- a/src/uucore/src/lib/features/utmpx.rs +++ b/src/uucore/src/lib/features/utmpx.rs @@ -249,7 +249,7 @@ impl Utmpx { return Ok(if display.is_empty() { ai_canonname } else { - format!("{}:{}", ai_canonname, display) + format!("{ai_canonname}:{display}") }); } } diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index 5f6f21b77..8f1b2f3ec 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -439,9 +439,9 @@ impl Display for UIoError { &message }; if let Some(ctx) = &self.context { - write!(f, "{}: {}", ctx, message) + write!(f, "{ctx}: {message}") } else { - write!(f, "{}", message) + write!(f, "{message}") } } } diff --git a/src/uucore/src/lib/mods/quoting_style.rs b/src/uucore/src/lib/mods/quoting_style.rs index b07154139..3c8bf686a 100644 --- a/src/uucore/src/lib/mods/quoting_style.rs +++ b/src/uucore/src/lib/mods/quoting_style.rs @@ -276,8 +276,8 @@ pub fn escape_name(name: &OsStr, style: &QuotingStyle) -> String { .collect(); match quotes { - Quotes::Single => format!("'{}'", escaped_str), - Quotes::Double => format!("\"{}\"", escaped_str), + Quotes::Single => format!("'{escaped_str}'"), + Quotes::Double => format!("\"{escaped_str}\""), Quotes::None => escaped_str, } } @@ -304,8 +304,8 @@ pub fn escape_name(name: &OsStr, style: &QuotingStyle) -> String { }; match (must_quote | contains_quote_chars, quotes) { - (true, Quotes::Single) => format!("'{}'", escaped_str), - (true, Quotes::Double) => format!("\"{}\"", escaped_str), + (true, Quotes::Single) => format!("'{escaped_str}'"), + (true, Quotes::Double) => format!("\"{escaped_str}\""), _ => escaped_str, } } diff --git a/src/uucore/src/lib/parser/parse_size.rs b/src/uucore/src/lib/parser/parse_size.rs index 4ec8268de..d1e571e06 100644 --- a/src/uucore/src/lib/parser/parse_size.rs +++ b/src/uucore/src/lib/parser/parse_size.rs @@ -14,12 +14,33 @@ use crate::display::Quotable; /// /// The [`Parser::parse`] function performs the parse. #[derive(Default)] -pub struct Parser { +pub struct Parser<'parser> { /// Whether to treat the suffix "B" as meaning "bytes". pub capital_b_bytes: bool, + /// Whether to treat "b" as a "byte count" instead of "block" + pub b_byte_count: bool, + /// Whitelist for the suffix + pub allow_list: Option<&'parser [&'parser str]>, + /// Default unit when no suffix is provided + pub default_unit: Option<&'parser str>, } -impl Parser { +impl<'parser> Parser<'parser> { + pub fn with_allow_list(&mut self, allow_list: &'parser [&str]) -> &mut Self { + self.allow_list = Some(allow_list); + self + } + + pub fn with_default_unit(&mut self, default_unit: &'parser str) -> &mut Self { + self.default_unit = Some(default_unit); + self + } + + pub fn with_b_byte_count(&mut self, value: bool) -> &mut Self { + self.b_byte_count = value; + self + } + /// Parse a size string into a number of bytes. /// /// A size string comprises an integer and an optional unit. The unit @@ -66,7 +87,34 @@ impl Parser { // The lowercase "b" (used by `od`, `head`, `tail`, etc.) means // "block" and the Posix block size is 512. The uppercase "B" // means "byte". - let unit = &size[numeric_string.len()..]; + let mut unit: &str = &size[numeric_string.len()..]; + + if let Some(default_unit) = self.default_unit { + // Check if `unit` is empty then assigns `default_unit` to `unit` + if unit.is_empty() { + unit = default_unit; + } + } + + // Check if `b` is a byte count and remove `b` + if self.b_byte_count && unit.ends_with('b') { + // If `unit` = 'b' then return error + if numeric_string.is_empty() { + return Err(ParseSizeError::parse_failure(size)); + } + unit = &unit[0..unit.len() - 1]; + } + + if let Some(allow_list) = self.allow_list { + // Check if `unit` appears in `allow_list`, if not return error + if !allow_list.contains(&unit) && !unit.is_empty() { + if numeric_string.is_empty() { + return Err(ParseSizeError::parse_failure(size)); + } + return Err(ParseSizeError::invalid_suffix(size)); + } + } + let (base, exponent): (u128, u32) = match unit { "" => (1, 0), "B" if self.capital_b_bytes => (1, 0), @@ -148,7 +196,7 @@ impl fmt::Display for ParseSizeError { let s = match self { Self::InvalidSuffix(s) | Self::ParseFailure(s) | Self::SizeTooBig(s) => s, }; - write!(f, "{}", s) + write!(f, "{s}") } } @@ -244,21 +292,21 @@ mod tests { ]; for &(c, exp) in &suffixes { - let s = format!("2{}B", c); // KB + let s = format!("2{c}B"); // KB assert_eq!(Ok((2 * (1000_u128).pow(exp)) as u64), parse_size(&s)); - let s = format!("2{}", c); // K + let s = format!("2{c}"); // K assert_eq!(Ok((2 * (1024_u128).pow(exp)) as u64), parse_size(&s)); - let s = format!("2{}iB", c); // KiB + let s = format!("2{c}iB"); // KiB assert_eq!(Ok((2 * (1024_u128).pow(exp)) as u64), parse_size(&s)); let s = format!("2{}iB", c.to_lowercase()); // kiB assert_eq!(Ok((2 * (1024_u128).pow(exp)) as u64), parse_size(&s)); // suffix only - let s = format!("{}B", c); // KB + let s = format!("{c}B"); // KB assert_eq!(Ok(((1000_u128).pow(exp)) as u64), parse_size(&s)); - let s = format!("{}", c); // K + let s = format!("{c}"); // K assert_eq!(Ok(((1024_u128).pow(exp)) as u64), parse_size(&s)); - let s = format!("{}iB", c); // KiB + let s = format!("{c}iB"); // KiB assert_eq!(Ok(((1024_u128).pow(exp)) as u64), parse_size(&s)); let s = format!("{}iB", c.to_lowercase()); // kiB assert_eq!(Ok(((1024_u128).pow(exp)) as u64), parse_size(&s)); @@ -362,4 +410,44 @@ mod tests { assert_eq!(Ok(2_000_000_000_000_000), parse_size("2PB")); assert_eq!(Ok(2_000_000_000_000_000_000), parse_size("2EB")); } + + #[test] + fn parse_size_options() { + let mut parser = Parser::default(); + + parser + .with_allow_list(&["k", "K", "G", "MB", "M"]) + .with_default_unit("K"); + + assert_eq!(Ok(1024), parser.parse("1")); + assert_eq!(Ok(2 * 1024), parser.parse("2")); + assert_eq!(Ok(1000 * 1000), parser.parse("1MB")); + assert_eq!(Ok(1024 * 1024), parser.parse("1M")); + assert_eq!(Ok(1024 * 1024 * 1024), parser.parse("1G")); + + assert!(parser.parse("1T").is_err()); + assert!(parser.parse("1P").is_err()); + assert!(parser.parse("1E").is_err()); + + parser + .with_allow_list(&[ + "b", "k", "K", "m", "M", "MB", "g", "G", "t", "T", "P", "E", "Z", "Y", + ]) + .with_default_unit("K") + .with_b_byte_count(true); + + assert_eq!(Ok(1024), parser.parse("1")); + assert_eq!(Ok(2 * 1024), parser.parse("2")); + assert_eq!(Ok(1000 * 1000), parser.parse("1MB")); + assert_eq!(Ok(1024 * 1024), parser.parse("1M")); + assert_eq!(Ok(1024 * 1024 * 1024), parser.parse("1G")); + + assert_eq!(Ok(1), parser.parse("1b")); + assert_eq!(Ok(1024), parser.parse("1024b")); + assert_eq!(Ok(1024 * 1024 * 1024), parser.parse("1024Mb")); + + assert!(parser.parse("b").is_err()); + assert!(parser.parse("1B").is_err()); + assert!(parser.parse("B").is_err()); + } } diff --git a/src/uucore_procs/Cargo.toml b/src/uucore_procs/Cargo.toml index f721ae447..c61d63673 100644 --- a/src/uucore_procs/Cargo.toml +++ b/src/uucore_procs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uucore_procs" -version = "0.0.16" +version = "0.0.17" authors = ["Roy Ivy III "] license = "MIT" description = "uutils ~ 'uucore' proc-macros" diff --git a/src/uucore_procs/src/lib.rs b/src/uucore_procs/src/lib.rs index 89ac1a749..1a452254a 100644 --- a/src/uucore_procs/src/lib.rs +++ b/src/uucore_procs/src/lib.rs @@ -107,8 +107,8 @@ fn get_argument(input: &[TokenTree], index: usize, name: &str) -> String { // Multiply by two to ignore the `','` in between the arguments let string = match &input.get(index * 2) { Some(TokenTree::Literal(lit)) => lit.to_string(), - Some(_) => panic!("Argument {} should be a string literal.", index), - None => panic!("Missing argument at index {} for {}", index, name), + Some(_) => panic!("Argument {index} should be a string literal."), + None => panic!("Missing argument at index {index} for {name}"), }; string @@ -152,8 +152,7 @@ fn parse_help_section(section: &str, content: &str) -> String { // a nice error message. if content.lines().all(|l| !is_section_header(l, section)) { panic!( - "The section '{}' could not be found in the help file. Maybe it is spelled wrong?", - section + "The section '{section}' could not be found in the help file. Maybe it is spelled wrong?" ) } @@ -183,7 +182,7 @@ fn parse_usage(content: &str) -> String { // Replace the util name (assumed to be the first word) with "{}" // to be replaced with the runtime value later. if let Some((_util, args)) = l.split_once(' ') { - format!("{{}} {}\n", args) + format!("{{}} {args}\n") } else { "{}\n".to_string() } diff --git a/tests/by-util/test_base32.rs b/tests/by-util/test_base32.rs index bb51cda57..0634d114e 100644 --- a/tests/by-util/test_base32.rs +++ b/tests/by-util/test_base32.rs @@ -121,5 +121,5 @@ fn test_base32_file_not_found() { new_ucmd!() .arg("a.txt") .fails() - .stderr_only("base32: a.txt: No such file or directory"); + .stderr_only("base32: a.txt: No such file or directory\n"); } diff --git a/tests/by-util/test_base64.rs b/tests/by-util/test_base64.rs index a5478f6b7..6a2563b10 100644 --- a/tests/by-util/test_base64.rs +++ b/tests/by-util/test_base64.rs @@ -110,5 +110,5 @@ fn test_base64_file_not_found() { new_ucmd!() .arg("a.txt") .fails() - .stderr_only("base64: a.txt: No such file or directory"); + .stderr_only("base64: a.txt: No such file or directory\n"); } diff --git a/tests/by-util/test_basenc.rs b/tests/by-util/test_basenc.rs index ba9eed1cd..d2c58b785 100644 --- a/tests/by-util/test_basenc.rs +++ b/tests/by-util/test_basenc.rs @@ -7,10 +7,10 @@ fn test_z85_not_padded() { .args(&["--z85", "-d"]) .pipe_in("##########") .fails() - .stderr_only("basenc: error: invalid input"); + .stderr_only("basenc: error: invalid input\n"); new_ucmd!() .args(&["--z85"]) .pipe_in("123") .fails() - .stderr_only("basenc: error: invalid input (length must be multiple of 4 characters)"); + .stderr_only("basenc: error: invalid input (length must be multiple of 4 characters)\n"); } diff --git a/tests/by-util/test_cat.rs b/tests/by-util/test_cat.rs index dc45b3605..bef9e76e4 100644 --- a/tests/by-util/test_cat.rs +++ b/tests/by-util/test_cat.rs @@ -182,7 +182,7 @@ fn test_directory() { s.ucmd() .args(&["test_directory"]) .fails() - .stderr_is("cat: test_directory: Is a directory"); + .stderr_is("cat: test_directory: Is a directory\n"); } #[test] @@ -194,7 +194,7 @@ fn test_directory_and_file() { s.ucmd() .args(&["test_directory2", fixture]) .fails() - .stderr_is("cat: test_directory2: Is a directory") + .stderr_is("cat: test_directory2: Is a directory\n") .stdout_is_fixture(fixture); } } @@ -527,7 +527,7 @@ fn test_write_to_self() { .arg("second_file") .fails() .code_is(2) - .stderr_only("cat: first_file: input file is output file\ncat: first_file: input file is output file"); + .stderr_only("cat: first_file: input file is output file\ncat: first_file: input file is output file\n"); assert_eq!( s.fixtures.read("first_file"), diff --git a/tests/by-util/test_chgrp.rs b/tests/by-util/test_chgrp.rs index 1aa01d435..352ecb513 100644 --- a/tests/by-util/test_chgrp.rs +++ b/tests/by-util/test_chgrp.rs @@ -48,7 +48,7 @@ fn test_invalid_group() { .arg("__nosuchgroup__") .arg("/") .fails() - .stderr_is("chgrp: invalid group: '__nosuchgroup__'"); + .stderr_is("chgrp: invalid group: '__nosuchgroup__'\n"); } #[test] @@ -92,7 +92,7 @@ fn test_preserve_root() { .arg("-R") .arg("bin").arg(d) .fails() - .stderr_is("chgrp: it is dangerous to operate recursively on '/'\nchgrp: use --no-preserve-root to override this failsafe"); + .stderr_is("chgrp: it is dangerous to operate recursively on '/'\nchgrp: use --no-preserve-root to override this failsafe\n"); } } @@ -111,16 +111,16 @@ fn test_preserve_root_symlink() { .arg("-HR") .arg("bin").arg(file) .fails() - .stderr_is("chgrp: it is dangerous to operate recursively on '/'\nchgrp: use --no-preserve-root to override this failsafe"); + .stderr_is("chgrp: it is dangerous to operate recursively on '/'\nchgrp: use --no-preserve-root to override this failsafe\n"); } let (at, mut ucmd) = at_and_ucmd!(); at.symlink_file("///dev", file); ucmd.arg("--preserve-root") .arg("-HR") - .arg("bin").arg(format!(".//{}/..//..//../../", file)) + .arg("bin").arg(format!(".//{file}/..//..//../../")) .fails() - .stderr_is("chgrp: it is dangerous to operate recursively on '/'\nchgrp: use --no-preserve-root to override this failsafe"); + .stderr_is("chgrp: it is dangerous to operate recursively on '/'\nchgrp: use --no-preserve-root to override this failsafe\n"); let (at, mut ucmd) = at_and_ucmd!(); at.symlink_file("/", "__root__"); @@ -128,7 +128,7 @@ fn test_preserve_root_symlink() { .arg("-R") .arg("bin").arg("__root__/.") .fails() - .stderr_is("chgrp: it is dangerous to operate recursively on '/'\nchgrp: use --no-preserve-root to override this failsafe"); + .stderr_is("chgrp: it is dangerous to operate recursively on '/'\nchgrp: use --no-preserve-root to override this failsafe\n"); } #[test] @@ -143,7 +143,7 @@ fn test_reference() { .arg("--reference=/etc/passwd") .arg("/etc") .fails() - .stderr_is("chgrp: changing group of '/etc': Operation not permitted (os error 1)\nfailed to change group of '/etc' from root to root"); + .stderr_is("chgrp: changing group of '/etc': Operation not permitted (os error 1)\nfailed to change group of '/etc' from root to root\n"); } } @@ -270,7 +270,7 @@ fn test_permission_denied() { .arg(group.as_raw().to_string()) .arg("dir") .fails() - .stderr_only("chgrp: cannot access 'dir': Permission denied"); + .stderr_only("chgrp: cannot access 'dir': Permission denied\n"); } } @@ -289,7 +289,7 @@ fn test_subdir_permission_denied() { .arg(group.as_raw().to_string()) .arg("dir") .fails() - .stderr_only("chgrp: cannot access 'dir/subdir': Permission denied"); + .stderr_only("chgrp: cannot access 'dir/subdir': Permission denied\n"); } } diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index fd296ba89..5dfd1a714 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -216,7 +216,7 @@ fn test_chmod_ugoa() { .fails() .code_is(1) // spell-checker:disable-next-line - .stderr_is("chmod: file: new permissions are r-xrwxrwx, not r-xr-xr-x"); + .stderr_is("chmod: file: new permissions are r-xrwxrwx, not r-xr-xr-x\n"); assert_eq!( metadata(at.plus("file")).unwrap().permissions().mode(), 0o100577 @@ -314,7 +314,7 @@ fn test_permission_denied() { .arg("o=r") .arg("d") .fails() - .stderr_is("chmod: 'd/no-x/y': Permission denied"); + .stderr_is("chmod: 'd/no-x/y': Permission denied\n"); } #[test] @@ -341,7 +341,7 @@ fn test_chmod_recursive() { .arg("a") .arg("z") .fails() - .stderr_is("chmod: Permission denied"); + .stderr_is("chmod: Permission denied\n"); assert_eq!(at.metadata("z/y").permissions().mode(), 0o100444); assert_eq!(at.metadata("a/a").permissions().mode(), 0o100444); @@ -414,10 +414,9 @@ fn test_chmod_symlink_non_existing_file() { let non_existing = "test_chmod_symlink_non_existing_file"; let test_symlink = "test_chmod_symlink_non_existing_file_symlink"; let expected_stdout = &format!( - "failed to change mode of '{}' from 0000 (---------) to 0000 (---------)", - test_symlink + "failed to change mode of '{test_symlink}' from 0000 (---------) to 0000 (---------)" ); - let expected_stderr = &format!("cannot operate on dangling symlink '{}'", test_symlink); + let expected_stderr = &format!("cannot operate on dangling symlink '{test_symlink}'"); at.symlink_file(non_existing, test_symlink); @@ -455,10 +454,7 @@ fn test_chmod_symlink_non_existing_file_recursive() { let test_directory = "test_chmod_symlink_non_existing_file_directory"; at.mkdir(test_directory); - at.symlink_file( - non_existing, - &format!("{}/{}", test_directory, test_symlink), - ); + at.symlink_file(non_existing, &format!("{test_directory}/{test_symlink}")); // this should succeed scene @@ -472,8 +468,7 @@ fn test_chmod_symlink_non_existing_file_recursive() { let expected_stdout = &format!( // spell-checker:disable-next-line - "mode of '{}' retained as 0755 (rwxr-xr-x)", - test_directory + "mode of '{test_directory}' retained as 0755 (rwxr-xr-x)" ); // '-v': this should succeed without stderr diff --git a/tests/by-util/test_chown.rs b/tests/by-util/test_chown.rs index 716e7f48f..5237a7cf7 100644 --- a/tests/by-util/test_chown.rs +++ b/tests/by-util/test_chown.rs @@ -138,7 +138,7 @@ fn test_chown_only_owner_colon() { scene .ucmd() - .arg(format!("{}:", user_name)) + .arg(format!("{user_name}:")) .arg("--verbose") .arg(file1) .succeeds() @@ -146,7 +146,7 @@ fn test_chown_only_owner_colon() { scene .ucmd() - .arg(format!("{}.", user_name)) + .arg(format!("{user_name}.")) .arg("--verbose") .arg(file1) .succeeds() @@ -244,7 +244,7 @@ fn test_chown_owner_group() { let result = scene .ucmd() - .arg(format!("{}:{}", user_name, group_name)) + .arg(format!("{user_name}:{group_name}")) .arg("--verbose") .arg(file1) .run(); @@ -309,7 +309,7 @@ fn test_chown_various_input() { let result = scene .ucmd() - .arg(format!("{}:{}", user_name, group_name)) + .arg(format!("{user_name}:{group_name}")) .arg("--verbose") .arg(file1) .run(); @@ -321,7 +321,7 @@ fn test_chown_various_input() { // check that username.groupname is understood let result = scene .ucmd() - .arg(format!("{}.{}", user_name, group_name)) + .arg(format!("{user_name}.{group_name}")) .arg("--verbose") .arg(file1) .run(); @@ -365,7 +365,7 @@ fn test_chown_only_group() { let result = scene .ucmd() - .arg(format!(":{}", user_name)) + .arg(format!(":{user_name}")) .arg("--verbose") .arg(file1) .run(); @@ -442,14 +442,14 @@ fn test_chown_fail_id() { scene .ucmd() - .arg(format!("{}:", user_id)) + .arg(format!("{user_id}:")) .arg(file1) .fails() .stderr_contains("invalid spec"); scene .ucmd() - .arg(format!("{}.", user_id)) + .arg(format!("{user_id}.")) .arg(file1) .fails() .stderr_contains("invalid spec"); @@ -499,7 +499,7 @@ fn test_chown_only_group_id() { let result = scene .ucmd() - .arg(format!(":{}", group_id)) + .arg(format!(":{group_id}")) .arg("--verbose") .arg(file1) .run(); @@ -570,7 +570,7 @@ fn test_chown_owner_group_id() { let result = scene .ucmd() - .arg(format!("{}:{}", user_id, group_id)) + .arg(format!("{user_id}:{group_id}")) .arg("--verbose") .arg(file1) .run(); @@ -583,7 +583,7 @@ fn test_chown_owner_group_id() { let result = scene .ucmd() - .arg(format!("{}.{}", user_id, group_id)) + .arg(format!("{user_id}.{group_id}")) .arg("--verbose") .arg(file1) .run(); @@ -631,7 +631,7 @@ fn test_chown_owner_group_mix() { let result = scene .ucmd() - .arg(format!("{}:{}", user_id, group_name)) + .arg(format!("{user_id}:{group_name}")) .arg("--verbose") .arg(file1) .run(); diff --git a/tests/by-util/test_chroot.rs b/tests/by-util/test_chroot.rs index b53ca4e5b..c7e786f93 100644 --- a/tests/by-util/test_chroot.rs +++ b/tests/by-util/test_chroot.rs @@ -43,7 +43,7 @@ fn test_no_such_directory() { ucmd.arg("a") .fails() - .stderr_is("chroot: cannot change root directory to 'a': no such directory") + .stderr_is("chroot: cannot change root directory to 'a': no such directory\n") .code_is(125); } @@ -94,7 +94,7 @@ fn test_preference_of_userspec() { .arg("fake") .arg("-G") .arg("ABC,DEF") - .arg(format!("--userspec={}:{}", username, group_name)) + .arg(format!("--userspec={username}:{group_name}")) .fails(); result.code_is(125); @@ -113,10 +113,7 @@ fn test_default_shell() { at.mkdir(dir); let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string()); - let expected = format!( - "chroot: failed to run command '{}': No such file or directory", - shell - ); + let expected = format!("chroot: failed to run command '{shell}': No such file or directory"); if let Ok(result) = run_ucmd_as_root(&ts, &[dir]) { result.stderr_contains(expected); diff --git a/tests/by-util/test_comm.rs b/tests/by-util/test_comm.rs index 9fc175c7f..93f81f089 100644 --- a/tests/by-util/test_comm.rs +++ b/tests/by-util/test_comm.rs @@ -179,5 +179,5 @@ fn test_no_such_file() { new_ucmd!() .args(&["bogus_file_1", "bogus_file_2"]) .fails() - .stderr_only("comm: bogus_file_1: No such file or directory"); + .stderr_only("comm: bogus_file_1: No such file or directory\n"); } diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 4406f5997..e6e8a6ba2 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -22,9 +22,7 @@ use filetime::FileTime; use rlimit::Resource; #[cfg(any(target_os = "linux", target_os = "android"))] use std::fs as std_fs; -#[cfg(not(target_os = "freebsd"))] use std::thread::sleep; -#[cfg(not(target_os = "freebsd"))] use std::time::Duration; static TEST_EXISTING_FILE: &str = "existing_file.txt"; @@ -93,7 +91,7 @@ fn test_cp_existing_target() { assert_eq!(at.read(TEST_EXISTING_FILE), "Hello, World!\n"); // No backup should have been created - assert!(!at.file_exists(&format!("{}~", TEST_EXISTING_FILE))); + assert!(!at.file_exists(&format!("{TEST_EXISTING_FILE}~"))); } #[test] @@ -213,7 +211,7 @@ fn test_cp_target_directory_is_file() { .arg(TEST_HOW_ARE_YOU_SOURCE) .arg(TEST_HELLO_WORLD_SOURCE) .fails() - .stderr_contains(format!("'{}' is not a directory", TEST_HOW_ARE_YOU_SOURCE)); + .stderr_contains(format!("'{TEST_HOW_ARE_YOU_SOURCE}' is not a directory")); } #[test] @@ -376,7 +374,7 @@ fn test_cp_arg_backup() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")), "How are you?\n" ); } @@ -392,7 +390,7 @@ fn test_cp_arg_backup_with_other_args() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")), "How are you?\n" ); } @@ -408,7 +406,7 @@ fn test_cp_arg_backup_arg_first() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")), "How are you?\n" ); } @@ -426,7 +424,7 @@ fn test_cp_arg_suffix() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}.bak", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}.bak")), "How are you?\n" ); } @@ -444,7 +442,7 @@ fn test_cp_arg_suffix_hyphen_value() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}-v", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}-v")), "How are you?\n" ); } @@ -463,7 +461,7 @@ fn test_cp_custom_backup_suffix_via_env() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}{}", TEST_HOW_ARE_YOU_SOURCE, suffix)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}{suffix}")), "How are you?\n" ); } @@ -480,7 +478,7 @@ fn test_cp_backup_numbered_with_t() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}.~1~")), "How are you?\n" ); } @@ -497,7 +495,7 @@ fn test_cp_backup_numbered() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}.~1~")), "How are you?\n" ); } @@ -514,7 +512,7 @@ fn test_cp_backup_existing() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")), "How are you?\n" ); } @@ -531,7 +529,7 @@ fn test_cp_backup_nil() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")), "How are you?\n" ); } @@ -539,7 +537,7 @@ fn test_cp_backup_nil() { #[test] fn test_cp_numbered_if_existing_backup_existing() { let (at, mut ucmd) = at_and_ucmd!(); - let existing_backup = &format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE); + let existing_backup = &format!("{TEST_HOW_ARE_YOU_SOURCE}.~1~"); at.touch(existing_backup); ucmd.arg("--backup=existing") @@ -551,7 +549,7 @@ fn test_cp_numbered_if_existing_backup_existing() { assert!(at.file_exists(TEST_HOW_ARE_YOU_SOURCE)); assert!(at.file_exists(existing_backup)); assert_eq!( - at.read(&format!("{}.~2~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}.~2~")), "How are you?\n" ); } @@ -559,7 +557,7 @@ fn test_cp_numbered_if_existing_backup_existing() { #[test] fn test_cp_numbered_if_existing_backup_nil() { let (at, mut ucmd) = at_and_ucmd!(); - let existing_backup = &format!("{}.~1~", TEST_HOW_ARE_YOU_SOURCE); + let existing_backup = &format!("{TEST_HOW_ARE_YOU_SOURCE}.~1~"); at.touch(existing_backup); ucmd.arg("--backup=nil") @@ -571,7 +569,7 @@ fn test_cp_numbered_if_existing_backup_nil() { assert!(at.file_exists(TEST_HOW_ARE_YOU_SOURCE)); assert!(at.file_exists(existing_backup)); assert_eq!( - at.read(&format!("{}.~2~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}.~2~")), "How are you?\n" ); } @@ -588,7 +586,7 @@ fn test_cp_backup_simple() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")), "How are you?\n" ); } @@ -596,15 +594,14 @@ fn test_cp_backup_simple() { #[test] fn test_cp_backup_simple_protect_source() { let (at, mut ucmd) = at_and_ucmd!(); - let source = format!("{}~", TEST_HELLO_WORLD_SOURCE); + let source = format!("{TEST_HELLO_WORLD_SOURCE}~"); at.touch(&source); ucmd.arg("--backup=simple") .arg(&source) .arg(TEST_HELLO_WORLD_SOURCE) .fails() .stderr_only(format!( - "cp: backing up '{}' might destroy source; '{}' not copied", - TEST_HELLO_WORLD_SOURCE, source, + "cp: backing up '{TEST_HELLO_WORLD_SOURCE}' might destroy source; '{source}' not copied\n", )); assert_eq!(at.read(TEST_HELLO_WORLD_SOURCE), "Hello, World!\n"); @@ -623,7 +620,7 @@ fn test_cp_backup_never() { assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); assert_eq!( - at.read(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE)), + at.read(&format!("{TEST_HOW_ARE_YOU_SOURCE}~")), "How are you?\n" ); } @@ -639,7 +636,7 @@ fn test_cp_backup_none() { .no_stderr(); assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); - assert!(!at.file_exists(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE))); + assert!(!at.file_exists(&format!("{TEST_HOW_ARE_YOU_SOURCE}~"))); } #[test] @@ -653,7 +650,7 @@ fn test_cp_backup_off() { .no_stderr(); assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "Hello, World!\n"); - assert!(!at.file_exists(&format!("{}~", TEST_HOW_ARE_YOU_SOURCE))); + assert!(!at.file_exists(&format!("{TEST_HOW_ARE_YOU_SOURCE}~"))); } #[test] @@ -803,7 +800,7 @@ fn test_cp_strip_trailing_slashes() { //using --strip-trailing-slashes option ucmd.arg("--strip-trailing-slashes") - .arg(format!("{}/", TEST_HELLO_WORLD_SOURCE)) + .arg(format!("{TEST_HELLO_WORLD_SOURCE}/")) .arg(TEST_HELLO_WORLD_DEST) .succeeds(); @@ -822,8 +819,7 @@ fn test_cp_parents() { assert_eq!( at.read(&format!( - "{}/{}", - TEST_COPY_TO_FOLDER, TEST_COPY_FROM_FOLDER_FILE + "{TEST_COPY_TO_FOLDER}/{TEST_COPY_FROM_FOLDER_FILE}" )), "Hello, World!\n" ); @@ -841,16 +837,12 @@ fn test_cp_parents_multiple_files() { assert_eq!( at.read(&format!( - "{}/{}", - TEST_COPY_TO_FOLDER, TEST_COPY_FROM_FOLDER_FILE + "{TEST_COPY_TO_FOLDER}/{TEST_COPY_FROM_FOLDER_FILE}" )), "Hello, World!\n" ); assert_eq!( - at.read(&format!( - "{}/{}", - TEST_COPY_TO_FOLDER, TEST_HOW_ARE_YOU_SOURCE - )), + at.read(&format!("{TEST_COPY_TO_FOLDER}/{TEST_HOW_ARE_YOU_SOURCE}")), "How are you?\n" ); } @@ -907,6 +899,91 @@ fn test_cp_preserve_no_args() { } } +#[test] +fn test_cp_preserve_all() { + let (at, mut ucmd) = at_and_ucmd!(); + let src_file = "a"; + let dst_file = "b"; + + // Prepare the source file + at.touch(src_file); + #[cfg(unix)] + at.set_mode(src_file, 0o0500); + + // TODO: create a destination that does not allow copying of xattr and context + // Copy + ucmd.arg(src_file) + .arg(dst_file) + .arg("--preserve=all") + .succeeds(); + + #[cfg(all(unix, not(target_os = "freebsd")))] + { + // Assert that the mode, ownership, and timestamps are preserved + // NOTICE: the ownership is not modified on the src file, because that requires root permissions + let metadata_src = at.metadata(src_file); + let metadata_dst = at.metadata(dst_file); + assert_metadata_eq!(metadata_src, metadata_dst); + } +} + +#[test] +#[cfg(all(unix, not(target_os = "android")))] +fn test_cp_preserve_xattr() { + let (at, mut ucmd) = at_and_ucmd!(); + let src_file = "a"; + let dst_file = "b"; + + // Prepare the source file + at.touch(src_file); + #[cfg(unix)] + at.set_mode(src_file, 0o0500); + + // Sleep so that the time stats are different + sleep(Duration::from_secs(1)); + + // TODO: create a destination that does not allow copying of xattr and context + // Copy + ucmd.arg(src_file) + .arg(dst_file) + .arg("--preserve=xattr") + .succeeds(); + + // FIXME: macos copy keeps the original mtime + #[cfg(not(any(target_os = "freebsd", target_os = "macos")))] + { + // Assert that the mode, ownership, and timestamps are *NOT* preserved + // NOTICE: the ownership is not modified on the src file, because that requires root permissions + let metadata_src = at.metadata(src_file); + let metadata_dst = at.metadata(dst_file); + assert_ne!(metadata_src.mtime(), metadata_dst.mtime()); + // TODO: verify access time as well. It shouldn't change, however, it does change in this test. + } +} + +#[test] +#[cfg(all(target_os = "linux", not(feature = "feat_selinux")))] +fn test_cp_preserve_all_context_fails_on_non_selinux() { + new_ucmd!() + .arg(TEST_COPY_FROM_FOLDER_FILE) + .arg(TEST_HELLO_WORLD_DEST) + .arg("--preserve=all,context") + .fails(); +} + +#[test] +#[cfg(any(target_os = "android"))] +fn test_cp_preserve_xattr_fails_on_android() { + // Because of the SELinux extended attributes used on Android, trying to copy extended + // attributes has to fail in this case, since we specify `--preserve=xattr` and this puts it + // into the required attributes + new_ucmd!() + .arg(TEST_COPY_FROM_FOLDER_FILE) + .arg(TEST_HELLO_WORLD_DEST) + .arg("--preserve=xattr") + .fails(); +} + #[test] // For now, disable the test on Windows. Symlinks aren't well support on Windows. // It works on Unix for now and it works locally when run from a powershell @@ -1267,7 +1344,7 @@ fn test_cp_no_preserve_timestamps() { let result = scene2.cmd("ls").arg("-al").arg(at.subdir).run(); println!("ls dest {}", result.stdout_str()); - println!("creation {:?} / {:?}", creation, creation2); + println!("creation {creation:?} / {creation2:?}"); assert_ne!(creation, creation2); let res = creation.elapsed().unwrap() - creation2.elapsed().unwrap(); @@ -1441,7 +1518,7 @@ fn test_cp_reflink_insufficient_permission() { .arg("unreadable") .arg(TEST_EXISTING_FILE) .fails() - .stderr_only("cp: 'unreadable' -> 'existing_file.txt': Permission denied (os error 13)"); + .stderr_only("cp: 'unreadable' -> 'existing_file.txt': Permission denied (os error 13)\n"); } #[cfg(any(target_os = "linux", target_os = "android"))] @@ -1780,9 +1857,9 @@ fn test_copy_through_just_created_symlink() { .arg("c") .fails() .stderr_only(if cfg!(not(target_os = "windows")) { - "cp: will not copy 'b/1' through just-created symlink 'c/1'" + "cp: will not copy 'b/1' through just-created symlink 'c/1'\n" } else { - "cp: will not copy 'b/1' through just-created symlink 'c\\1'" + "cp: will not copy 'b/1' through just-created symlink 'c\\1'\n" }); if create_t { assert_eq!(at.read("a/1"), "world"); @@ -1798,7 +1875,7 @@ fn test_copy_through_dangling_symlink() { ucmd.arg("file") .arg("target") .fails() - .stderr_only("cp: not writing through dangling symlink 'target'"); + .stderr_only("cp: not writing through dangling symlink 'target'\n"); } #[test] @@ -1850,7 +1927,7 @@ fn test_copy_through_dangling_symlink_no_dereference_2() { at.symlink_file("nonexistent", "target"); ucmd.args(&["-P", "file", "target"]) .fails() - .stderr_only("cp: not writing through dangling symlink 'target'"); + .stderr_only("cp: not writing through dangling symlink 'target'\n"); } /// Test that copy through a dangling symbolic link fails, even with --force. @@ -1862,7 +1939,7 @@ fn test_copy_through_dangling_symlink_force() { at.symlink_file("no-such-file", "dest"); ucmd.args(&["--force", "src", "dest"]) .fails() - .stderr_only("cp: not writing through dangling symlink 'dest'"); + .stderr_only("cp: not writing through dangling symlink 'dest'\n"); assert!(!at.file_exists("dest")); } @@ -1875,7 +1952,7 @@ fn test_cp_archive_on_nonexistent_file() { .arg(TEST_EXISTING_FILE) .fails() .stderr_only( - "cp: cannot stat 'nonexistent_file.txt': No such file or directory (os error 2)", + "cp: cannot stat 'nonexistent_file.txt': No such file or directory (os error 2)\n", ); } @@ -1960,7 +2037,7 @@ fn test_cp_dir_vs_file() { .arg(TEST_COPY_FROM_FOLDER) .arg(TEST_EXISTING_FILE) .fails() - .stderr_only("cp: cannot overwrite non-directory with directory"); + .stderr_only("cp: cannot overwrite non-directory with directory\n"); } #[test] @@ -2202,9 +2279,9 @@ fn test_copy_directory_to_itself_disallowed() { let (at, mut ucmd) = at_and_ucmd!(); at.mkdir("d"); #[cfg(not(windows))] - let expected = "cp: cannot copy a directory, 'd', into itself, 'd/d'"; + let expected = "cp: cannot copy a directory, 'd', into itself, 'd/d'\n"; #[cfg(windows)] - let expected = "cp: cannot copy a directory, 'd', into itself, 'd\\d'"; + let expected = "cp: cannot copy a directory, 'd', into itself, 'd\\d'\n"; ucmd.args(&["-R", "d", "d"]).fails().stderr_only(expected); } @@ -2216,9 +2293,9 @@ fn test_copy_nested_directory_to_itself_disallowed() { at.mkdir("a/b"); at.mkdir("a/b/c"); #[cfg(not(windows))] - let expected = "cp: cannot copy a directory, 'a/b', into itself, 'a/b/c/b'"; + let expected = "cp: cannot copy a directory, 'a/b', into itself, 'a/b/c/b'\n"; #[cfg(windows)] - let expected = "cp: cannot copy a directory, 'a/b', into itself, 'a/b/c\\b'"; + let expected = "cp: cannot copy a directory, 'a/b', into itself, 'a/b/c\\b'\n"; ucmd.args(&["-R", "a/b", "a/b/c"]) .fails() .stderr_only(expected); @@ -2277,8 +2354,8 @@ fn test_copy_dir_preserve_permissions_inaccessible_file() { // V V V V ucmd.args(&["-p", "-R", "d1", "d2"]) .fails() - .status_code(1) - .stderr_only("cp: cannot open 'd1/f' for reading: Permission denied"); + .code_is(1) + .stderr_only("cp: cannot open 'd1/f' for reading: Permission denied\n"); assert!(at.dir_exists("d2")); assert!(!at.file_exists("d2/f")); @@ -2295,7 +2372,7 @@ fn test_same_file_backup() { at.touch("f"); ucmd.args(&["--backup", "f", "f"]) .fails() - .stderr_only("cp: 'f' and 'f' are the same file"); + .stderr_only("cp: 'f' and 'f' are the same file\n"); assert!(!at.file_exists("f~")); } @@ -2307,7 +2384,7 @@ fn test_same_file_force() { at.touch("f"); ucmd.args(&["--force", "f", "f"]) .fails() - .stderr_only("cp: 'f' and 'f' are the same file"); + .stderr_only("cp: 'f' and 'f' are the same file\n"); assert!(!at.file_exists("f~")); } diff --git a/tests/by-util/test_csplit.rs b/tests/by-util/test_csplit.rs index d44b4aca5..771cd5f81 100644 --- a/tests/by-util/test_csplit.rs +++ b/tests/by-util/test_csplit.rs @@ -4,7 +4,7 @@ use glob::glob; /// Returns a string of numbers with the given range, each on a new line. /// The upper bound is not included. fn generate(from: u32, to: u32) -> String { - (from..to).fold(String::new(), |acc, v| format!("{}{}\n", acc, v)) + (from..to).fold(String::new(), |acc, v| format!("{acc}{v}\n")) } #[test] @@ -213,7 +213,7 @@ fn test_up_to_match_repeat_over() { ucmd.args(&["numbers50.txt", "/9$/", "{50}"]) .fails() .stdout_is("16\n29\n30\n30\n30\n6\n") - .stderr_is("csplit: '/9$/': match not found on repetition 5"); + .stderr_is("csplit: '/9$/': match not found on repetition 5\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -224,7 +224,7 @@ fn test_up_to_match_repeat_over() { ucmd.args(&["numbers50.txt", "/9$/", "{50}", "-k"]) .fails() .stdout_is("16\n29\n30\n30\n30\n6\n") - .stderr_is("csplit: '/9$/': match not found on repetition 5"); + .stderr_is("csplit: '/9$/': match not found on repetition 5\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -370,7 +370,7 @@ fn test_option_keep() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["-k", "numbers50.txt", "/20/", "/nope/"]) .fails() - .stderr_is("csplit: '/nope/': match not found") + .stderr_is("csplit: '/nope/': match not found\n") .stdout_is("48\n93\n"); let count = glob(&at.plus_as_string("xx*")) @@ -546,7 +546,7 @@ fn test_up_to_match_context_overflow() { ucmd.args(&["numbers50.txt", "/45/+10"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/45/+10': line number out of range"); + .stderr_is("csplit: '/45/+10': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -557,7 +557,7 @@ fn test_up_to_match_context_overflow() { ucmd.args(&["numbers50.txt", "/45/+10", "-k"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/45/+10': line number out of range"); + .stderr_is("csplit: '/45/+10': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -572,7 +572,7 @@ fn test_skip_to_match_context_underflow() { ucmd.args(&["numbers50.txt", "%5%-10"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '%5%-10': line number out of range"); + .stderr_is("csplit: '%5%-10': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -583,7 +583,7 @@ fn test_skip_to_match_context_underflow() { ucmd.args(&["numbers50.txt", "%5%-10", "-k"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '%5%-10': line number out of range"); + .stderr_is("csplit: '%5%-10': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -597,7 +597,7 @@ fn test_skip_to_match_context_overflow() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%45%+10"]) .fails() - .stderr_only("csplit: '%45%+10': line number out of range"); + .stderr_is("csplit: '%45%+10': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -607,7 +607,7 @@ fn test_skip_to_match_context_overflow() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%45%+10", "-k"]) .fails() - .stderr_only("csplit: '%45%+10': line number out of range"); + .stderr_only("csplit: '%45%+10': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -621,7 +621,7 @@ fn test_up_to_no_match1() { ucmd.args(&["numbers50.txt", "/4/", "/nope/"]) .fails() .stdout_is("6\n135\n") - .stderr_is("csplit: '/nope/': match not found"); + .stderr_is("csplit: '/nope/': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -632,7 +632,7 @@ fn test_up_to_no_match1() { ucmd.args(&["numbers50.txt", "/4/", "/nope/", "-k"]) .fails() .stdout_is("6\n135\n") - .stderr_is("csplit: '/nope/': match not found"); + .stderr_is("csplit: '/nope/': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -648,7 +648,7 @@ fn test_up_to_no_match2() { ucmd.args(&["numbers50.txt", "/4/", "/nope/", "{50}"]) .fails() .stdout_is("6\n135\n") - .stderr_is("csplit: '/nope/': match not found"); + .stderr_is("csplit: '/nope/': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -659,7 +659,7 @@ fn test_up_to_no_match2() { ucmd.args(&["numbers50.txt", "/4/", "/nope/", "{50}", "-k"]) .fails() .stdout_is("6\n135\n") - .stderr_is("csplit: '/nope/': match not found"); + .stderr_is("csplit: '/nope/': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -675,7 +675,7 @@ fn test_up_to_no_match3() { ucmd.args(&["numbers50.txt", "/0$/", "{50}"]) .fails() .stdout_is("18\n30\n30\n30\n30\n3\n") - .stderr_is("csplit: '/0$/': match not found on repetition 5"); + .stderr_is("csplit: '/0$/': match not found on repetition 5\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -686,7 +686,7 @@ fn test_up_to_no_match3() { ucmd.args(&["numbers50.txt", "/0$/", "{50}", "-k"]) .fails() .stdout_is("18\n30\n30\n30\n30\n3\n") - .stderr_is("csplit: '/0$/': match not found on repetition 5"); + .stderr_is("csplit: '/0$/': match not found on repetition 5\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -706,7 +706,7 @@ fn test_up_to_no_match4() { ucmd.args(&["numbers50.txt", "/nope/", "/4/"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/nope/': match not found"); + .stderr_is("csplit: '/nope/': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -717,7 +717,7 @@ fn test_up_to_no_match4() { ucmd.args(&["numbers50.txt", "/nope/", "/4/", "-k"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/nope/': match not found"); + .stderr_is("csplit: '/nope/': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -746,7 +746,7 @@ fn test_up_to_no_match6() { ucmd.args(&["numbers50.txt", "/nope/-5"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/nope/-5': match not found"); + .stderr_is("csplit: '/nope/-5': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -757,7 +757,7 @@ fn test_up_to_no_match6() { ucmd.args(&["numbers50.txt", "/nope/-5", "-k"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/nope/-5': match not found"); + .stderr_is("csplit: '/nope/-5': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -772,7 +772,7 @@ fn test_up_to_no_match7() { ucmd.args(&["numbers50.txt", "/nope/+5"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/nope/+5': match not found"); + .stderr_is("csplit: '/nope/+5': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -783,7 +783,7 @@ fn test_up_to_no_match7() { ucmd.args(&["numbers50.txt", "/nope/+5", "-k"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/nope/+5': match not found"); + .stderr_is("csplit: '/nope/+5': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -797,7 +797,7 @@ fn test_skip_to_no_match1() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%nope%"]) .fails() - .stderr_only("csplit: '%nope%': match not found"); + .stderr_only("csplit: '%nope%': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -810,7 +810,7 @@ fn test_skip_to_no_match2() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%nope%", "{50}"]) .fails() - .stderr_only("csplit: '%nope%': match not found"); + .stderr_only("csplit: '%nope%': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -823,7 +823,7 @@ fn test_skip_to_no_match3() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%0$%", "{50}"]) .fails() - .stderr_only("csplit: '%0$%': match not found on repetition 5"); + .stderr_only("csplit: '%0$%': match not found on repetition 5\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -836,7 +836,7 @@ fn test_skip_to_no_match4() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%nope%", "/4/"]) .fails() - .stderr_only("csplit: '%nope%': match not found"); + .stderr_only("csplit: '%nope%': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -863,7 +863,7 @@ fn test_skip_to_no_match6() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%nope%-5"]) .fails() - .stderr_only("csplit: '%nope%-5': match not found"); + .stderr_only("csplit: '%nope%-5': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -876,7 +876,7 @@ fn test_skip_to_no_match7() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%nope%+5"]) .fails() - .stderr_only("csplit: '%nope%+5': match not found"); + .stderr_only("csplit: '%nope%+5': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -889,7 +889,7 @@ fn test_no_match() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "%nope%"]) .fails() - .stderr_only("csplit: '%nope%': match not found"); + .stderr_only("csplit: '%nope%': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -900,7 +900,7 @@ fn test_no_match() { ucmd.args(&["numbers50.txt", "/nope/"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '/nope/': match not found"); + .stderr_is("csplit: '/nope/': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -997,7 +997,7 @@ fn test_too_small_line_num_repeat() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "/20/", "10", "{*}"]) .fails() - .stderr_is("csplit: '10': line number out of range on repetition 5") + .stderr_is("csplit: '10': line number out of range on repetition 5\n") .stdout_is("48\n0\n0\n30\n30\n30\n3\n"); let count = glob(&at.plus_as_string("xx*")) @@ -1008,7 +1008,7 @@ fn test_too_small_line_num_repeat() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "/20/", "10", "{*}", "-k"]) .fails() - .stderr_is("csplit: '10': line number out of range on repetition 5") + .stderr_is("csplit: '10': line number out of range on repetition 5\n") .stdout_is("48\n0\n0\n30\n30\n30\n3\n"); let count = glob(&at.plus_as_string("xx*")) @@ -1030,7 +1030,7 @@ fn test_line_num_out_of_range1() { ucmd.args(&["numbers50.txt", "100"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '100': line number out of range"); + .stderr_is("csplit: '100': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1041,7 +1041,7 @@ fn test_line_num_out_of_range1() { ucmd.args(&["numbers50.txt", "100", "-k"]) .fails() .stdout_is("141\n") - .stderr_is("csplit: '100': line number out of range"); + .stderr_is("csplit: '100': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1056,7 +1056,7 @@ fn test_line_num_out_of_range2() { ucmd.args(&["numbers50.txt", "10", "100"]) .fails() .stdout_is("18\n123\n") - .stderr_is("csplit: '100': line number out of range"); + .stderr_is("csplit: '100': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1067,7 +1067,7 @@ fn test_line_num_out_of_range2() { ucmd.args(&["numbers50.txt", "10", "100", "-k"]) .fails() .stdout_is("18\n123\n") - .stderr_is("csplit: '100': line number out of range"); + .stderr_is("csplit: '100': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1083,7 +1083,7 @@ fn test_line_num_out_of_range3() { ucmd.args(&["numbers50.txt", "40", "{2}"]) .fails() .stdout_is("108\n33\n") - .stderr_is("csplit: '40': line number out of range on repetition 1"); + .stderr_is("csplit: '40': line number out of range on repetition 1\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1094,7 +1094,7 @@ fn test_line_num_out_of_range3() { ucmd.args(&["numbers50.txt", "40", "{2}", "-k"]) .fails() .stdout_is("108\n33\n") - .stderr_is("csplit: '40': line number out of range on repetition 1"); + .stderr_is("csplit: '40': line number out of range on repetition 1\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1110,7 +1110,7 @@ fn test_line_num_out_of_range4() { ucmd.args(&["numbers50.txt", "40", "{*}"]) .fails() .stdout_is("108\n33\n") - .stderr_is("csplit: '40': line number out of range on repetition 1"); + .stderr_is("csplit: '40': line number out of range on repetition 1\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1121,7 +1121,7 @@ fn test_line_num_out_of_range4() { ucmd.args(&["numbers50.txt", "40", "{*}", "-k"]) .fails() .stdout_is("108\n33\n") - .stderr_is("csplit: '40': line number out of range on repetition 1"); + .stderr_is("csplit: '40': line number out of range on repetition 1\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1137,7 +1137,7 @@ fn test_skip_to_match_negative_offset_before_a_match() { ucmd.args(&["numbers50.txt", "/20/-10", "/15/"]) .fails() .stdout_is("18\n123\n") - .stderr_is("csplit: '/15/': match not found"); + .stderr_is("csplit: '/15/': match not found\n"); let count = glob(&at.plus_as_string("xx*")) .expect("there should be splits created") @@ -1182,7 +1182,7 @@ fn test_corner_case2() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "/10/-5", "/10/"]) .fails() - .stderr_is("csplit: '/10/': match not found") + .stderr_is("csplit: '/10/': match not found\n") .stdout_is("8\n133\n"); let count = glob(&at.plus_as_string("xx*")) @@ -1196,7 +1196,7 @@ fn test_corner_case3() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "/15/-3", "14", "/15/"]) .fails() - .stderr_is("csplit: '/15/': match not found") + .stderr_is("csplit: '/15/': match not found\n") .stdout_is("24\n6\n111\n"); let count = glob(&at.plus_as_string("xx*")) @@ -1228,7 +1228,7 @@ fn test_up_to_match_context_underflow() { ucmd.args(&["numbers50.txt", "/5/-10"]) .fails() .stdout_is("0\n141\n") - .stderr_is("csplit: '/5/-10': line number out of range"); + .stderr_is("csplit: '/5/-10': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -1239,7 +1239,7 @@ fn test_up_to_match_context_underflow() { ucmd.args(&["numbers50.txt", "/5/-10", "-k"]) .fails() .stdout_is("0\n141\n") - .stderr_is("csplit: '/5/-10': line number out of range"); + .stderr_is("csplit: '/5/-10': line number out of range\n"); let count = glob(&at.plus_as_string("xx*")) .expect("counting splits") @@ -1256,7 +1256,7 @@ fn test_line_num_range_with_up_to_match1() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "10", "/12/-5"]) .fails() - .stderr_is("csplit: '/12/-5': line number out of range") + .stderr_is("csplit: '/12/-5': line number out of range\n") .stdout_is("18\n0\n123\n"); let count = glob(&at.plus_as_string("xx*")) @@ -1267,7 +1267,7 @@ fn test_line_num_range_with_up_to_match1() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "10", "/12/-5", "-k"]) .fails() - .stderr_is("csplit: '/12/-5': line number out of range") + .stderr_is("csplit: '/12/-5': line number out of range\n") .stdout_is("18\n0\n123\n"); let count = glob(&at.plus_as_string("xx*")) @@ -1286,7 +1286,7 @@ fn test_line_num_range_with_up_to_match2() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "10", "/12/-15"]) .fails() - .stderr_is("csplit: '/12/-15': line number out of range") + .stderr_is("csplit: '/12/-15': line number out of range\n") .stdout_is("18\n0\n123\n"); let count = glob(&at.plus_as_string("xx*")) @@ -1297,7 +1297,7 @@ fn test_line_num_range_with_up_to_match2() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "10", "/12/-15", "-k"]) .fails() - .stderr_is("csplit: '/12/-15': line number out of range") + .stderr_is("csplit: '/12/-15': line number out of range\n") .stdout_is("18\n0\n123\n"); let count = glob(&at.plus_as_string("xx*")) @@ -1315,7 +1315,7 @@ fn test_line_num_range_with_up_to_match3() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.args(&["numbers50.txt", "10", "/10/", "-k"]) .fails() - .stderr_is("csplit: '/10/': match not found") + .stderr_is("csplit: '/10/': match not found\n") .stdout_is("18\n123\n"); let count = glob(&at.plus_as_string("xx*")) diff --git a/tests/by-util/test_cut.rs b/tests/by-util/test_cut.rs index bcdd9eaf0..bad609758 100644 --- a/tests/by-util/test_cut.rs +++ b/tests/by-util/test_cut.rs @@ -81,6 +81,38 @@ fn test_field_sequence() { } } +#[test] +fn test_whitespace_delimited() { + new_ucmd!() + .args(&["-w", "-f", COMPLEX_SEQUENCE.sequence, INPUT]) + .succeeds() + .stdout_only_fixture("whitespace_delimited.expected"); +} + +#[test] +fn test_whitespace_with_explicit_delimiter() { + new_ucmd!() + .args(&["-w", "-f", COMPLEX_SEQUENCE.sequence, "-d:"]) + .fails() + .code_is(1); +} + +#[test] +fn test_whitespace_with_byte() { + new_ucmd!() + .args(&["-w", "-b", COMPLEX_SEQUENCE.sequence]) + .fails() + .code_is(1); +} + +#[test] +fn test_whitespace_with_char() { + new_ucmd!() + .args(&["-c", COMPLEX_SEQUENCE.sequence, "-w"]) + .fails() + .code_is(1); +} + #[test] fn test_specify_delimiter() { for param in ["-d", "--delimiter", "--del"] { diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 6aa0031ca..4442f2df4 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -31,13 +31,13 @@ fn test_date_rfc_3339() { for param in ["--rfc-3339", "--rfc-3"] { scene .ucmd() - .arg(format!("{}=ns", param)) + .arg(format!("{param}=ns")) .succeeds() .stdout_matches(&re); scene .ucmd() - .arg(format!("{}=seconds", param)) + .arg(format!("{param}=seconds")) .succeeds() .stdout_matches(&re); } @@ -46,14 +46,14 @@ fn test_date_rfc_3339() { #[test] fn test_date_rfc_8601() { for param in ["--iso-8601", "--i"] { - new_ucmd!().arg(format!("{}=ns", param)).succeeds(); + new_ucmd!().arg(format!("{param}=ns")).succeeds(); } } #[test] fn test_date_rfc_8601_second() { for param in ["--iso-8601", "--i"] { - new_ucmd!().arg(format!("{}=second", param)).succeeds(); + new_ucmd!().arg(format!("{param}=second")).succeeds(); } } diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 17cece8e6..19050965c 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -211,35 +211,35 @@ fn test_x_multiplier() { fn test_zero_multiplier_warning() { for arg in ["count", "seek", "skip"] { new_ucmd!() - .args(&[format!("{}=0", arg).as_str(), "status=none"]) + .args(&[format!("{arg}=0").as_str(), "status=none"]) .pipe_in("") .succeeds() .no_stdout() .no_stderr(); new_ucmd!() - .args(&[format!("{}=00x1", arg).as_str(), "status=none"]) + .args(&[format!("{arg}=00x1").as_str(), "status=none"]) .pipe_in("") .succeeds() .no_stdout() .no_stderr(); new_ucmd!() - .args(&[format!("{}=0x1", arg).as_str(), "status=none"]) + .args(&[format!("{arg}=0x1").as_str(), "status=none"]) .pipe_in("") .succeeds() .no_stdout() .stderr_contains("warning: '0x' is a zero multiplier; use '00x' if that is intended"); new_ucmd!() - .args(&[format!("{}=0x0x1", arg).as_str(), "status=none"]) + .args(&[format!("{arg}=0x0x1").as_str(), "status=none"]) .pipe_in("") .succeeds() .no_stdout() .stderr_is("dd: warning: '0x' is a zero multiplier; use '00x' if that is intended\ndd: warning: '0x' is a zero multiplier; use '00x' if that is intended\n"); new_ucmd!() - .args(&[format!("{}=1x0x1", arg).as_str(), "status=none"]) + .args(&[format!("{arg}=1x0x1").as_str(), "status=none"]) .pipe_in("") .succeeds() .no_stdout() @@ -325,7 +325,7 @@ fn test_nocreat_causes_failure_when_outfile_not_present() { .pipe_in("") .fails() .stderr_only( - "dd: failed to open 'this-file-does-not-exist.txt': No such file or directory", + "dd: failed to open 'this-file-does-not-exist.txt': No such file or directory\n", ); assert!(!fix.file_exists(fname)); } @@ -461,7 +461,7 @@ fn test_oversized_bs_32_bit() { .run() .no_stdout() .failure() - .status_code(1) + .code_is(1) .stderr_is(format!("dd: {}=N cannot fit into memory\n", bs_param)); } } @@ -496,7 +496,7 @@ fn test_ascii_10k_to_stdout() { #[test] fn test_zeros_to_file() { let tname = "zero-256k"; - let test_fn = format!("{}.txt", tname); + let test_fn = format!("{tname}.txt"); let tmp_fn = format!("TESTFILE-{}.tmp", &tname); assert_fixture_exists!(test_fn); @@ -516,7 +516,7 @@ fn test_zeros_to_file() { #[test] fn test_to_file_with_ibs_obs() { let tname = "zero-256k"; - let test_fn = format!("{}.txt", tname); + let test_fn = format!("{tname}.txt"); let tmp_fn = format!("TESTFILE-{}.tmp", &tname); assert_fixture_exists!(test_fn); @@ -608,7 +608,7 @@ fn test_self_transfer() { #[test] fn test_unicode_filenames() { let tname = "😎💚🦊"; - let test_fn = format!("{}.txt", tname); + let test_fn = format!("{tname}.txt"); let tmp_fn = format!("TESTFILE-{}.tmp", &tname); assert_fixture_exists!(test_fn); @@ -1284,14 +1284,14 @@ fn test_invalid_number_arg_gnu_compatibility() { for command in commands { new_ucmd!() - .args(&[format!("{}=", command)]) + .args(&[format!("{command}=")]) .fails() - .stderr_is("dd: invalid number: ‘’"); + .stderr_is("dd: invalid number: ‘’\n"); new_ucmd!() - .args(&[format!("{}=29d", command)]) + .args(&[format!("{command}=29d")]) .fails() - .stderr_is("dd: invalid number: ‘29d’"); + .stderr_is("dd: invalid number: ‘29d’\n"); } } @@ -1301,14 +1301,14 @@ fn test_invalid_flag_arg_gnu_compatibility() { for command in commands { new_ucmd!() - .args(&[format!("{}=", command)]) + .args(&[format!("{command}=")]) .fails() - .stderr_is("dd: invalid input flag: ‘’\nTry 'dd --help' for more information."); + .usage_error("invalid input flag: ‘’"); new_ucmd!() - .args(&[format!("{}=29d", command)]) + .args(&[format!("{command}=29d")]) .fails() - .stderr_is("dd: invalid input flag: ‘29d’\nTry 'dd --help' for more information."); + .usage_error("invalid input flag: ‘29d’"); } } @@ -1317,19 +1317,19 @@ fn test_invalid_file_arg_gnu_compatibility() { new_ucmd!() .args(&["if="]) .fails() - .stderr_is("dd: failed to open '': No such file or directory"); + .stderr_is("dd: failed to open '': No such file or directory\n"); new_ucmd!() .args(&["if=81as9bn8as9g302az8ns9.pdf.zip.pl.com"]) .fails() .stderr_is( - "dd: failed to open '81as9bn8as9g302az8ns9.pdf.zip.pl.com': No such file or directory", + "dd: failed to open '81as9bn8as9g302az8ns9.pdf.zip.pl.com': No such file or directory\n", ); new_ucmd!() .args(&["of="]) .fails() - .stderr_is("dd: failed to open '': No such file or directory"); + .stderr_is("dd: failed to open '': No such file or directory\n"); new_ucmd!() .args(&["of=81as9bn8as9g302az8ns9.pdf.zip.pl.com"]) diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index 62f6e2633..0cf27c205 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -321,13 +321,13 @@ fn test_include_exclude_same_type() { new_ucmd!() .args(&["-t", "ext4", "-x", "ext4"]) .fails() - .stderr_is("df: file system type 'ext4' both selected and excluded"); + .stderr_is("df: file system type 'ext4' both selected and excluded\n"); new_ucmd!() .args(&["-t", "ext4", "-x", "ext4", "-t", "ext3", "-x", "ext3"]) .fails() .stderr_is( "df: file system type 'ext4' both selected and excluded\n\ - df: file system type 'ext3' both selected and excluded", + df: file system type 'ext3' both selected and excluded\n", ); } @@ -519,7 +519,7 @@ fn test_default_block_size_in_posix_portability_mode() { fn test_block_size_1024() { fn get_header(block_size: u64) -> String { let output = new_ucmd!() - .args(&["-B", &format!("{}", block_size), "--output=size"]) + .args(&["-B", &format!("{block_size}"), "--output=size"]) .succeeds() .stdout_move_str(); output.lines().next().unwrap().trim().to_string() @@ -693,9 +693,9 @@ fn test_ignore_block_size_from_env_in_posix_portability_mode() { fn test_too_large_block_size() { fn run_command(size: &str) { new_ucmd!() - .arg(format!("--block-size={}", size)) + .arg(format!("--block-size={size}")) .fails() - .stderr_contains(format!("--block-size argument '{}' too large", size)); + .stderr_contains(format!("--block-size argument '{size}' too large")); } let too_large_sizes = vec!["1Y", "1Z"]; @@ -853,7 +853,7 @@ fn test_nonexistent_file() { new_ucmd!() .arg("does-not-exist") .fails() - .stderr_only("df: does-not-exist: No such file or directory"); + .stderr_only("df: does-not-exist: No such file or directory\n"); new_ucmd!() .args(&["--output=file", "does-not-exist", "."]) .fails() diff --git a/tests/by-util/test_dircolors.rs b/tests/by-util/test_dircolors.rs index 80b9711a2..aaff02d30 100644 --- a/tests/by-util/test_dircolors.rs +++ b/tests/by-util/test_dircolors.rs @@ -210,14 +210,14 @@ fn test_helper(file_name: &str, term: &str) { new_ucmd!() .env("TERM", term) .arg("-c") - .arg(format!("{}.txt", file_name)) + .arg(format!("{file_name}.txt")) .run() - .stdout_is_fixture(format!("{}.csh.expected", file_name)); + .stdout_is_fixture(format!("{file_name}.csh.expected")); new_ucmd!() .env("TERM", term) .arg("-b") - .arg(format!("{}.txt", file_name)) + .arg(format!("{file_name}.txt")) .run() - .stdout_is_fixture(format!("{}.sh.expected", file_name)); + .stdout_is_fixture(format!("{file_name}.sh.expected")); } diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 09bb36e05..1232beda9 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -95,24 +95,24 @@ fn test_du_invalid_size() { let ts = TestScenario::new(util_name!()); for s in args { ts.ucmd() - .arg(format!("--{}=1fb4t", s)) + .arg(format!("--{s}=1fb4t")) .arg("/tmp") .fails() .code_is(1) - .stderr_only(format!("du: invalid suffix in --{} argument '1fb4t'", s)); + .stderr_only(format!("du: invalid suffix in --{s} argument '1fb4t'\n")); ts.ucmd() - .arg(format!("--{}=x", s)) + .arg(format!("--{s}=x")) .arg("/tmp") .fails() .code_is(1) - .stderr_only(format!("du: invalid --{} argument 'x'", s)); + .stderr_only(format!("du: invalid --{s} argument 'x'\n")); #[cfg(not(target_pointer_width = "128"))] ts.ucmd() - .arg(format!("--{}=1Y", s)) + .arg(format!("--{s}=1Y")) .arg("/tmp") .fails() .code_is(1) - .stderr_only(format!("du: --{} argument '1Y' too large", s)); + .stderr_only(format!("du: --{s} argument '1Y' too large\n")); } } @@ -511,13 +511,13 @@ fn test_du_threshold() { let threshold = if cfg!(windows) { "7K" } else { "10K" }; ts.ucmd() - .arg(format!("--threshold={}", threshold)) + .arg(format!("--threshold={threshold}")) .succeeds() .stdout_contains("links") .stdout_does_not_contain("deeper_dir"); ts.ucmd() - .arg(format!("--threshold=-{}", threshold)) + .arg(format!("--threshold=-{threshold}")) .succeeds() .stdout_does_not_contain("links") .stdout_contains("deeper_dir"); diff --git a/tests/by-util/test_echo.rs b/tests/by-util/test_echo.rs index 401e16706..f28bc1bb4 100644 --- a/tests/by-util/test_echo.rs +++ b/tests/by-util/test_echo.rs @@ -176,7 +176,7 @@ fn test_disable_escapes() { .arg("-E") .arg(input_str) .succeeds() - .stdout_only(format!("{}\n", input_str)); + .stdout_only(format!("{input_str}\n")); } #[test] diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index 9b6452548..ef10512ab 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -90,7 +90,7 @@ fn test_unset_invalid_variables() { // with this error: Error { kind: InvalidInput, message: "nul byte found in provided data" } for var in ["", "a=b"] { new_ucmd!().arg("-u").arg(var).run().stderr_only(format!( - "env: cannot unset {}: Invalid argument", + "env: cannot unset {}: Invalid argument\n", var.quote() )); } @@ -130,7 +130,7 @@ fn test_empty_name() { .arg("-i") .arg("=xyz") .run() - .stderr_only("env: warning: no name specified for value 'xyz'"); + .stderr_only("env: warning: no name specified for value 'xyz'\n"); } #[test] diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index 3a753aa1b..1eebf35f0 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -1,7 +1,31 @@ -// spell-checker:ignore αbcdef +// spell-checker:ignore αbcdef ; (people) kkos use crate::common::util::*; +#[test] +fn test_simple_values() { + // null or 0 => EXIT_VALUE == 1 + new_ucmd!().args(&[""]).fails().code_is(1).stdout_only("\n"); + new_ucmd!() + .args(&["0"]) + .fails() + .code_is(1) + .stdout_only("0\n"); + new_ucmd!() + .args(&["00"]) + .fails() + .code_is(1) + .stdout_only("00\n"); + new_ucmd!() + .args(&["-0"]) + .fails() + .code_is(1) + .stdout_only("-0\n"); + + // non-null and non-0 => EXIT_VALUE = 0 + new_ucmd!().args(&["1"]).succeeds().stdout_only("1\n"); +} + #[test] fn test_simple_arithmetic() { new_ucmd!() @@ -12,7 +36,7 @@ fn test_simple_arithmetic() { new_ucmd!() .args(&["1", "-", "1"]) .fails() - .status_code(1) + .code_is(1) .stdout_only("0\n"); new_ucmd!() @@ -97,6 +121,39 @@ fn test_and() { new_ucmd!().args(&["", "&", "1"]).run().stdout_is("0\n"); } +#[test] +fn test_index() { + new_ucmd!() + .args(&["index", "αbcdef", "x"]) + .fails() + .code_is(1) + .stdout_only("0\n"); + new_ucmd!() + .args(&["index", "αbcdef", "α"]) + .succeeds() + .stdout_only("1\n"); + new_ucmd!() + .args(&["index", "αbc_δef", "δ"]) + .succeeds() + .stdout_only("5\n"); + new_ucmd!() + .args(&["index", "αbc_δef", "δf"]) + .succeeds() + .stdout_only("5\n"); + new_ucmd!() + .args(&["index", "αbcdef", "fb"]) + .succeeds() + .stdout_only("2\n"); + new_ucmd!() + .args(&["index", "αbcdef", "f"]) + .succeeds() + .stdout_only("6\n"); + new_ucmd!() + .args(&["index", "αbcdef_f", "f"]) + .succeeds() + .stdout_only("6\n"); +} + #[test] fn test_length_fail() { new_ucmd!().args(&["length", "αbcdef", "1"]).fails(); @@ -118,6 +175,27 @@ fn test_length_mb() { .stdout_only("6\n"); } +#[test] +fn test_regex() { + // FixME: [2022-12-19; rivy] test disabled as it currently fails due to 'oniguruma' bug (see GH:kkos/oniguruma/issues/279) + // new_ucmd!() + // .args(&["a^b", ":", "a^b"]) + // .succeeds() + // .stdout_only("3\n"); + new_ucmd!() + .args(&["a^b", ":", "a\\^b"]) + .succeeds() + .stdout_only("3\n"); + new_ucmd!() + .args(&["a$b", ":", "a\\$b"]) + .succeeds() + .stdout_only("3\n"); + new_ucmd!() + .args(&["-5", ":", "-\\{0,1\\}[0-9]*$"]) + .succeeds() + .stdout_only("2\n"); +} + #[test] fn test_substr() { new_ucmd!() @@ -131,18 +209,18 @@ fn test_invalid_substr() { new_ucmd!() .args(&["substr", "abc", "0", "1"]) .fails() - .status_code(1) + .code_is(1) .stdout_only("\n"); new_ucmd!() .args(&["substr", "abc", &(std::usize::MAX.to_string() + "0"), "1"]) .fails() - .status_code(1) + .code_is(1) .stdout_only("\n"); new_ucmd!() .args(&["substr", "abc", "0", &(std::usize::MAX.to_string() + "0")]) .fails() - .status_code(1) + .code_is(1) .stdout_only("\n"); } diff --git a/tests/by-util/test_factor.rs b/tests/by-util/test_factor.rs index 6a17c00ff..7a4d54fb5 100644 --- a/tests/by-util/test_factor.rs +++ b/tests/by-util/test_factor.rs @@ -41,7 +41,7 @@ fn test_parallel() { let n_integers = 100_000; let mut input_string = String::new(); for i in 0..=n_integers { - input_string.push_str(&(format!("{} ", i))[..]); + input_string.push_str(&(format!("{i} "))[..]); } let tmp_dir = TempDir::new().unwrap(); @@ -87,10 +87,10 @@ fn test_first_1000_integers() { let n_integers = 1000; let mut input_string = String::new(); for i in 0..=n_integers { - input_string.push_str(&(format!("{} ", i))[..]); + input_string.push_str(&(format!("{i} "))[..]); } - println!("STDIN='{}'", input_string); + println!("STDIN='{input_string}'"); let result = new_ucmd!().pipe_in(input_string.as_bytes()).succeeds(); // `seq 0 1000 | factor | sha1sum` => "c734327bd18b90fca5762f671672b5eda19f7dca" @@ -126,7 +126,7 @@ fn test_random() { .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs(); - println!("rng_seed={:?}", rng_seed); + println!("rng_seed={rng_seed:?}"); let mut rng = SmallRng::seed_from_u64(rng_seed); let mut rand_gt = move |min: u64| { @@ -162,11 +162,11 @@ fn test_random() { let mut output_string = String::new(); for _ in 0..NUM_TESTS { let (product, factors) = rand_gt(1 << 63); - input_string.push_str(&(format!("{} ", product))[..]); + input_string.push_str(&(format!("{product} "))[..]); - output_string.push_str(&(format!("{}:", product))[..]); + output_string.push_str(&(format!("{product}:"))[..]); for factor in factors { - output_string.push_str(&(format!(" {}", factor))[..]); + output_string.push_str(&(format!(" {factor}"))[..]); } output_string.push('\n'); } @@ -180,7 +180,7 @@ fn test_random_big() { .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs(); - println!("rng_seed={:?}", rng_seed); + println!("rng_seed={rng_seed:?}"); let mut rng = SmallRng::seed_from_u64(rng_seed); let bit_range_1 = Uniform::new(14_usize, 51); @@ -244,11 +244,11 @@ fn test_random_big() { let mut output_string = String::new(); for _ in 0..NUM_TESTS { let (product, factors) = rand_64(); - input_string.push_str(&(format!("{} ", product))[..]); + input_string.push_str(&(format!("{product} "))[..]); - output_string.push_str(&(format!("{}:", product))[..]); + output_string.push_str(&(format!("{product}:"))[..]); for factor in factors { - output_string.push_str(&(format!(" {}", factor))[..]); + output_string.push_str(&(format!(" {factor}"))[..]); } output_string.push('\n'); } @@ -261,8 +261,8 @@ fn test_big_primes() { let mut input_string = String::new(); let mut output_string = String::new(); for prime in PRIMES64 { - input_string.push_str(&(format!("{} ", prime))[..]); - output_string.push_str(&(format!("{0}: {0}\n", prime))[..]); + input_string.push_str(&(format!("{prime} "))[..]); + output_string.push_str(&(format!("{prime}: {prime}\n"))[..]); } run(input_string.as_bytes(), output_string.as_bytes()); diff --git a/tests/by-util/test_hashsum.rs b/tests/by-util/test_hashsum.rs index e8f716815..5a9cd1965 100644 --- a/tests/by-util/test_hashsum.rs +++ b/tests/by-util/test_hashsum.rs @@ -134,7 +134,7 @@ fn test_check_file_not_found_warning() { .arg(at.subdir.join("testf.sha1")) .succeeds() .stdout_is("sha1sum: testf: No such file or directory\ntestf: FAILED open or read\n") - .stderr_is("sha1sum: warning: 1 listed file could not be read"); + .stderr_is("sha1sum: warning: 1 listed file could not be read\n"); } #[test] diff --git a/tests/by-util/test_head.rs b/tests/by-util/test_head.rs index cefb5c0ae..364ed3b45 100644 --- a/tests/by-util/test_head.rs +++ b/tests/by-util/test_head.rs @@ -288,21 +288,21 @@ fn test_head_invalid_num() { new_ucmd!() .args(&["-c", "1024R", "emptyfile.txt"]) .fails() - .stderr_is("head: invalid number of bytes: '1024R'"); + .stderr_is("head: invalid number of bytes: '1024R'\n"); new_ucmd!() .args(&["-n", "1024R", "emptyfile.txt"]) .fails() - .stderr_is("head: invalid number of lines: '1024R'"); + .stderr_is("head: invalid number of lines: '1024R'\n"); #[cfg(not(target_pointer_width = "128"))] new_ucmd!() .args(&["-c", "1Y", "emptyfile.txt"]) .fails() - .stderr_is("head: invalid number of bytes: '1Y': Value too large for defined data type"); + .stderr_is("head: invalid number of bytes: '1Y': Value too large for defined data type\n"); #[cfg(not(target_pointer_width = "128"))] new_ucmd!() .args(&["-n", "1Y", "emptyfile.txt"]) .fails() - .stderr_is("head: invalid number of lines: '1Y': Value too large for defined data type"); + .stderr_is("head: invalid number of lines: '1Y': Value too large for defined data type\n"); #[cfg(target_pointer_width = "32")] { let sizes = ["1000G", "10T"]; @@ -317,13 +317,13 @@ fn test_head_invalid_num() { new_ucmd!() .args(&["-c", size]) .fails() - .stderr_is("head: out of range integral type conversion attempted: number of bytes is too large"); + .stderr_is("head: out of range integral type conversion attempted: number of bytes is too large\n"); } } new_ucmd!() .args(&["-c", "-³"]) .fails() - .stderr_is("head: invalid number of bytes: '³'"); + .stderr_is("head: invalid number of bytes: '³'\n"); } #[test] diff --git a/tests/by-util/test_install.rs b/tests/by-util/test_install.rs index 3543d2628..1e6cd7606 100644 --- a/tests/by-util/test_install.rs +++ b/tests/by-util/test_install.rs @@ -28,8 +28,8 @@ fn test_install_basic() { assert!(at.file_exists(file1)); assert!(at.file_exists(file2)); - assert!(at.file_exists(&format!("{}/{}", dir, file1))); - assert!(at.file_exists(&format!("{}/{}", dir, file2))); + assert!(at.file_exists(&format!("{dir}/{file1}"))); + assert!(at.file_exists(&format!("{dir}/{file2}"))); } #[test] @@ -76,7 +76,7 @@ fn test_install_unimplemented_arg() { .fails() .stderr_contains("Unimplemented"); - assert!(!at.file_exists(&format!("{}/{}", dir, file))); + assert!(!at.file_exists(&format!("{dir}/{file}"))); } #[test] @@ -181,7 +181,7 @@ fn test_install_mode_numeric() { .succeeds() .no_stderr(); - let dest_file = &format!("{}/{}", dir, file); + let dest_file = &format!("{dir}/{file}"); assert!(at.file_exists(file)); assert!(at.file_exists(dest_file)); let permissions = at.metadata(dest_file).permissions(); @@ -192,7 +192,7 @@ fn test_install_mode_numeric() { scene.ucmd().arg(mode_arg).arg(file).arg(dir2).succeeds(); - let dest_file = &format!("{}/{}", dir2, file); + let dest_file = &format!("{dir2}/{file}"); assert!(at.file_exists(file)); assert!(at.file_exists(dest_file)); let permissions = at.metadata(dest_file).permissions(); @@ -210,7 +210,7 @@ fn test_install_mode_symbolic() { at.mkdir(dir); ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr(); - let dest_file = &format!("{}/{}", dir, file); + let dest_file = &format!("{dir}/{file}"); assert!(at.file_exists(file)); assert!(at.file_exists(dest_file)); let permissions = at.metadata(dest_file).permissions(); @@ -232,7 +232,7 @@ fn test_install_mode_failing() { .fails() .stderr_contains("Invalid mode string: invalid digit found in string"); - let dest_file = &format!("{}/{}", dir, file); + let dest_file = &format!("{dir}/{file}"); assert!(at.file_exists(file)); assert!(!at.file_exists(dest_file)); } @@ -278,12 +278,12 @@ fn test_install_target_new_file() { at.touch(file); at.mkdir(dir); ucmd.arg(file) - .arg(format!("{}/{}", dir, file)) + .arg(format!("{dir}/{file}")) .succeeds() .no_stderr(); assert!(at.file_exists(file)); - assert!(at.file_exists(&format!("{}/{}", dir, file))); + assert!(at.file_exists(&format!("{dir}/{file}"))); } #[test] @@ -299,7 +299,7 @@ fn test_install_target_new_file_with_group() { .arg(file) .arg("--group") .arg(gid.to_string()) - .arg(format!("{}/{}", dir, file)) + .arg(format!("{dir}/{file}")) .run(); if is_ci() && result.stderr_str().contains("no such group:") { @@ -310,7 +310,7 @@ fn test_install_target_new_file_with_group() { result.success(); assert!(at.file_exists(file)); - assert!(at.file_exists(&format!("{}/{}", dir, file))); + assert!(at.file_exists(&format!("{dir}/{file}"))); } #[test] @@ -326,7 +326,7 @@ fn test_install_target_new_file_with_owner() { .arg(file) .arg("--owner") .arg(uid.to_string()) - .arg(format!("{}/{}", dir, file)) + .arg(format!("{dir}/{file}")) .run(); if is_ci() && result.stderr_str().contains("no such user:") { @@ -337,7 +337,7 @@ fn test_install_target_new_file_with_owner() { result.success(); assert!(at.file_exists(file)); - assert!(at.file_exists(&format!("{}/{}", dir, file))); + assert!(at.file_exists(&format!("{dir}/{file}"))); } #[test] @@ -350,7 +350,7 @@ fn test_install_target_new_file_failing_nonexistent_parent() { at.touch(file1); ucmd.arg(file1) - .arg(format!("{}/{}", dir, file2)) + .arg(format!("{dir}/{file2}")) .fails() .stderr_contains("No such file or directory"); } @@ -416,13 +416,13 @@ fn test_install_nested_paths_copy_file() { at.mkdir(dir1); at.mkdir(dir2); - at.touch(&format!("{}/{}", dir1, file1)); + at.touch(&format!("{dir1}/{file1}")); - ucmd.arg(format!("{}/{}", dir1, file1)) + ucmd.arg(format!("{dir1}/{file1}")) .arg(dir2) .succeeds() .no_stderr(); - assert!(at.file_exists(&format!("{}/{}", dir2, file1))); + assert!(at.file_exists(&format!("{dir2}/{file1}"))); } #[test] @@ -456,7 +456,7 @@ fn test_install_failing_omitting_directory() { .fails() .code_is(1) .stderr_contains("omitting directory"); - assert!(at.file_exists(&format!("{}/{}", dir3, file1))); + assert!(at.file_exists(&format!("{dir3}/{file1}"))); // install also fails, when only one source param is given scene @@ -826,14 +826,14 @@ fn test_install_dir() { at.mkdir(dir); ucmd.arg(file1) .arg(file2) - .arg(&format!("--target-directory={}", dir)) + .arg(&format!("--target-directory={dir}")) .succeeds() .no_stderr(); assert!(at.file_exists(file1)); assert!(at.file_exists(file2)); - assert!(at.file_exists(&format!("{}/{}", dir, file1))); - assert!(at.file_exists(&format!("{}/{}", dir, file2))); + assert!(at.file_exists(&format!("{dir}/{file1}"))); + assert!(at.file_exists(&format!("{dir}/{file2}"))); } // // test backup functionality @@ -857,7 +857,7 @@ fn test_install_backup_short_no_args_files() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -867,7 +867,7 @@ fn test_install_backup_short_no_args_file_to_dir() { let file = "test_install_simple_backup_file_a"; let dest_dir = "test_install_dest/"; - let expect = format!("{}{}", dest_dir, file); + let expect = format!("{dest_dir}{file}"); at.touch(file); at.mkdir(dest_dir); @@ -882,7 +882,7 @@ fn test_install_backup_short_no_args_file_to_dir() { assert!(at.file_exists(file)); assert!(at.file_exists(&expect)); - assert!(at.file_exists(&format!("{}~", expect))); + assert!(at.file_exists(&format!("{expect}~"))); } // Long --backup option is tested separately as it requires a slightly different @@ -907,7 +907,7 @@ fn test_install_backup_long_no_args_files() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -917,7 +917,7 @@ fn test_install_backup_long_no_args_file_to_dir() { let file = "test_install_simple_backup_file_a"; let dest_dir = "test_install_dest/"; - let expect = format!("{}{}", dest_dir, file); + let expect = format!("{dest_dir}{file}"); at.touch(file); at.mkdir(dest_dir); @@ -932,7 +932,7 @@ fn test_install_backup_long_no_args_file_to_dir() { assert!(at.file_exists(file)); assert!(at.file_exists(&expect)); - assert!(at.file_exists(&format!("{}~", expect))); + assert!(at.file_exists(&format!("{expect}~"))); } #[test] @@ -949,7 +949,7 @@ fn test_install_backup_short_custom_suffix() { scene .ucmd() .arg("-b") - .arg(format!("--suffix={}", suffix)) + .arg(format!("--suffix={suffix}")) .arg(file_a) .arg(file_b) .succeeds() @@ -957,7 +957,7 @@ fn test_install_backup_short_custom_suffix() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}{}", file_b, suffix))); + assert!(at.file_exists(&format!("{file_b}{suffix}"))); } #[test] @@ -974,7 +974,7 @@ fn test_install_backup_short_custom_suffix_hyphen_value() { scene .ucmd() .arg("-b") - .arg(format!("--suffix={}", suffix)) + .arg(format!("--suffix={suffix}")) .arg(file_a) .arg(file_b) .succeeds() @@ -982,7 +982,7 @@ fn test_install_backup_short_custom_suffix_hyphen_value() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}{}", file_b, suffix))); + assert!(at.file_exists(&format!("{file_b}{suffix}"))); } #[test] @@ -1007,7 +1007,7 @@ fn test_install_backup_custom_suffix_via_env() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}{}", file_b, suffix))); + assert!(at.file_exists(&format!("{file_b}{suffix}"))); } #[test] @@ -1030,7 +1030,7 @@ fn test_install_backup_numbered_with_t() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}.~1~", file_b))); + assert!(at.file_exists(&format!("{file_b}.~1~"))); } #[test] @@ -1053,7 +1053,7 @@ fn test_install_backup_numbered_with_numbered() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}.~1~", file_b))); + assert!(at.file_exists(&format!("{file_b}.~1~"))); } #[test] @@ -1076,7 +1076,7 @@ fn test_install_backup_existing() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -1099,7 +1099,7 @@ fn test_install_backup_nil() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -1125,7 +1125,7 @@ fn test_install_backup_numbered_if_existing_backup_existing() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); assert!(at.file_exists(file_b_backup)); - assert!(at.file_exists(&format!("{}.~2~", file_b))); + assert!(at.file_exists(&format!("{file_b}.~2~"))); } #[test] @@ -1151,7 +1151,7 @@ fn test_install_backup_numbered_if_existing_backup_nil() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); assert!(at.file_exists(file_b_backup)); - assert!(at.file_exists(&format!("{}.~2~", file_b))); + assert!(at.file_exists(&format!("{file_b}.~2~"))); } #[test] @@ -1174,7 +1174,7 @@ fn test_install_backup_simple() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -1197,7 +1197,7 @@ fn test_install_backup_never() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -1220,7 +1220,7 @@ fn test_install_backup_none() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(!at.file_exists(&format!("{}~", file_b))); + assert!(!at.file_exists(&format!("{file_b}~"))); } #[test] @@ -1243,7 +1243,7 @@ fn test_install_backup_off() { assert!(at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(!at.file_exists(&format!("{}~", file_b))); + assert!(!at.file_exists(&format!("{file_b}~"))); } #[test] @@ -1257,16 +1257,14 @@ fn test_install_missing_arguments() { .ucmd() .fails() .code_is(1) - .stderr_contains("install: missing file operand") - .stderr_contains("install --help' for more information."); + .usage_error("missing file operand"); scene .ucmd() .arg("-D") - .arg(format!("-t {}", no_target_dir)) + .arg(format!("-t {no_target_dir}")) .fails() - .stderr_contains("install: missing file operand") - .stderr_contains("install --help' for more information."); + .usage_error("missing file operand"); assert!(!at.dir_exists(no_target_dir)); } @@ -1286,11 +1284,7 @@ fn test_install_missing_destination() { .ucmd() .arg(file_1) .fails() - .stderr_contains(format!( - "install: missing destination file operand after '{}'", - file_1 - )) - .stderr_contains("install --help' for more information."); + .usage_error(format!("missing destination file operand after '{file_1}'")); // GNU's install will check for correct num of arguments and then fail // and it does not recognize, that the source is not a file but a directory. @@ -1298,11 +1292,7 @@ fn test_install_missing_destination() { .ucmd() .arg(dir_1) .fails() - .stderr_contains(format!( - "install: missing destination file operand after '{}'", - dir_1 - )) - .stderr_contains("install --help' for more information."); + .usage_error(format!("missing destination file operand after '{dir_1}'")); } #[test] @@ -1390,7 +1380,7 @@ fn test_install_compare_option() { .ucmd() .args(&["-Cv", first, second]) .succeeds() - .stdout_contains(format!("'{}' -> '{}'", first, second)); + .stdout_contains(format!("'{first}' -> '{second}'")); scene .ucmd() .args(&["-Cv", first, second]) @@ -1400,12 +1390,12 @@ fn test_install_compare_option() { .ucmd() .args(&["-Cv", "-m0644", first, second]) .succeeds() - .stdout_contains(format!("removed '{}'\n'{}' -> '{}'", second, first, second)); + .stdout_contains(format!("removed '{second}'\n'{first}' -> '{second}'")); scene .ucmd() .args(&["-Cv", first, second]) .succeeds() - .stdout_contains(format!("removed '{}'\n'{}' -> '{}'", second, first, second)); + .stdout_contains(format!("removed '{second}'\n'{first}' -> '{second}'")); scene .ucmd() .args(&["-C", "--preserve-timestamps", first, second]) diff --git a/tests/by-util/test_join.rs b/tests/by-util/test_join.rs index 10af26ec5..9138e3d6b 100644 --- a/tests/by-util/test_join.rs +++ b/tests/by-util/test_join.rs @@ -206,7 +206,7 @@ fn tab_multi_character() { .arg("-t") .arg("э") .fails() - .stderr_is("join: multi-character tab э"); + .stderr_is("join: multi-character tab э\n"); } #[test] @@ -282,7 +282,7 @@ fn empty_format() { .arg("-o") .arg("") .fails() - .stderr_is("join: invalid file number in field spec: ''"); + .stderr_is("join: invalid file number in field spec: ''\n"); } #[test] @@ -332,7 +332,7 @@ fn wrong_line_order() { .fails() .stdout_contains("7 g f 4 fg") .stderr_is(&format!( - "{0} {1}: fields_4.txt:5: is not sorted: 11 g 5 gh\n{0} {1}: input is not in sorted order", + "{0} {1}: fields_4.txt:5: is not sorted: 11 g 5 gh\n{0} {1}: input is not in sorted order\n", ts.bin_path.to_string_lossy(), ts.util_name )); @@ -344,7 +344,7 @@ fn wrong_line_order() { .fails() .stdout_does_not_contain("7 g f 4 fg") .stderr_is(&format!( - "{0}: fields_4.txt:5: is not sorted: 11 g 5 gh", + "{0}: fields_4.txt:5: is not sorted: 11 g 5 gh\n", ts.util_name )); } @@ -358,7 +358,7 @@ fn both_files_wrong_line_order() { .fails() .stdout_contains("5 e 3 ef") .stderr_is(&format!( - "{0} {1}: fields_5.txt:4: is not sorted: 3\n{0} {1}: fields_4.txt:5: is not sorted: 11 g 5 gh\n{0} {1}: input is not in sorted order", + "{0} {1}: fields_5.txt:4: is not sorted: 3\n{0} {1}: fields_4.txt:5: is not sorted: 11 g 5 gh\n{0} {1}: input is not in sorted order\n", ts.bin_path.to_string_lossy(), ts.util_name )); @@ -370,7 +370,7 @@ fn both_files_wrong_line_order() { .fails() .stdout_does_not_contain("5 e 3 ef") .stderr_is(&format!( - "{0}: fields_5.txt:4: is not sorted: 3", + "{0}: fields_5.txt:4: is not sorted: 3\n", ts.util_name )); } @@ -453,7 +453,7 @@ fn non_unicode() { .arg("non-unicode_2.bin") .fails() .stderr_is( - "join: unprintable field separators are only supported on unix-like platforms", + "join: unprintable field separators are only supported on unix-like platforms\n", ); } } diff --git a/tests/by-util/test_link.rs b/tests/by-util/test_link.rs index c65dc29d8..e52a31a33 100644 --- a/tests/by-util/test_link.rs +++ b/tests/by-util/test_link.rs @@ -29,7 +29,7 @@ fn test_link_no_circular() { ucmd.args(&[link, link]) .fails() - .stderr_is("link: cannot create link 'test_link_no_circular' to 'test_link_no_circular': No such file or directory"); + .stderr_is("link: cannot create link 'test_link_no_circular' to 'test_link_no_circular': No such file or directory\n"); assert!(!at.file_exists(link)); } @@ -41,7 +41,7 @@ fn test_link_nonexistent_file() { ucmd.args(&[file, link]) .fails() - .stderr_only("link: cannot create link 'test_link_nonexistent_file_link' to 'test_link_nonexistent_file': No such file or directory"); + .stderr_only("link: cannot create link 'test_link_nonexistent_file_link' to 'test_link_nonexistent_file': No such file or directory\n"); assert!(!at.file_exists(file)); assert!(!at.file_exists(link)); } diff --git a/tests/by-util/test_ln.rs b/tests/by-util/test_ln.rs index 07b824649..bc51fc107 100644 --- a/tests/by-util/test_ln.rs +++ b/tests/by-util/test_ln.rs @@ -153,7 +153,7 @@ fn test_symlink_simple_backup() { assert!(at.is_symlink(link)); assert_eq!(at.resolve_link(link), file); - let backup = &format!("{}~", link); + let backup = &format!("{link}~"); assert!(at.is_symlink(backup)); assert_eq!(at.resolve_link(backup), file); } @@ -171,7 +171,7 @@ fn test_symlink_custom_backup_suffix() { assert!(at.is_symlink(link)); assert_eq!(at.resolve_link(link), file); - let arg = &format!("--suffix={}", suffix); + let arg = &format!("--suffix={suffix}"); ucmd.args(&["-b", arg, "-s", file, link]) .succeeds() .no_stderr(); @@ -180,7 +180,7 @@ fn test_symlink_custom_backup_suffix() { assert!(at.is_symlink(link)); assert_eq!(at.resolve_link(link), file); - let backup = &format!("{}{}", link, suffix); + let backup = &format!("{link}{suffix}"); assert!(at.is_symlink(backup)); assert_eq!(at.resolve_link(backup), file); } @@ -198,7 +198,7 @@ fn test_symlink_custom_backup_suffix_hyphen_value() { assert!(at.is_symlink(link)); assert_eq!(at.resolve_link(link), file); - let arg = &format!("--suffix={}", suffix); + let arg = &format!("--suffix={suffix}"); ucmd.args(&["-b", arg, "-s", file, link]) .succeeds() .no_stderr(); @@ -207,7 +207,7 @@ fn test_symlink_custom_backup_suffix_hyphen_value() { assert!(at.is_symlink(link)); assert_eq!(at.resolve_link(link), file); - let backup = &format!("{}{}", link, suffix); + let backup = &format!("{link}{suffix}"); assert!(at.is_symlink(backup)); assert_eq!(at.resolve_link(backup), file); } @@ -232,7 +232,7 @@ fn test_symlink_backup_numbering() { assert!(at.is_symlink(link)); assert_eq!(at.resolve_link(link), file); - let backup = &format!("{}.~1~", link); + let backup = &format!("{link}.~1~"); assert!(at.is_symlink(backup)); assert_eq!(at.resolve_link(backup), file); } @@ -285,11 +285,11 @@ fn test_symlink_target_dir() { .succeeds() .no_stderr(); - let file_a_link = &format!("{}/{}", dir, file_a); + let file_a_link = &format!("{dir}/{file_a}"); assert!(at.is_symlink(file_a_link)); assert_eq!(at.resolve_link(file_a_link), file_a); - let file_b_link = &format!("{}/{}", dir, file_b); + let file_b_link = &format!("{dir}/{file_b}"); assert!(at.is_symlink(file_b_link)); assert_eq!(at.resolve_link(file_b_link), file_b); } @@ -301,8 +301,8 @@ fn test_symlink_target_dir_from_dir() { let from_dir = "test_ln_target_dir_from_dir"; let filename_a = "test_ln_target_dir_file_a"; let filename_b = "test_ln_target_dir_file_b"; - let file_a = &format!("{}/{}", from_dir, filename_a); - let file_b = &format!("{}/{}", from_dir, filename_b); + let file_a = &format!("{from_dir}/{filename_a}"); + let file_b = &format!("{from_dir}/{filename_b}"); at.mkdir(from_dir); at.touch(file_a); @@ -313,11 +313,11 @@ fn test_symlink_target_dir_from_dir() { .succeeds() .no_stderr(); - let file_a_link = &format!("{}/{}", dir, filename_a); + let file_a_link = &format!("{dir}/{filename_a}"); assert!(at.is_symlink(file_a_link)); assert_eq!(&at.resolve_link(file_a_link), file_a); - let file_b_link = &format!("{}/{}", dir, filename_b); + let file_b_link = &format!("{dir}/{filename_b}"); assert!(at.is_symlink(file_b_link)); assert_eq!(&at.resolve_link(file_b_link), file_b); } @@ -367,7 +367,7 @@ fn test_symlink_verbose() { .ucmd() .args(&["-s", "-v", file_a, file_b]) .succeeds() - .stdout_only(format!("'{}' -> '{}'\n", file_b, file_a)); + .stdout_only(format!("'{file_b}' -> '{file_a}'\n")); at.touch(file_b); @@ -375,10 +375,7 @@ fn test_symlink_verbose() { .ucmd() .args(&["-s", "-v", "-b", file_a, file_b]) .succeeds() - .stdout_only(format!( - "'{}' -> '{}' (backup: '{}~')\n", - file_b, file_a, file_b - )); + .stdout_only(format!("'{file_b}' -> '{file_a}' (backup: '{file_b}~')\n")); } #[test] @@ -421,7 +418,7 @@ fn test_symlink_to_dir_2args() { let filename = "test_symlink_to_dir_2args_file"; let from_file = &format!("{}/{}", at.as_string(), filename); let to_dir = "test_symlink_to_dir_2args_to_dir"; - let to_file = &format!("{}/{}", to_dir, filename); + let to_file = &format!("{to_dir}/{filename}"); at.mkdir(to_dir); at.touch(from_file); @@ -441,8 +438,7 @@ fn test_symlink_missing_destination() { at.touch(file); ucmd.args(&["-s", "-T", file]).fails().stderr_is(format!( - "ln: missing destination file operand after '{}'", - file + "ln: missing destination file operand after '{file}'\n" )); } @@ -475,7 +471,7 @@ fn test_symlink_relative_path() { // Thanks to -r, all the ../ should be resolved to a single file ucmd.args(&["-r", "-s", "-v", &p.to_string_lossy(), link]) .succeeds() - .stdout_only(format!("'{}' -> '{}'\n", link, file_a)); + .stdout_only(format!("'{link}' -> '{file_a}'\n")); assert!(at.is_symlink(link)); assert_eq!(at.resolve_link(link), file_a); diff --git a/tests/by-util/test_logname.rs b/tests/by-util/test_logname.rs index 43fce6851..3d2081641 100644 --- a/tests/by-util/test_logname.rs +++ b/tests/by-util/test_logname.rs @@ -12,7 +12,7 @@ fn test_normal() { println!("env::var(CI).is_ok() = {}", env::var("CI").is_ok()); for (key, value) in env::vars() { - println!("{}: {}", key, value); + println!("{key}: {value}"); } if (is_ci() || uucore::os::is_wsl_1()) && result.stderr_str().contains("no login name") { // ToDO: investigate WSL failure diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 159f21de3..f1ab3eea4 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -435,44 +435,43 @@ fn test_ls_io_errors() { // on the mac and in certain Linux containers bad fds are typed as dirs, // however sometimes bad fds are typed as links and directory entry on links won't fail - if PathBuf::from(format!("/dev/fd/{fd}", fd = fd2)).is_dir() { + if PathBuf::from(format!("/dev/fd/{fd2}")).is_dir() { scene .ucmd() .arg("-alR") - .arg(format!("/dev/fd/{fd}", fd = fd2)) + .arg(format!("/dev/fd/{fd2}")) .fails() .stderr_contains(format!( - "cannot open directory '/dev/fd/{fd}': Bad file descriptor", - fd = fd2 + "cannot open directory '/dev/fd/{fd2}': Bad file descriptor" )) - .stdout_does_not_contain(format!("{fd}:\n", fd = fd2)); + .stdout_does_not_contain(format!("{fd2}:\n")); scene .ucmd() .arg("-RiL") - .arg(format!("/dev/fd/{fd}", fd = fd2)) + .arg(format!("/dev/fd/{fd2}")) .fails() - .stderr_contains(format!("cannot open directory '/dev/fd/{fd}': Bad file descriptor", fd = fd2)) + .stderr_contains(format!("cannot open directory '/dev/fd/{fd2}': Bad file descriptor")) // don't double print bad fd errors - .stderr_does_not_contain(format!("ls: cannot open directory '/dev/fd/{fd}': Bad file descriptor\nls: cannot open directory '/dev/fd/{fd}': Bad file descriptor", fd = fd2)); + .stderr_does_not_contain(format!("ls: cannot open directory '/dev/fd/{fd2}': Bad file descriptor\nls: cannot open directory '/dev/fd/{fd2}': Bad file descriptor")); } else { scene .ucmd() .arg("-alR") - .arg(format!("/dev/fd/{fd}", fd = fd2)) + .arg(format!("/dev/fd/{fd2}")) .succeeds(); scene .ucmd() .arg("-RiL") - .arg(format!("/dev/fd/{fd}", fd = fd2)) + .arg(format!("/dev/fd/{fd2}")) .succeeds(); } scene .ucmd() .arg("-alL") - .arg(format!("/dev/fd/{fd}", fd = fd2)) + .arg(format!("/dev/fd/{fd2}")) .succeeds(); let _ = close(fd2); @@ -685,7 +684,7 @@ fn test_ls_width() { .args(&option.split(' ').collect::>()) .arg("-C") .fails() - .stderr_only("ls: invalid line width: '1a'"); + .stderr_only("ls: invalid line width: '1a'\n"); } } @@ -736,7 +735,7 @@ fn test_ls_columns() { .arg("-C") .succeeds() .stdout_is("test-columns-1 test-columns-2 test-columns-3 test-columns-4\n") - .stderr_is("ls: ignoring invalid width in environment variable COLUMNS: 'garbage'"); + .stderr_is("ls: ignoring invalid width in environment variable COLUMNS: 'garbage'\n"); } scene .ucmd() @@ -1932,10 +1931,7 @@ fn test_ls_color() { .arg("-w=15") .arg("-C") .succeeds() - .stdout_only(format!( - "{} test-color\nb {}\n", - a_with_colors, z_with_colors - )); + .stdout_only(format!("{a_with_colors} test-color\nb {z_with_colors}\n")); } #[cfg(unix)] @@ -2041,7 +2037,7 @@ fn test_ls_indicator_style() { // Verify that classify and file-type both contain indicators for symlinks. scene .ucmd() - .arg(format!("--indicator-style={}", opt)) + .arg(format!("--indicator-style={opt}")) .succeeds() .stdout_contains("@") .stdout_contains("|"); @@ -2091,7 +2087,7 @@ fn test_ls_indicator_style() { // Verify that classify and file-type both contain indicators for symlinks. scene .ucmd() - .arg(format!("--indicator-style={}", opt)) + .arg(format!("--indicator-style={opt}")) .succeeds() .stdout_contains("/"); } @@ -2108,7 +2104,7 @@ fn test_ls_indicator_style() { // Verify that classify and file-type both contain indicators for symlinks. scene .ucmd() - .arg(format!("--indicator-style={}", opt)) + .arg(format!("--indicator-style={opt}")) .succeeds() .stdout_contains("@"); } @@ -2389,7 +2385,7 @@ fn test_ls_quoting_style() { .arg(arg) .arg("one\ntwo") .succeeds() - .stdout_only(format!("{}\n", correct)); + .stdout_only(format!("{correct}\n")); } for (arg, correct) in [ @@ -2405,7 +2401,7 @@ fn test_ls_quoting_style() { .arg("--show-control-chars") .arg("one\ntwo") .succeeds() - .stdout_only(format!("{}\n", correct)); + .stdout_only(format!("{correct}\n")); } for (arg, correct) in [ @@ -2427,7 +2423,7 @@ fn test_ls_quoting_style() { .arg(arg) .arg("one\\two") .succeeds() - .stdout_only(format!("{}\n", correct)); + .stdout_only(format!("{correct}\n")); } // Tests for a character that forces quotation in shell-style escaping @@ -2443,7 +2439,7 @@ fn test_ls_quoting_style() { .arg(arg) .arg("one\n&two") .succeeds() - .stdout_only(format!("{}\n", correct)); + .stdout_only(format!("{correct}\n")); } } @@ -2474,7 +2470,7 @@ fn test_ls_quoting_style() { .arg(arg) .arg("one two") .succeeds() - .stdout_only(format!("{}\n", correct)); + .stdout_only(format!("{correct}\n")); } scene.ucmd().arg("one").succeeds().stdout_only("one\n"); @@ -2498,7 +2494,7 @@ fn test_ls_quoting_style() { .arg(arg) .arg("one") .succeeds() - .stdout_only(format!("{}\n", correct)); + .stdout_only(format!("{correct}\n")); } } @@ -3028,31 +3024,31 @@ fn test_ls_path() { let file1 = "file1"; let file2 = "file2"; let dir = "dir"; - let path = &format!("{}/{}", dir, file2); + let path = &format!("{dir}/{file2}"); at.mkdir(dir); at.touch(file1); at.touch(path); - let expected_stdout = &format!("{}\n", path); + let expected_stdout = &format!("{path}\n"); scene.ucmd().arg(path).run().stdout_is(expected_stdout); - let expected_stdout = &format!("./{}\n", path); + let expected_stdout = &format!("./{path}\n"); scene .ucmd() - .arg(format!("./{}", path)) + .arg(format!("./{path}")) .run() .stdout_is(expected_stdout); let abs_path = format!("{}/{}", at.as_string(), path); let expected_stdout = if cfg!(windows) { - format!("\'{}\'\n", abs_path) + format!("\'{abs_path}\'\n") } else { - format!("{}\n", abs_path) + format!("{abs_path}\n") }; scene.ucmd().arg(&abs_path).run().stdout_is(expected_stdout); - let expected_stdout = format!("{}\n{}\n", path, file1); + let expected_stdout = format!("{path}\n{file1}\n"); scene .ucmd() .arg(file1) diff --git a/tests/by-util/test_mkfifo.rs b/tests/by-util/test_mkfifo.rs index 18d1d53d1..f8b168195 100644 --- a/tests/by-util/test_mkfifo.rs +++ b/tests/by-util/test_mkfifo.rs @@ -7,7 +7,7 @@ fn test_invalid_arg() { #[test] fn test_create_fifo_missing_operand() { - new_ucmd!().fails().stderr_is("mkfifo: missing operand"); + new_ucmd!().fails().stderr_is("mkfifo: missing operand\n"); } #[test] @@ -46,5 +46,5 @@ fn test_create_one_fifo_already_exists() { .arg("abcdef") .arg("abcdef") .fails() - .stderr_is("mkfifo: cannot create fifo 'abcdef': File exists"); + .stderr_is("mkfifo: cannot create fifo 'abcdef': File exists\n"); } diff --git a/tests/by-util/test_mknod.rs b/tests/by-util/test_mknod.rs index d8afb3e53..c6d15e204 100644 --- a/tests/by-util/test_mknod.rs +++ b/tests/by-util/test_mknod.rs @@ -77,14 +77,14 @@ fn test_mknod_character_device_requires_major_and_minor() { .arg("test_file") .arg("c") .fails() - .status_code(1) + .code_is(1) .stderr_contains("Special files require major and minor device numbers."); new_ucmd!() .arg("test_file") .arg("c") .arg("1") .fails() - .status_code(1) + .code_is(1) .stderr_contains("Special files require major and minor device numbers."); new_ucmd!() .arg("test_file") @@ -122,6 +122,6 @@ fn test_mknod_invalid_mode() { .arg("p") .fails() .no_stdout() - .status_code(1) + .code_is(1) .stderr_contains("invalid mode"); } diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index d19f5d6d1..d6926c41b 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -473,8 +473,7 @@ fn test_tmpdir_absolute_path() { .args(&["--tmpdir=a", path]) .fails() .stderr_only(format!( - "mktemp: invalid template, '{}'; with --tmpdir, it may not be absolute\n", - path + "mktemp: invalid template, '{path}'; with --tmpdir, it may not be absolute\n" )); } @@ -673,11 +672,7 @@ fn test_mktemp_with_posixly_correct() { .env("POSIXLY_CORRECT", "1") .args(&["aXXXX", "--suffix=b"]) .fails() - .stderr_is(&format!( - "mktemp: too many templates\nTry '{} {} --help' for more information.\n", - scene.bin_path.to_string_lossy(), - scene.util_name - )); + .usage_error("too many templates"); scene .ucmd() @@ -695,7 +690,7 @@ fn test_tmpdir_env_var() { let filename = result.no_stderr().stdout_str().trim_end(); #[cfg(not(windows))] { - let template = format!(".{}tmp.XXXXXXXXXX", MAIN_SEPARATOR); + let template = format!(".{MAIN_SEPARATOR}tmp.XXXXXXXXXX"); assert_matches_template!(&template, filename); } // On Windows, `env::temp_dir()` seems to give an absolute path @@ -724,7 +719,7 @@ fn test_tmpdir_env_var() { let filename = result.no_stderr().stdout_str().trim_end(); #[cfg(not(windows))] { - let template = format!(".{}XXX", MAIN_SEPARATOR); + let template = format!(".{MAIN_SEPARATOR}XXX"); assert_matches_template!(&template, filename); } #[cfg(windows)] diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index b4470ccea..93693279b 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -55,7 +55,7 @@ fn test_mv_move_file_into_dir() { ucmd.arg(file).arg(dir).succeeds().no_stderr(); - assert!(at.file_exists(&format!("{}/{}", dir, file))); + assert!(at.file_exists(&format!("{dir}/{file}"))); } #[test] @@ -67,17 +67,17 @@ fn test_mv_move_file_between_dirs() { at.mkdir(dir1); at.mkdir(dir2); - at.touch(&format!("{}/{}", dir1, file)); + at.touch(&format!("{dir1}/{file}")); - assert!(at.file_exists(&format!("{}/{}", dir1, file))); + assert!(at.file_exists(&format!("{dir1}/{file}"))); - ucmd.arg(&format!("{}/{}", dir1, file)) + ucmd.arg(&format!("{dir1}/{file}")) .arg(dir2) .succeeds() .no_stderr(); - assert!(!at.file_exists(&format!("{}/{}", dir1, file))); - assert!(at.file_exists(&format!("{}/{}", dir2, file))); + assert!(!at.file_exists(&format!("{dir1}/{file}"))); + assert!(at.file_exists(&format!("{dir2}/{file}"))); } #[test] @@ -94,7 +94,7 @@ fn test_mv_strip_slashes() { scene.ucmd().arg(&source).arg(dir).fails(); - assert!(!at.file_exists(&format!("{}/{}", dir, file))); + assert!(!at.file_exists(&format!("{dir}/{file}"))); scene .ucmd() @@ -104,7 +104,7 @@ fn test_mv_strip_slashes() { .succeeds() .no_stderr(); - assert!(at.file_exists(&format!("{}/{}", dir, file))); + assert!(at.file_exists(&format!("{dir}/{file}"))); } #[test] @@ -124,8 +124,8 @@ fn test_mv_multiple_files() { .succeeds() .no_stderr(); - assert!(at.file_exists(&format!("{}/{}", target_dir, file_a))); - assert!(at.file_exists(&format!("{}/{}", target_dir, file_b))); + assert!(at.file_exists(&format!("{target_dir}/{file_a}"))); + assert!(at.file_exists(&format!("{target_dir}/{file_b}"))); } #[test] @@ -145,8 +145,8 @@ fn test_mv_multiple_folders() { .succeeds() .no_stderr(); - assert!(at.dir_exists(&format!("{}/{}", target_dir, dir_a))); - assert!(at.dir_exists(&format!("{}/{}", target_dir, dir_b))); + assert!(at.dir_exists(&format!("{target_dir}/{dir_a}"))); + assert!(at.dir_exists(&format!("{target_dir}/{dir_b}"))); } #[test] @@ -262,10 +262,10 @@ fn test_mv_same_file() { let file_a = "test_mv_same_file_a"; at.touch(file_a); - ucmd.arg(file_a).arg(file_a).fails().stderr_is(format!( - "mv: '{f}' and '{f}' are the same file\n", - f = file_a, - )); + ucmd.arg(file_a) + .arg(file_a) + .fails() + .stderr_is(format!("mv: '{file_a}' and '{file_a}' are the same file\n",)); } #[test] @@ -275,8 +275,7 @@ fn test_mv_same_file_not_dot_dir() { at.mkdir(dir); ucmd.arg(dir).arg(dir).fails().stderr_is(format!( - "mv: cannot move '{d}' to a subdirectory of itself, '{d}/{d}'", - d = dir, + "mv: cannot move '{dir}' to a subdirectory of itself, '{dir}/{dir}'\n", )); } @@ -306,7 +305,7 @@ fn test_mv_simple_backup() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -325,7 +324,7 @@ fn test_mv_simple_backup_with_file_extension() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -340,7 +339,7 @@ fn test_mv_arg_backup_arg_first() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -353,7 +352,7 @@ fn test_mv_custom_backup_suffix() { at.touch(file_a); at.touch(file_b); ucmd.arg("-b") - .arg(format!("--suffix={}", suffix)) + .arg(format!("--suffix={suffix}")) .arg(file_a) .arg(file_b) .succeeds() @@ -361,7 +360,7 @@ fn test_mv_custom_backup_suffix() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}{}", file_b, suffix))); + assert!(at.file_exists(&format!("{file_b}{suffix}"))); } #[test] @@ -374,7 +373,7 @@ fn test_mv_custom_backup_suffix_hyphen_value() { at.touch(file_a); at.touch(file_b); ucmd.arg("-b") - .arg(format!("--suffix={}", suffix)) + .arg(format!("--suffix={suffix}")) .arg(file_a) .arg(file_b) .succeeds() @@ -382,7 +381,7 @@ fn test_mv_custom_backup_suffix_hyphen_value() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}{}", file_b, suffix))); + assert!(at.file_exists(&format!("{file_b}{suffix}"))); } #[test] @@ -402,7 +401,7 @@ fn test_mv_custom_backup_suffix_via_env() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}{}", file_b, suffix))); + assert!(at.file_exists(&format!("{file_b}{suffix}"))); } #[test] @@ -421,7 +420,7 @@ fn test_mv_backup_numbered_with_t() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}.~1~", file_b))); + assert!(at.file_exists(&format!("{file_b}.~1~"))); } #[test] @@ -440,7 +439,7 @@ fn test_mv_backup_numbered() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}.~1~", file_b))); + assert!(at.file_exists(&format!("{file_b}.~1~"))); } #[test] @@ -459,7 +458,7 @@ fn test_mv_backup_existing() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -478,7 +477,7 @@ fn test_mv_backup_nil() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -499,7 +498,7 @@ fn test_mv_numbered_if_existing_backup_existing() { assert!(at.file_exists(file_b)); assert!(at.file_exists(file_b_backup)); - assert!(at.file_exists(&format!("{}.~2~", file_b))); + assert!(at.file_exists(&format!("{file_b}.~2~"))); } #[test] @@ -520,7 +519,7 @@ fn test_mv_numbered_if_existing_backup_nil() { assert!(at.file_exists(file_b)); assert!(at.file_exists(file_b_backup)); - assert!(at.file_exists(&format!("{}.~2~", file_b))); + assert!(at.file_exists(&format!("{file_b}.~2~"))); } #[test] @@ -539,7 +538,7 @@ fn test_mv_backup_simple() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -558,7 +557,7 @@ fn test_mv_backup_never() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}~", file_b))); + assert!(at.file_exists(&format!("{file_b}~"))); } #[test] @@ -577,7 +576,7 @@ fn test_mv_backup_none() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(!at.file_exists(&format!("{}~", file_b))); + assert!(!at.file_exists(&format!("{file_b}~"))); } #[test] @@ -596,7 +595,7 @@ fn test_mv_backup_off() { assert!(!at.file_exists(file_a)); assert!(at.file_exists(file_b)); - assert!(!at.file_exists(&format!("{}~", file_b))); + assert!(!at.file_exists(&format!("{file_b}~"))); } #[test] @@ -661,8 +660,8 @@ fn test_mv_target_dir() { assert!(!at.file_exists(file_a)); assert!(!at.file_exists(file_b)); - assert!(at.file_exists(&format!("{}/{}", dir, file_a))); - assert!(at.file_exists(&format!("{}/{}", dir, file_b))); + assert!(at.file_exists(&format!("{dir}/{file_a}"))); + assert!(at.file_exists(&format!("{dir}/{file_b}"))); } #[test] @@ -676,7 +675,7 @@ fn test_mv_target_dir_single_source() { ucmd.arg("-t").arg(dir).arg(file).succeeds().no_stderr(); assert!(!at.file_exists(file)); - assert!(at.file_exists(&format!("{}/{}", dir, file))); + assert!(at.file_exists(&format!("{dir}/{file}"))); } #[test] @@ -729,14 +728,11 @@ fn test_mv_backup_dir() { .arg(dir_a) .arg(dir_b) .succeeds() - .stdout_only(format!( - "'{}' -> '{}' (backup: '{}~')\n", - dir_a, dir_b, dir_b - )); + .stdout_only(format!("'{dir_a}' -> '{dir_b}' (backup: '{dir_b}~')\n")); assert!(!at.dir_exists(dir_a)); assert!(at.dir_exists(dir_b)); - assert!(at.dir_exists(&format!("{}~", dir_b))); + assert!(at.dir_exists(&format!("{dir_b}~"))); } #[test] @@ -772,8 +768,7 @@ fn test_mv_errors() { .arg(dir) .fails() .stderr_is(format!( - "mv: cannot overwrite directory '{}' with non-directory\n", - dir + "mv: cannot overwrite directory '{dir}' with non-directory\n" )); // $ at.mkdir dir && at.touch file @@ -805,7 +800,7 @@ fn test_mv_verbose() { .arg(file_a) .arg(file_b) .succeeds() - .stdout_only(format!("'{}' -> '{}'\n", file_a, file_b)); + .stdout_only(format!("'{file_a}' -> '{file_b}'\n")); at.touch(file_a); scene @@ -814,10 +809,7 @@ fn test_mv_verbose() { .arg(file_a) .arg(file_b) .succeeds() - .stdout_only(format!( - "'{}' -> '{}' (backup: '{}~')\n", - file_a, file_b, file_b - )); + .stdout_only(format!("'{file_a}' -> '{file_b}' (backup: '{file_b}~')\n")); } #[test] diff --git a/tests/by-util/test_nice.rs b/tests/by-util/test_nice.rs index 036723cde..6fca05ab4 100644 --- a/tests/by-util/test_nice.rs +++ b/tests/by-util/test_nice.rs @@ -63,3 +63,22 @@ fn test_command_where_command_takes_n_flag() { fn test_invalid_argument() { new_ucmd!().arg("--invalid").fails().code_is(125); } + +#[test] +fn test_bare_adjustment() { + new_ucmd!() + .args(&["-1", "echo", "-n", "a"]) + .run() + .stdout_is("a"); +} + +#[test] +fn test_trailing_empty_adjustment() { + new_ucmd!() + .args(&["-n", "1", "-n"]) + .fails() + .stderr_str() + .starts_with( + "error: The argument '--adjustment ' requires a value but none was supplied", + ); +} diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index 108c26fd0..e162196f2 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -60,8 +60,7 @@ fn test_from_iec_i_requires_suffix() { .fails() .code_is(2) .stderr_is(format!( - "numfmt: missing 'i' suffix in input: '{}' (e.g Ki/Mi/Gi)", - number + "numfmt: missing 'i' suffix in input: '{number}' (e.g Ki/Mi/Gi)\n" )); } } @@ -151,7 +150,7 @@ fn test_header_error_if_non_numeric() { new_ucmd!() .args(&["--header=two"]) .run() - .stderr_is("numfmt: invalid header value 'two'"); + .stderr_is("numfmt: invalid header value 'two'\n"); } #[test] @@ -159,7 +158,7 @@ fn test_header_error_if_0() { new_ucmd!() .args(&["--header=0"]) .run() - .stderr_is("numfmt: invalid header value '0'"); + .stderr_is("numfmt: invalid header value '0'\n"); } #[test] @@ -167,7 +166,7 @@ fn test_header_error_if_negative() { new_ucmd!() .args(&["--header=-3"]) .run() - .stderr_is("numfmt: invalid header value '-3'"); + .stderr_is("numfmt: invalid header value '-3'\n"); } #[test] @@ -458,7 +457,7 @@ fn test_delimiter_must_not_be_more_than_one_character() { new_ucmd!() .args(&["--delimiter", "sad"]) .fails() - .stderr_is("numfmt: the delimiter must be a single character"); + .stderr_is("numfmt: the delimiter must be a single character\n"); } #[test] @@ -687,11 +686,11 @@ fn test_invalid_padding_value() { for padding_value in padding_values { new_ucmd!() - .arg(format!("--padding={}", padding_value)) + .arg(format!("--padding={padding_value}")) .arg("5") .fails() .code_is(1) - .stderr_contains(format!("invalid padding value '{}'", padding_value)); + .stderr_contains(format!("invalid padding value '{padding_value}'")); } } @@ -719,10 +718,10 @@ fn test_invalid_unit_size() { for command in commands { for invalid_size in &invalid_sizes { new_ucmd!() - .arg(format!("--{}-unit={}", command, invalid_size)) + .arg(format!("--{command}-unit={invalid_size}")) .fails() .code_is(1) - .stderr_contains(format!("invalid unit size: '{}'", invalid_size)); + .stderr_contains(format!("invalid unit size: '{invalid_size}'")); } } } @@ -737,8 +736,7 @@ fn test_valid_but_forbidden_suffix() { .fails() .code_is(2) .stderr_contains(format!( - "rejecting suffix in input: '{}' (consider using --from)", - number + "rejecting suffix in input: '{number}' (consider using --from)" )); } } @@ -805,7 +803,7 @@ fn test_format_with_zero_padding() { for format in formats { new_ucmd!() - .args(&[format!("--format={}", format), String::from("1234")]) + .args(&[format!("--format={format}"), String::from("1234")]) .succeeds() .stdout_is("001234\n"); } @@ -851,7 +849,7 @@ fn test_format_with_precision() { new_ucmd!() .args(&["--format=%.1f", input]) .succeeds() - .stdout_is(format!("{}\n", expected)); + .stdout_is(format!("{expected}\n")); } let values = vec![("0.99", "0.99"), ("1", "1.00"), ("1.01", "1.01")]; @@ -860,7 +858,7 @@ fn test_format_with_precision() { new_ucmd!() .args(&["--format=%.2f", input]) .succeeds() - .stdout_is(format!("{}\n", expected)); + .stdout_is(format!("{expected}\n")); } } @@ -872,7 +870,7 @@ fn test_format_with_precision_and_down_rounding() { new_ucmd!() .args(&["--format=%.1f", input, "--round=down"]) .succeeds() - .stdout_is(format!("{}\n", expected)); + .stdout_is(format!("{expected}\n")); } } @@ -883,12 +881,12 @@ fn test_format_with_precision_and_to_arg() { for (format, expected) in values { new_ucmd!() .args(&[ - format!("--format={}", format), + format!("--format={format}"), "9991239123".to_string(), "--to=si".to_string(), ]) .succeeds() - .stdout_is(format!("{}\n", expected)); + .stdout_is(format!("{expected}\n")); } } @@ -900,7 +898,7 @@ fn test_format_preserve_trailing_zeros_if_no_precision_is_specified() { new_ucmd!() .args(&["--format=%f", value]) .succeeds() - .stdout_is(format!("{}\n", value)); + .stdout_is(format!("{value}\n")); } } @@ -910,10 +908,10 @@ fn test_format_without_percentage_directive() { for invalid_format in invalid_formats { new_ucmd!() - .arg(format!("--format={}", invalid_format)) + .arg(format!("--format={invalid_format}")) .fails() .code_is(1) - .stderr_contains(format!("format '{}' has no % directive", invalid_format)); + .stderr_contains(format!("format '{invalid_format}' has no % directive")); } } @@ -922,10 +920,10 @@ fn test_format_with_percentage_directive_at_end() { let invalid_format = "hello%"; new_ucmd!() - .arg(format!("--format={}", invalid_format)) + .arg(format!("--format={invalid_format}")) .fails() .code_is(1) - .stderr_contains(format!("format '{}' ends in %", invalid_format)); + .stderr_contains(format!("format '{invalid_format}' ends in %")); } #[test] @@ -933,12 +931,11 @@ fn test_format_with_too_many_percentage_directives() { let invalid_format = "%f %f"; new_ucmd!() - .arg(format!("--format={}", invalid_format)) + .arg(format!("--format={invalid_format}")) .fails() .code_is(1) .stderr_contains(format!( - "format '{}' has too many % directives", - invalid_format + "format '{invalid_format}' has too many % directives" )); } @@ -948,12 +945,11 @@ fn test_format_with_invalid_format() { for invalid_format in invalid_formats { new_ucmd!() - .arg(format!("--format={}", invalid_format)) + .arg(format!("--format={invalid_format}")) .fails() .code_is(1) .stderr_contains(format!( - "invalid format '{}', directive must be %[0]['][-][N][.][N]f", - invalid_format + "invalid format '{invalid_format}', directive must be %[0]['][-][N][.][N]f" )); } } @@ -962,12 +958,11 @@ fn test_format_with_invalid_format() { fn test_format_with_width_overflow() { let invalid_format = "%18446744073709551616f"; new_ucmd!() - .arg(format!("--format={}", invalid_format)) + .arg(format!("--format={invalid_format}")) .fails() .code_is(1) .stderr_contains(format!( - "invalid format '{}' (width overflow)", - invalid_format + "invalid format '{invalid_format}' (width overflow)" )); } @@ -977,10 +972,10 @@ fn test_format_with_invalid_precision() { for invalid_format in invalid_formats { new_ucmd!() - .arg(format!("--format={}", invalid_format)) + .arg(format!("--format={invalid_format}")) .fails() .code_is(1) - .stderr_contains(format!("invalid precision in format '{}'", invalid_format)); + .stderr_contains(format!("invalid precision in format '{invalid_format}'")); } } diff --git a/tests/by-util/test_od.rs b/tests/by-util/test_od.rs index 00a408d56..c1857f3bc 100644 --- a/tests/by-util/test_od.rs +++ b/tests/by-util/test_od.rs @@ -76,7 +76,7 @@ fn test_2files() { let file2 = tmpdir.join("test2"); for (n, a) in [(1, "a"), (2, "b")] { - println!("number: {} letter:{}", n, a); + println!("number: {n} letter:{a}"); } // spell-checker:disable-next-line @@ -849,31 +849,27 @@ fn test_od_invalid_bytes() { ]; for option in &options { new_ucmd!() - .arg(format!("{}={}", option, INVALID_SIZE)) + .arg(format!("{option}={INVALID_SIZE}")) .arg("file") .fails() .code_is(1) - .stderr_only(format!( - "od: invalid {} argument '{}'", - option, INVALID_SIZE - )); + .stderr_only(format!("od: invalid {option} argument '{INVALID_SIZE}'\n")); new_ucmd!() - .arg(format!("{}={}", option, INVALID_SUFFIX)) + .arg(format!("{option}={INVALID_SUFFIX}")) .arg("file") .fails() .code_is(1) .stderr_only(format!( - "od: invalid suffix in {} argument '{}'", - option, INVALID_SUFFIX + "od: invalid suffix in {option} argument '{INVALID_SUFFIX}'\n" )); #[cfg(not(target_pointer_width = "128"))] new_ucmd!() - .arg(format!("{}={}", option, BIG_SIZE)) + .arg(format!("{option}={BIG_SIZE}")) .arg("file") .fails() .code_is(1) - .stderr_only(format!("od: {} argument '{}' too large", option, BIG_SIZE)); + .stderr_only(format!("od: {option} argument '{BIG_SIZE}' too large\n")); } } diff --git a/tests/by-util/test_paste.rs b/tests/by-util/test_paste.rs index 088a27eae..977645bee 100644 --- a/tests/by-util/test_paste.rs +++ b/tests/by-util/test_paste.rs @@ -162,7 +162,7 @@ fn test_data() { let (at, mut ucmd) = at_and_ucmd!(); let mut ins = vec![]; for (i, _in) in example.ins.iter().enumerate() { - let file = format!("in{}", i); + let file = format!("in{i}"); at.write(&file, _in); ins.push(file); } diff --git a/tests/by-util/test_pinky.rs b/tests/by-util/test_pinky.rs index 6dd85b6be..da4aab605 100644 --- a/tests/by-util/test_pinky.rs +++ b/tests/by-util/test_pinky.rs @@ -35,8 +35,7 @@ fn test_long_format() { let real_name = user_info.replace('&', &pw.name.capitalize()); let ts = TestScenario::new(util_name!()); ts.ucmd().arg("-l").arg(login).succeeds().stdout_is(format!( - "Login name: {:<28}In real life: {}\nDirectory: {:<29}Shell: {}\n\n", - login, real_name, user_dir, user_shell + "Login name: {login:<28}In real life: {real_name}\nDirectory: {user_dir:<29}Shell: {user_shell}\n\n" )); ts.ucmd() @@ -44,8 +43,7 @@ fn test_long_format() { .arg(login) .succeeds() .stdout_is(format!( - "Login name: {:<28}In real life: {1}\n\n", - login, real_name + "Login name: {login:<28}In real life: {real_name}\n\n" )); } diff --git a/tests/by-util/test_pr.rs b/tests/by-util/test_pr.rs index 20abd1a24..4e2667b6f 100644 --- a/tests/by-util/test_pr.rs +++ b/tests/by-util/test_pr.rs @@ -163,7 +163,7 @@ fn test_with_valid_page_ranges() { scenario .args(&["--pages=20:5", test_file_path]) .fails() - .stderr_is("pr: invalid --pages argument '20:5'") + .stderr_is("pr: invalid --pages argument '20:5'\n") .stdout_is(""); new_ucmd!() .args(&["--pages=1:5", test_file_path]) @@ -172,17 +172,17 @@ fn test_with_valid_page_ranges() { new_ucmd!() .args(&["--pages=-1:5", test_file_path]) .fails() - .stderr_is("pr: invalid --pages argument '-1:5'") + .stderr_is("pr: invalid --pages argument '-1:5'\n") .stdout_is(""); new_ucmd!() .args(&["--pages=1:-5", test_file_path]) .fails() - .stderr_is("pr: invalid --pages argument '1:-5'") + .stderr_is("pr: invalid --pages argument '1:-5'\n") .stdout_is(""); new_ucmd!() .args(&["--pages=5:1", test_file_path]) .fails() - .stderr_is("pr: invalid --pages argument '5:1'") + .stderr_is("pr: invalid --pages argument '5:1'\n") .stdout_is(""); } @@ -364,13 +364,13 @@ fn test_with_mpr_and_column_options() { new_ucmd!() .args(&["--column=2", "-m", "-n", test_file_path]) .fails() - .stderr_is("pr: cannot specify number of columns when printing in parallel") + .stderr_is("pr: cannot specify number of columns when printing in parallel\n") .stdout_is(""); new_ucmd!() .args(&["-a", "-m", "-n", test_file_path]) .fails() - .stderr_is("pr: cannot specify both printing across and printing in parallel") + .stderr_is("pr: cannot specify both printing across and printing in parallel\n") .stdout_is(""); } diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index 2bc983b02..4441aebd9 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -29,8 +29,8 @@ fn test_canonicalize() { let (at, mut ucmd) = at_and_ucmd!(); let actual = ucmd.arg("-f").arg(".").run().stdout_move_str(); let expect = at.root_dir_resolved() + "\n"; - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); assert_eq!(actual, expect); } @@ -39,8 +39,8 @@ fn test_canonicalize_existing() { let (at, mut ucmd) = at_and_ucmd!(); let actual = ucmd.arg("-e").arg(".").run().stdout_move_str(); let expect = at.root_dir_resolved() + "\n"; - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); assert_eq!(actual, expect); } @@ -49,8 +49,8 @@ fn test_canonicalize_missing() { let (at, mut ucmd) = at_and_ucmd!(); let actual = ucmd.arg("-m").arg(GIBBERISH).run().stdout_move_str(); let expect = path_concat!(at.root_dir_resolved(), GIBBERISH) + "\n"; - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); assert_eq!(actual, expect); } @@ -61,8 +61,8 @@ fn test_long_redirection_to_current_dir() { let dir = path_concat!(".", ..128); let actual = ucmd.arg("-n").arg("-m").arg(dir).run().stdout_move_str(); let expect = at.root_dir_resolved(); - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); assert_eq!(actual, expect); } @@ -77,8 +77,8 @@ fn test_long_redirection_to_root() { .run() .stdout_move_str(); let expect = get_root_path(); - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); assert_eq!(actual, expect); } @@ -214,21 +214,21 @@ fn test_canonicalize_trailing_slash_regfile() { .stdout_contains("regfile"); scene .ucmd() - .args(&["-fv", &format!("./{}/", name)]) + .args(&["-fv", &format!("./{name}/")]) .fails() .code_is(1) .stderr_contains(NOT_A_DIRECTORY) .no_stdout(); scene .ucmd() - .args(&["-fv", &format!("{}/more", name)]) + .args(&["-fv", &format!("{name}/more")]) .fails() .code_is(1) .stderr_contains(NOT_A_DIRECTORY) .no_stdout(); scene .ucmd() - .args(&["-fv", &format!("./{}/more/", name)]) + .args(&["-fv", &format!("./{name}/more/")]) .fails() .code_is(1) .stderr_contains(NOT_A_DIRECTORY) @@ -250,28 +250,28 @@ fn test_canonicalize_trailing_slash_subdir() { .stdout_contains("subdir"); scene .ucmd() - .args(&["-f", &format!("./{}/", name)]) + .args(&["-f", &format!("./{name}/")]) .succeeds() .stdout_contains("subdir"); scene .ucmd() - .args(&["-f", &format!("{}/more", name)]) + .args(&["-f", &format!("{name}/more")]) .succeeds() .stdout_contains(path_concat!("subdir", "more")); scene .ucmd() - .args(&["-f", &format!("./{}/more/", name)]) + .args(&["-f", &format!("./{name}/more/")]) .succeeds() .stdout_contains(path_concat!("subdir", "more")); scene .ucmd() - .args(&["-f", &format!("{}/more/more2", name)]) + .args(&["-f", &format!("{name}/more/more2")]) .fails() .code_is(1) .no_stdout(); scene .ucmd() - .args(&["-f", &format!("./{}/more/more2/", name)]) + .args(&["-f", &format!("./{name}/more/more2/")]) .fails() .code_is(1) .no_stdout(); @@ -291,18 +291,18 @@ fn test_canonicalize_trailing_slash_missing() { .stdout_contains("missing"); scene .ucmd() - .args(&["-f", &format!("./{}/", name)]) + .args(&["-f", &format!("./{name}/")]) .succeeds() .stdout_contains("missing"); scene .ucmd() - .args(&["-f", &format!("{}/more", name)]) + .args(&["-f", &format!("{name}/more")]) .fails() .code_is(1) .no_stdout(); scene .ucmd() - .args(&["-f", &format!("./{}/more/", name)]) + .args(&["-f", &format!("./{name}/more/")]) .fails() .code_is(1) .no_stdout(); diff --git a/tests/by-util/test_realpath.rs b/tests/by-util/test_realpath.rs index fdbead59f..5ff98c78d 100644 --- a/tests/by-util/test_realpath.rs +++ b/tests/by-util/test_realpath.rs @@ -239,7 +239,7 @@ fn test_realpath_when_symlink_is_absolute_and_enoent() { .run() .stdout_contains("\\dir2\\bar\n") .stdout_contains("\\dir2\\baz\n") - .stderr_is("realpath: dir1/foo2: No such file or directory"); + .stderr_is("realpath: dir1/foo2: No such file or directory\n"); } #[test] @@ -255,8 +255,8 @@ fn test_realpath_when_symlink_part_is_missing() { at.relative_symlink_file("../dir2/baz", "dir1/foo3"); at.symlink_file("dir3/bar", "dir1/foo4"); - let expect1 = format!("dir2{}bar", MAIN_SEPARATOR); - let expect2 = format!("dir2{}baz", MAIN_SEPARATOR); + let expect1 = format!("dir2{MAIN_SEPARATOR}bar"); + let expect2 = format!("dir2{MAIN_SEPARATOR}baz"); ucmd.args(&["dir1/foo1", "dir1/foo2", "dir1/foo3", "dir1/foo4"]) .run() diff --git a/tests/by-util/test_relpath.rs b/tests/by-util/test_relpath.rs index 52b829fdf..753b5d755 100644 --- a/tests/by-util/test_relpath.rs +++ b/tests/by-util/test_relpath.rs @@ -87,7 +87,7 @@ fn test_relpath_with_from_no_d() { .arg(to) .arg(from) .succeeds() - .stdout_only(&format!("{}\n", expected)); + .stdout_only(&format!("{expected}\n")); } } @@ -108,7 +108,7 @@ fn test_relpath_with_from_with_d() { .ucmd() .arg(to) .arg(from) - .arg(&format!("-d{}", pwd)) + .arg(&format!("-d{pwd}")) .succeeds() .stdout_move_str(); // relax rules for windows test environment @@ -138,10 +138,10 @@ fn test_relpath_no_from_no_d() { let _result_stdout = scene.ucmd().arg(to).succeeds().stdout_move_str(); #[cfg(not(windows))] - assert_eq!(_result_stdout, format!("{}\n", to)); + assert_eq!(_result_stdout, format!("{to}\n")); // relax rules for windows test environment #[cfg(windows)] - assert!(_result_stdout.ends_with(&format!("{}\n", to))); + assert!(_result_stdout.ends_with(&format!("{to}\n"))); } } @@ -159,7 +159,7 @@ fn test_relpath_no_from_with_d() { let _result_stdout = scene .ucmd() .arg(to) - .arg(&format!("-d{}", pwd)) + .arg(&format!("-d{pwd}")) .succeeds() .stdout_move_str(); // relax rules for windows test environment diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index f642c770b..ce534af8d 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -1,3 +1,5 @@ +use std::process::Stdio; + use crate::common::util::*; #[test] @@ -23,8 +25,7 @@ fn test_rm_failed() { let file = "test_rm_one_file"; // Doesn't exist ucmd.arg(file).fails().stderr_contains(&format!( - "cannot remove '{}': No such file or directory", - file + "cannot remove '{file}': No such file or directory" )); } @@ -134,7 +135,7 @@ fn test_rm_empty_directory_verbose() { .arg("-v") .arg(dir) .succeeds() - .stdout_only(format!("removed directory '{}'\n", dir)); + .stdout_only(format!("removed directory '{dir}'\n")); assert!(!at.dir_exists(dir)); } @@ -143,7 +144,7 @@ fn test_rm_empty_directory_verbose() { fn test_rm_non_empty_directory() { let (at, mut ucmd) = at_and_ucmd!(); let dir = "test_rm_non_empty_dir"; - let file_a = &format!("{}/test_rm_non_empty_file_a", dir); + let file_a = &format!("{dir}/test_rm_non_empty_file_a"); at.mkdir(dir); at.touch(file_a); @@ -151,7 +152,7 @@ fn test_rm_non_empty_directory() { ucmd.arg("-d") .arg(dir) .fails() - .stderr_contains(&format!("cannot remove '{}': Directory not empty", dir)); + .stderr_contains(&format!("cannot remove '{dir}': Directory not empty")); assert!(at.file_exists(file_a)); assert!(at.dir_exists(dir)); } @@ -206,7 +207,7 @@ fn test_rm_directory_without_flag() { ucmd.arg(dir) .fails() - .stderr_contains(&format!("cannot remove '{}': Is a directory", dir)); + .stderr_contains(&format!("cannot remove '{dir}': Is a directory")); } #[test] @@ -222,7 +223,7 @@ fn test_rm_verbose() { .arg(file_a) .arg(file_b) .succeeds() - .stdout_only(format!("removed '{}'\nremoved '{}'\n", file_a, file_b)); + .stdout_only(format!("removed '{file_a}'\nremoved '{file_b}'\n")); } #[test] @@ -257,7 +258,7 @@ fn test_rm_symlink_dir() { .ucmd() .arg(link) .fails() - .stderr_contains(&format!("cannot remove '{}': Is a directory", link)); + .stderr_contains(&format!("cannot remove '{link}': Is a directory")); assert!(at.dir_exists(link)); @@ -284,18 +285,14 @@ fn test_rm_force_no_operand() { #[test] fn test_rm_no_operand() { let ts = TestScenario::new(util_name!()); - ts.ucmd().fails().stderr_is(&format!( - "{0}: missing operand\nTry '{1} {0} --help' for more information.\n", - ts.util_name, - ts.bin_path.to_string_lossy() - )); + ts.ucmd().fails().usage_error("missing operand"); } #[test] fn test_rm_verbose_slash() { let (at, mut ucmd) = at_and_ucmd!(); let dir = "test_rm_verbose_slash_directory"; - let file_a = &format!("{}/test_rm_verbose_slash_file_a", dir); + let file_a = &format!("{dir}/test_rm_verbose_slash_file_a"); at.mkdir(dir); at.touch(file_a); @@ -309,11 +306,10 @@ fn test_rm_verbose_slash() { ucmd.arg("-r") .arg("-f") .arg("-v") - .arg(&format!("{}///", dir)) + .arg(&format!("{dir}///")) .succeeds() .stdout_only(format!( - "removed '{}'\nremoved directory '{}'\n", - file_a_normalized, dir + "removed '{file_a_normalized}'\nremoved directory '{dir}'\n" )); assert!(!at.dir_exists(dir)); @@ -361,7 +357,7 @@ fn test_rm_descend_directory() { // Needed for talking with stdin on platforms where CRLF or LF matters const END_OF_LINE: &str = if cfg!(windows) { "\r\n" } else { "\n" }; - let yes = format!("y{}", END_OF_LINE); + let yes = format!("y{END_OF_LINE}"); let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; @@ -373,7 +369,12 @@ fn test_rm_descend_directory() { at.touch(file_1); at.touch(file_2); - let mut child = scene.ucmd().arg("-ri").arg("a").run_no_wait(); + let mut child = scene + .ucmd() + .set_stdin(Stdio::piped()) + .arg("-ri") + .arg("a") + .run_no_wait(); child.try_write_in(yes.as_bytes()).unwrap(); child.try_write_in(yes.as_bytes()).unwrap(); child.try_write_in(yes.as_bytes()).unwrap(); @@ -411,7 +412,7 @@ fn test_rm_prompts() { answers.sort(); - let yes = format!("y{}", END_OF_LINE); + let yes = format!("y{END_OF_LINE}"); let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; @@ -445,7 +446,12 @@ fn test_rm_prompts() { .arg(file_2) .succeeds(); - let mut child = scene.ucmd().arg("-ri").arg("a").run_no_wait(); + let mut child = scene + .ucmd() + .set_stdin(Stdio::piped()) + .arg("-ri") + .arg("a") + .run_no_wait(); for _ in 0..9 { child.try_write_in(yes.as_bytes()).unwrap(); } @@ -455,7 +461,7 @@ fn test_rm_prompts() { let mut trimmed_output = Vec::new(); for string in result.stderr_str().split("rm: ") { if !string.is_empty() { - let trimmed_string = format!("rm: {}", string).trim().to_string(); + let trimmed_string = format!("rm: {string}").trim().to_string(); trimmed_output.push(trimmed_string); } } @@ -476,7 +482,7 @@ fn test_rm_force_prompts_order() { // Needed for talking with stdin on platforms where CRLF or LF matters const END_OF_LINE: &str = if cfg!(windows) { "\r\n" } else { "\n" }; - let yes = format!("y{}", END_OF_LINE); + let yes = format!("y{END_OF_LINE}"); let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; @@ -486,15 +492,17 @@ fn test_rm_force_prompts_order() { at.touch(empty_file); // This should cause rm to prompt to remove regular empty file - let mut child = scene.ucmd().arg("-fi").arg(empty_file).run_no_wait(); + let mut child = scene + .ucmd() + .set_stdin(Stdio::piped()) + .arg("-fi") + .arg(empty_file) + .run_no_wait(); child.try_write_in(yes.as_bytes()).unwrap(); let result = child.wait().unwrap(); - let string_output = result.stderr_str(); - assert_eq!( - string_output.trim(), - "rm: remove regular empty file 'empty'?" - ); + result.stderr_only("rm: remove regular empty file 'empty'? "); + assert!(!at.file_exists(empty_file)); at.touch(empty_file); @@ -554,3 +562,19 @@ fn test_prompt_write_protected_no() { scene.ucmd().arg(file_2).pipe_in("n").succeeds(); assert!(at.file_exists(file_2)); } + +#[test] +#[cfg(not(windows))] +fn test_fifo_removal() { + use std::time::Duration; + + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkfifo("some_fifo"); + + scene + .ucmd() + .arg("some_fifo") + .timeout(Duration::from_secs(2)) + .succeeds(); +} diff --git a/tests/by-util/test_rmdir.rs b/tests/by-util/test_rmdir.rs index 4cee34bf8..df86e2423 100644 --- a/tests/by-util/test_rmdir.rs +++ b/tests/by-util/test_rmdir.rs @@ -57,7 +57,7 @@ fn test_rmdir_nonempty_directory_no_parents() { ucmd.arg(DIR) .fails() - .stderr_is(format!("rmdir: failed to remove 'dir': {}", NOT_EMPTY)); + .stderr_is(format!("rmdir: failed to remove 'dir': {NOT_EMPTY}\n")); assert!(at.dir_exists(DIR)); } @@ -70,8 +70,7 @@ fn test_rmdir_nonempty_directory_with_parents() { at.touch(NESTED_DIR_FILE); ucmd.arg("-p").arg(NESTED_DIR).fails().stderr_is(format!( - "rmdir: failed to remove 'dir/ect/ory': {}", - NOT_EMPTY + "rmdir: failed to remove 'dir/ect/ory': {NOT_EMPTY}\n" )); assert!(at.dir_exists(NESTED_DIR)); @@ -119,8 +118,7 @@ fn test_rmdir_not_a_directory() { .fails() .no_stdout() .stderr_is(format!( - "rmdir: failed to remove 'file': {}", - NOT_A_DIRECTORY + "rmdir: failed to remove 'file': {NOT_A_DIRECTORY}\n" )); } @@ -152,8 +150,7 @@ fn test_verbose_multi() { rmdir: removing directory, 'dir'\n", ) .stderr_is(format!( - "rmdir: failed to remove 'does_not_exist': {}", - NOT_FOUND + "rmdir: failed to remove 'does_not_exist': {NOT_FOUND}\n" )); } @@ -171,7 +168,7 @@ fn test_verbose_nested_failure() { "rmdir: removing directory, 'dir/ect/ory'\n\ rmdir: removing directory, 'dir/ect'\n", ) - .stderr_is(format!("rmdir: failed to remove 'dir/ect': {}", NOT_EMPTY)); + .stderr_is(format!("rmdir: failed to remove 'dir/ect': {NOT_EMPTY}\n")); } #[cfg(unix)] @@ -211,8 +208,7 @@ fn test_rmdir_remove_symlink_file() { at.symlink_file("file", "fl"); ucmd.arg("fl/").fails().stderr_is(format!( - "rmdir: failed to remove 'fl/': {}", - NOT_A_DIRECTORY + "rmdir: failed to remove 'fl/': {NOT_A_DIRECTORY}\n" )); } @@ -227,7 +223,7 @@ fn test_rmdir_remove_symlink_dir() { ucmd.arg("dl/") .fails() - .stderr_is("rmdir: failed to remove 'dl/': Symbolic link not followed"); + .stderr_is("rmdir: failed to remove 'dl/': Symbolic link not followed\n"); } #[cfg(any(target_os = "linux", target_os = "android"))] @@ -239,5 +235,5 @@ fn test_rmdir_remove_symlink_dangling() { ucmd.arg("dl/") .fails() - .stderr_is("rmdir: failed to remove 'dl/': Symbolic link not followed"); + .stderr_is("rmdir: failed to remove 'dl/': Symbolic link not followed\n"); } diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index ad224fbc7..fa73b2937 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -13,25 +13,40 @@ fn test_hex_rejects_sign_after_identifier() { .args(&["0x-123ABC"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '0x-123ABC'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '0x-123ABC'"); new_ucmd!() .args(&["0x+123ABC"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '0x+123ABC'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '0x+123ABC'"); + + new_ucmd!() + .args(&["--", "-0x-123ABC"]) + .fails() + .no_stdout() + .usage_error("invalid floating point argument: '-0x-123ABC'"); + new_ucmd!() + .args(&["--", "-0x+123ABC"]) + .fails() + .no_stdout() + .usage_error("invalid floating point argument: '-0x+123ABC'"); + + // test without "--" => argument parsed as (invalid) flag new_ucmd!() .args(&["-0x-123ABC"]) .fails() .no_stdout() - .stderr_contains("which wasn't expected, or isn't valid in this context") + .stderr_contains( + "Found argument '-0' which wasn't expected, or isn't valid in this context", + ) .stderr_contains("For more information try '--help'"); new_ucmd!() .args(&["-0x+123ABC"]) .fails() .no_stdout() - .stderr_contains("which wasn't expected, or isn't valid in this context") + .stderr_contains( + "Found argument '-0' which wasn't expected, or isn't valid in this context", + ) .stderr_contains("For more information try '--help'"); } @@ -66,8 +81,7 @@ fn test_hex_identifier_in_wrong_place() { .args(&["1234ABCD0x"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '1234ABCD0x'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '1234ABCD0x'"); } #[test] @@ -119,38 +133,32 @@ fn test_invalid_float() { .args(&["1e2.3"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '1e2.3'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '1e2.3'"); new_ucmd!() .args(&["1e2.3", "2"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '1e2.3'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '1e2.3'"); new_ucmd!() .args(&["1", "1e2.3"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '1e2.3'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '1e2.3'"); new_ucmd!() .args(&["1e2.3", "2", "3"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '1e2.3'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '1e2.3'"); new_ucmd!() .args(&["1", "1e2.3", "3"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '1e2.3'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '1e2.3'"); new_ucmd!() .args(&["1", "2", "1e2.3"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '1e2.3'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '1e2.3'"); } #[test] @@ -159,8 +167,7 @@ fn test_width_invalid_float() { .args(&["-w", "1e2.3"]) .fails() .no_stdout() - .stderr_contains("invalid floating point argument: '1e2.3'") - .stderr_contains("for more information."); + .usage_error("invalid floating point argument: '1e2.3'"); } // ---- Tests for the big integer based path ---- @@ -738,6 +745,5 @@ fn test_invalid_zero_increment_value() { .args(&["0", "0", "1"]) .fails() .no_stdout() - .stderr_contains("invalid Zero increment value: '0'") - .stderr_contains("for more information."); + .usage_error("invalid Zero increment value: '0'"); } diff --git a/tests/by-util/test_sleep.rs b/tests/by-util/test_sleep.rs index c7c6b3af1..b6b573508 100644 --- a/tests/by-util/test_sleep.rs +++ b/tests/by-util/test_sleep.rs @@ -9,6 +9,10 @@ fn test_invalid_time_interval() { .arg("xyz") .fails() .usage_error("invalid time interval 'xyz'"); + new_ucmd!() + .args(&["--", "-1"]) + .fails() + .usage_error("invalid time interval '-1'"); } #[test] @@ -75,7 +79,7 @@ fn test_sleep_zero_duration() { #[test] fn test_sleep_no_argument() { - new_ucmd!().fails(); + new_ucmd!().fails().usage_error("missing operand"); } #[test] diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index a03217cb9..8a03432af 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -12,17 +12,17 @@ use crate::common::util::*; fn test_helper(file_name: &str, possible_args: &[&str]) { for args in possible_args { new_ucmd!() - .arg(format!("{}.txt", file_name)) + .arg(format!("{file_name}.txt")) .args(&args.split_whitespace().collect::>()) .succeeds() - .stdout_is_fixture(format!("{}.expected", file_name)); + .stdout_is_fixture(format!("{file_name}.expected")); new_ucmd!() - .arg(format!("{}.txt", file_name)) + .arg(format!("{file_name}.txt")) .arg("--debug") .args(&args.split_whitespace().collect::>()) .succeeds() - .stdout_is_fixture(format!("{}.expected.debug", file_name)); + .stdout_is_fixture(format!("{file_name}.expected.debug")); } } @@ -63,14 +63,14 @@ fn test_invalid_buffer_size() { .arg("asd") .fails() .code_is(2) - .stderr_only("sort: invalid --buffer-size argument 'asd'"); + .stderr_only("sort: invalid --buffer-size argument 'asd'\n"); new_ucmd!() .arg("-S") .arg("100f") .fails() .code_is(2) - .stderr_only("sort: invalid suffix in --buffer-size argument '100f'"); + .stderr_only("sort: invalid suffix in --buffer-size argument '100f'\n"); #[cfg(not(target_pointer_width = "128"))] new_ucmd!() @@ -80,7 +80,7 @@ fn test_invalid_buffer_size() { .arg("ext_sort.txt") .fails() .code_is(2) - .stderr_only("sort: --buffer-size argument '1Y' too large"); + .stderr_only("sort: --buffer-size argument '1Y' too large\n"); #[cfg(target_pointer_width = "32")] { @@ -94,7 +94,7 @@ fn test_invalid_buffer_size() { .fails() .code_is(2) .stderr_only(format!( - "sort: --buffer-size argument '{}' too large", + "sort: --buffer-size argument '{}' too large\n", buffer_size )); } @@ -529,7 +529,7 @@ fn test_keys_invalid_field() { new_ucmd!() .args(&["-k", "1."]) .fails() - .stderr_only("sort: failed to parse key '1.': failed to parse character index '': cannot parse integer from empty string"); + .stderr_only("sort: failed to parse key '1.': failed to parse character index '': cannot parse integer from empty string\n"); } #[test] @@ -537,7 +537,7 @@ fn test_keys_invalid_field_option() { new_ucmd!() .args(&["-k", "1.1x"]) .fails() - .stderr_only("sort: failed to parse key '1.1x': invalid option: 'x'"); + .stderr_only("sort: failed to parse key '1.1x': invalid option: 'x'\n"); } #[test] @@ -545,7 +545,7 @@ fn test_keys_invalid_field_zero() { new_ucmd!() .args(&["-k", "0.1"]) .fails() - .stderr_only("sort: failed to parse key '0.1': field index can not be 0"); + .stderr_only("sort: failed to parse key '0.1': field index can not be 0\n"); } #[test] @@ -553,7 +553,7 @@ fn test_keys_invalid_char_zero() { new_ucmd!() .args(&["-k", "1.0"]) .fails() - .stderr_only("sort: failed to parse key '1.0': invalid character index 0 for the start position of a field"); + .stderr_only("sort: failed to parse key '1.0': invalid character index 0 for the start position of a field\n"); } #[test] @@ -801,7 +801,7 @@ fn test_check_unique() { .pipe_in("A\nA\n") .fails() .code_is(1) - .stderr_only("sort: -:2: disorder: A"); + .stderr_only("sort: -:2: disorder: A\n"); } #[test] @@ -810,21 +810,21 @@ fn test_dictionary_and_nonprinting_conflicts() { for restricted_arg in ["d", "i"] { for conflicting_arg in &conflicting_args { new_ucmd!() - .arg(&format!("-{}{}", restricted_arg, conflicting_arg)) + .arg(&format!("-{restricted_arg}{conflicting_arg}")) .fails(); } for conflicting_arg in &conflicting_args { new_ucmd!() .args(&[ - format!("-{}", restricted_arg).as_str(), + format!("-{restricted_arg}").as_str(), "-k", - &format!("1,1{}", conflicting_arg), + &format!("1,1{conflicting_arg}"), ]) .succeeds(); } for conflicting_arg in &conflicting_args { new_ucmd!() - .args(&["-k", &format!("1{},1{}", restricted_arg, conflicting_arg)]) + .args(&["-k", &format!("1{restricted_arg},1{conflicting_arg}")]) .fails(); } } @@ -844,12 +844,12 @@ fn test_nonexistent_file() { new_ucmd!() .arg("nonexistent.txt") .fails() - .status_code(2) + .code_is(2) .stderr_only( #[cfg(not(windows))] - "sort: cannot read: nonexistent.txt: No such file or directory", + "sort: cannot read: nonexistent.txt: No such file or directory\n", #[cfg(windows)] - "sort: cannot read: nonexistent.txt: The system cannot find the file specified.", + "sort: cannot read: nonexistent.txt: The system cannot find the file specified.\n", ); } @@ -928,7 +928,7 @@ fn test_compress_fail() { "10", ]) .fails() - .stderr_only("sort: couldn't execute compress program: errno 2"); + .stderr_only("sort: couldn't execute compress program: errno 2\n"); // With coverage, it fails with a different error: // "thread 'main' panicked at 'called `Option::unwrap()` on ... // So, don't check the output @@ -1015,12 +1015,12 @@ fn test_verifies_out_file() { .pipe_in(input) .ignore_stdin_write_error() .fails() - .status_code(2) + .code_is(2) .stderr_only( #[cfg(not(windows))] - "sort: open failed: nonexistent_dir/nonexistent_file: No such file or directory", + "sort: open failed: nonexistent_dir/nonexistent_file: No such file or directory\n", #[cfg(windows)] - "sort: open failed: nonexistent_dir/nonexistent_file: The system cannot find the path specified.", + "sort: open failed: nonexistent_dir/nonexistent_file: The system cannot find the path specified.\n", ); } } @@ -1036,7 +1036,7 @@ fn test_verifies_files_after_keys() { "nonexistent_dir/input_file", ]) .fails() - .status_code(2) + .code_is(2) .stderr_contains("failed to parse key"); } @@ -1046,8 +1046,8 @@ fn test_verifies_input_files() { new_ucmd!() .args(&["/dev/random", "nonexistent_file"]) .fails() - .status_code(2) - .stderr_is("sort: cannot read: nonexistent_file: No such file or directory"); + .code_is(2) + .stderr_is("sort: cannot read: nonexistent_file: No such file or directory\n"); } #[test] @@ -1104,7 +1104,7 @@ fn test_wrong_args_exit_code() { new_ucmd!() .arg("--misspelled") .fails() - .status_code(2) + .code_is(2) .stderr_contains("--misspelled"); } diff --git a/tests/by-util/test_split.rs b/tests/by-util/test_split.rs index 2ff448a79..a682b1b8c 100644 --- a/tests/by-util/test_split.rs +++ b/tests/by-util/test_split.rs @@ -320,7 +320,7 @@ fn test_split_lines_number() { .args(&["--lines", "2fb", "file"]) .fails() .code_is(1) - .stderr_only("split: invalid number of lines: '2fb'"); + .stderr_only("split: invalid number of lines: '2fb'\n"); } #[test] @@ -329,13 +329,15 @@ fn test_split_invalid_bytes_size() { .args(&["-b", "1024R"]) .fails() .code_is(1) - .stderr_only("split: invalid number of bytes: '1024R'"); + .stderr_only("split: invalid number of bytes: '1024R'\n"); #[cfg(not(target_pointer_width = "128"))] new_ucmd!() .args(&["-b", "1Y"]) .fails() .code_is(1) - .stderr_only("split: invalid number of bytes: '1Y': Value too large for defined data type"); + .stderr_only( + "split: invalid number of bytes: '1Y': Value too large for defined data type\n", + ); #[cfg(target_pointer_width = "32")] { let sizes = ["1000G", "10T"]; @@ -357,7 +359,7 @@ fn test_split_chunks_num_chunks_oversized_32() { .args(&["--number", "5000000000", "file"]) .fails() .code_is(1) - .stderr_only("split: Number of chunks too big"); + .stderr_only("split: Number of chunks too big\n"); } } @@ -367,7 +369,7 @@ fn test_split_stdin_num_chunks() { .args(&["--number=1"]) .fails() .code_is(1) - .stderr_only("split: -: cannot determine file size"); + .stderr_only("split: -: cannot determine file size\n"); } fn file_read(at: &AtPath, filename: &str) -> String { @@ -423,7 +425,7 @@ fn test_numeric_dynamic_suffix_length() { ucmd.args(&["-d", "-b", "1", "ninetyonebytes.txt"]) .succeeds(); for i in 0..90 { - let filename = format!("x{:02}", i); + let filename = format!("x{i:02}"); let contents = file_read(&at, &filename); assert_eq!(contents, "a"); } @@ -445,7 +447,7 @@ fn test_hex_dynamic_suffix_length() { ucmd.args(&["-x", "-b", "1", "twohundredfortyonebytes.txt"]) .succeeds(); for i in 0..240 { - let filename = format!("x{:02x}", i); + let filename = format!("x{i:02x}"); let contents = file_read(&at, &filename); assert_eq!(contents, "a"); } @@ -457,7 +459,7 @@ fn test_suffixes_exhausted() { new_ucmd!() .args(&["-b", "1", "-a", "1", "asciilowercase.txt"]) .fails() - .stderr_only("split: output file suffixes exhausted"); + .stderr_only("split: output file suffixes exhausted\n"); } #[test] @@ -699,7 +701,7 @@ fn test_guard_input() { ts.ucmd() .args(&["-C", "6", "xaa"]) .fails() - .stderr_only("split: 'xaa' would overwrite input; aborting"); + .stderr_only("split: 'xaa' would overwrite input; aborting\n"); assert_eq!(at.read("xaa"), "1\n2\n3\n"); } diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 5a6fa41f2..b404ef28e 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -53,8 +53,8 @@ fn test_terse_normal_format() { let ts = TestScenario::new(util_name!()); let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); let v_actual: Vec<&str> = actual.trim().split(' ').collect(); let mut v_expect: Vec<&str> = expect.trim().split(' ').collect(); assert!(!v_expect.is_empty()); @@ -83,8 +83,8 @@ fn test_format_created_time() { let ts = TestScenario::new(util_name!()); let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences let re = regex::Regex::new(r"\s").unwrap(); let v_actual: Vec<&str> = re.split(&actual).collect(); @@ -108,8 +108,8 @@ fn test_format_created_seconds() { let ts = TestScenario::new(util_name!()); let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences let re = regex::Regex::new(r"\s").unwrap(); let v_actual: Vec<&str> = re.split(&actual).collect(); diff --git a/tests/by-util/test_stdbuf.rs b/tests/by-util/test_stdbuf.rs index 344b759db..b4aa64040 100644 --- a/tests/by-util/test_stdbuf.rs +++ b/tests/by-util/test_stdbuf.rs @@ -61,7 +61,7 @@ fn test_stdbuf_invalid_mode_fails() { .args(&[*option, "1024R", "head"]) .fails() .code_is(125) - .stderr_only("stdbuf: invalid mode '1024R'"); + .stderr_only("stdbuf: invalid mode '1024R'\n"); #[cfg(not(target_pointer_width = "128"))] new_ucmd!() .args(&[*option, "1Y", "head"]) diff --git a/tests/by-util/test_sum.rs b/tests/by-util/test_sum.rs index 68432a647..37451c5ce 100644 --- a/tests/by-util/test_sum.rs +++ b/tests/by-util/test_sum.rs @@ -64,7 +64,7 @@ fn test_invalid_file() { at.mkdir("a"); - ucmd.arg("a").fails().stderr_is("sum: a: Is a directory"); + ucmd.arg("a").fails().stderr_is("sum: a: Is a directory\n"); } #[test] @@ -73,5 +73,5 @@ fn test_invalid_metadata() { ucmd.arg("b") .fails() - .stderr_is("sum: b: No such file or directory"); + .stderr_is("sum: b: No such file or directory\n"); } diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index 6ea075541..a82d66565 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -169,14 +169,12 @@ fn test_nc_0_wo_follow() { let ts = TestScenario::new(util_name!()); ts.ucmd() - .set_stdin(Stdio::null()) .args(&["-n0", "missing"]) .run() .no_stderr() .no_stdout() .succeeded(); ts.ucmd() - .set_stdin(Stdio::null()) .args(&["-c0", "missing"]) .run() .no_stderr() @@ -198,14 +196,12 @@ fn test_nc_0_wo_follow2() { .unwrap(); ts.ucmd() - .set_stdin(Stdio::null()) .args(&["-n0", "unreadable"]) .run() .no_stderr() .no_stdout() .succeeded(); ts.ucmd() - .set_stdin(Stdio::null()) .args(&["-c0", "unreadable"]) .run() .no_stderr() @@ -226,7 +222,6 @@ fn test_permission_denied() { .unwrap(); ts.ucmd() - .set_stdin(Stdio::null()) .arg("unreadable") .fails() .stderr_is("tail: cannot open 'unreadable' for reading: Permission denied\n") @@ -250,7 +245,6 @@ fn test_permission_denied_multiple() { .unwrap(); ts.ucmd() - .set_stdin(Stdio::null()) .args(&["file1", "unreadable", "file2"]) .fails() .stderr_is("tail: cannot open 'unreadable' for reading: Permission denied\n") @@ -275,7 +269,7 @@ fn test_follow_redirect_stdin_name_retry() { .args(&args) .fails() .no_stdout() - .stderr_is("tail: cannot follow '-' by name") + .stderr_is("tail: cannot follow '-' by name\n") .code_is(1); args.pop(); } @@ -301,14 +295,14 @@ fn test_stdin_redirect_dir() { .set_stdin(File::open(at.plus("dir")).unwrap()) .fails() .no_stdout() - .stderr_is("tail: error reading 'standard input': Is a directory") + .stderr_is("tail: error reading 'standard input': Is a directory\n") .code_is(1); ts.ucmd() .set_stdin(File::open(at.plus("dir")).unwrap()) .arg("-") .fails() .no_stdout() - .stderr_is("tail: error reading 'standard input': Is a directory") + .stderr_is("tail: error reading 'standard input': Is a directory\n") .code_is(1); } @@ -334,14 +328,14 @@ fn test_stdin_redirect_dir_when_target_os_is_macos() { .set_stdin(File::open(at.plus("dir")).unwrap()) .fails() .no_stdout() - .stderr_is("tail: cannot open 'standard input' for reading: No such file or directory") + .stderr_is("tail: cannot open 'standard input' for reading: No such file or directory\n") .code_is(1); ts.ucmd() .set_stdin(File::open(at.plus("dir")).unwrap()) .arg("-") .fails() .no_stdout() - .stderr_is("tail: cannot open 'standard input' for reading: No such file or directory") + .stderr_is("tail: cannot open 'standard input' for reading: No such file or directory\n") .code_is(1); } @@ -351,7 +345,11 @@ fn test_follow_stdin_descriptor() { let mut args = vec!["-f", "-"]; for _ in 0..2 { - let mut p = ts.ucmd().args(&args).run_no_wait(); + let mut p = ts + .ucmd() + .set_stdin(Stdio::piped()) + .args(&args) + .run_no_wait(); p.make_assertion_with_delay(500).is_alive(); p.kill() .make_assertion() @@ -373,7 +371,7 @@ fn test_follow_stdin_name_retry() { .args(&args) .run() .no_stdout() - .stderr_is("tail: cannot follow '-' by name") + .stderr_is("tail: cannot follow '-' by name\n") .code_is(1); args.pop(); } @@ -430,11 +428,7 @@ fn test_null_default() { fn test_follow_single() { let (at, mut ucmd) = at_and_ucmd!(); - let mut child = ucmd - .set_stdin(Stdio::null()) - .arg("-f") - .arg(FOOBAR_TXT) - .run_no_wait(); + let mut child = ucmd.arg("-f").arg(FOOBAR_TXT).run_no_wait(); let expected_fixture = "foobar_single_default.expected"; @@ -464,11 +458,7 @@ fn test_follow_single() { fn test_follow_non_utf8_bytes() { // Tail the test file and start following it. let (at, mut ucmd) = at_and_ucmd!(); - let mut child = ucmd - .arg("-f") - .set_stdin(Stdio::null()) - .arg(FOOBAR_TXT) - .run_no_wait(); + let mut child = ucmd.arg("-f").arg(FOOBAR_TXT).run_no_wait(); child .make_assertion_with_delay(500) @@ -504,7 +494,6 @@ fn test_follow_non_utf8_bytes() { fn test_follow_multiple() { let (at, mut ucmd) = at_and_ucmd!(); let mut child = ucmd - .set_stdin(Stdio::null()) .arg("-f") .arg(FOOBAR_TXT) .arg(FOOBAR_2_TXT) @@ -541,7 +530,6 @@ fn test_follow_multiple() { fn test_follow_name_multiple() { let (at, mut ucmd) = at_and_ucmd!(); let mut child = ucmd - .set_stdin(Stdio::null()) .arg("--follow=name") .arg(FOOBAR_TXT) .arg(FOOBAR_2_TXT) @@ -595,8 +583,7 @@ fn test_follow_multiple_untailable() { let (at, mut ucmd) = at_and_ucmd!(); at.mkdir("DIR1"); at.mkdir("DIR2"); - ucmd.set_stdin(Stdio::null()) - .arg("-f") + ucmd.arg("-f") .arg("DIR1") .arg("DIR2") .fails() @@ -634,8 +621,7 @@ fn test_follow_invalid_pid() { .fails() .no_stdout() .stderr_is(format!( - "tail: invalid PID: '{}': number too large to fit in target type\n", - max_pid + "tail: invalid PID: '{max_pid}': number too large to fit in target type\n" )); } @@ -657,15 +643,12 @@ fn test_follow_with_pid() { #[cfg(windows)] let dummy_cmd = "cmd"; - let mut dummy = Command::new(dummy_cmd) - .stdout(Stdio::null()) - .spawn() - .unwrap(); + let mut dummy = Command::new(dummy_cmd).spawn().unwrap(); let pid = dummy.id(); let mut child = ucmd .arg("-f") - .arg(format!("--pid={}", pid)) + .arg(format!("--pid={pid}")) .arg(FOOBAR_TXT) .arg(FOOBAR_2_TXT) .run_no_wait(); @@ -722,17 +705,17 @@ fn test_single_big_args() { let mut big_input = at.make_file(FILE); for i in 0..LINES { - writeln!(big_input, "Line {}", i).expect("Could not write to FILE"); + writeln!(big_input, "Line {i}").expect("Could not write to FILE"); } big_input.flush().expect("Could not flush FILE"); let mut big_expected = at.make_file(EXPECTED_FILE); for i in (LINES - N_ARG)..LINES { - writeln!(big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE"); + writeln!(big_expected, "Line {i}").expect("Could not write to EXPECTED_FILE"); } big_expected.flush().expect("Could not flush EXPECTED_FILE"); - ucmd.arg(FILE).arg("-n").arg(format!("{}", N_ARG)).run(); + ucmd.arg(FILE).arg("-n").arg(format!("{N_ARG}")).run(); // .stdout_is(at.read(EXPECTED_FILE)); } @@ -769,21 +752,21 @@ fn test_bytes_big() { let mut big_input = at.make_file(FILE); for i in 0..BYTES { let digit = from_digit((i % 10) as u32, 10).unwrap(); - write!(big_input, "{}", digit).expect("Could not write to FILE"); + write!(big_input, "{digit}").expect("Could not write to FILE"); } big_input.flush().expect("Could not flush FILE"); let mut big_expected = at.make_file(EXPECTED_FILE); for i in (BYTES - N_ARG)..BYTES { let digit = from_digit((i % 10) as u32, 10).unwrap(); - write!(big_expected, "{}", digit).expect("Could not write to EXPECTED_FILE"); + write!(big_expected, "{digit}").expect("Could not write to EXPECTED_FILE"); } big_expected.flush().expect("Could not flush EXPECTED_FILE"); let result = ucmd .arg(FILE) .arg("-c") - .arg(format!("{}", N_ARG)) + .arg(format!("{N_ARG}")) .succeeds() .stdout_move_str(); let expected = at.read(EXPECTED_FILE); @@ -805,13 +788,13 @@ fn test_lines_with_size_suffix() { let mut big_input = at.make_file(FILE); for i in 0..LINES { - writeln!(big_input, "Line {}", i).expect("Could not write to FILE"); + writeln!(big_input, "Line {i}").expect("Could not write to FILE"); } big_input.flush().expect("Could not flush FILE"); let mut big_expected = at.make_file(EXPECTED_FILE); for i in (LINES - N_ARG)..LINES { - writeln!(big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE"); + writeln!(big_expected, "Line {i}").expect("Could not write to EXPECTED_FILE"); } big_expected.flush().expect("Could not flush EXPECTED_FILE"); @@ -825,7 +808,6 @@ fn test_lines_with_size_suffix() { #[test] fn test_multiple_input_files() { new_ucmd!() - .set_stdin(Stdio::null()) .arg(FOOBAR_TXT) .arg(FOOBAR_2_TXT) .run() @@ -836,7 +818,6 @@ fn test_multiple_input_files() { #[test] fn test_multiple_input_files_missing() { new_ucmd!() - .set_stdin(Stdio::null()) .arg(FOOBAR_TXT) .arg("missing1") .arg(FOOBAR_2_TXT) @@ -845,7 +826,7 @@ fn test_multiple_input_files_missing() { .stdout_is_fixture("foobar_follow_multiple.expected") .stderr_is( "tail: cannot open 'missing1' for reading: No such file or directory\n\ - tail: cannot open 'missing2' for reading: No such file or directory", + tail: cannot open 'missing2' for reading: No such file or directory\n", ) .code_is(1); } @@ -857,14 +838,13 @@ fn test_follow_missing() { // file to appear. for follow_mode in &["--follow=descriptor", "--follow=name"] { new_ucmd!() - .set_stdin(Stdio::null()) .arg(follow_mode) .arg("missing") .run() .no_stdout() .stderr_is( "tail: cannot open 'missing' for reading: No such file or directory\n\ - tail: no files remaining", + tail: no files remaining\n", ) .code_is(1); } @@ -880,7 +860,7 @@ fn test_follow_name_stdin() { .arg("--follow=name") .arg("-") .run() - .stderr_is("tail: cannot follow '-' by name") + .stderr_is("tail: cannot follow '-' by name\n") .code_is(1); ts.ucmd() .arg("--follow=name") @@ -888,7 +868,7 @@ fn test_follow_name_stdin() { .arg("-") .arg("FILE2") .run() - .stderr_is("tail: cannot follow '-' by name") + .stderr_is("tail: cannot follow '-' by name\n") .code_is(1); } @@ -930,7 +910,6 @@ fn test_dir_follow() { at.mkdir("DIR"); for mode in &["--follow=descriptor", "--follow=name"] { ts.ucmd() - .set_stdin(Stdio::null()) .arg(mode) .arg("DIR") .run() @@ -950,7 +929,6 @@ fn test_dir_follow_retry() { let at = &ts.fixtures; at.mkdir("DIR"); ts.ucmd() - .set_stdin(Stdio::null()) .arg("--follow=descriptor") .arg("--retry") .arg("DIR") @@ -1207,12 +1185,7 @@ fn test_retry2() { let ts = TestScenario::new(util_name!()); let missing = "missing"; - let result = ts - .ucmd() - .set_stdin(Stdio::null()) - .arg(missing) - .arg("--retry") - .run(); + let result = ts.ucmd().arg(missing).arg("--retry").run(); result .stderr_is( "tail: warning: --retry ignored; --retry is useful only when following\n\ @@ -1243,7 +1216,7 @@ fn test_retry3() { let mut delay = 1500; let mut args = vec!["--follow=name", "--retry", missing, "--use-polling"]; for _ in 0..2 { - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -1296,7 +1269,7 @@ fn test_retry4() { ]; let mut delay = 1500; for _ in 0..2 { - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -1345,7 +1318,7 @@ fn test_retry5() { let mut delay = 1500; let mut args = vec!["--follow=descriptor", "--retry", missing, "--use-polling"]; for _ in 0..2 { - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -1386,7 +1359,6 @@ fn test_retry6() { let mut p = ts .ucmd() - .set_stdin(Stdio::null()) .arg("--follow=descriptor") .arg("missing") .arg("existing") @@ -1444,7 +1416,7 @@ fn test_retry7() { for _ in 0..2 { at.mkdir(untailable); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -1516,7 +1488,6 @@ fn test_retry8() { let mut p = ts .ucmd() - .set_stdin(Stdio::null()) .arg("-F") .arg("-s.1") .arg("--max-unchanged-stats=1") @@ -1577,13 +1548,12 @@ fn test_retry9() { "\ tail: 'parent_dir/watched_file' has become inaccessible: No such file or directory\n\ tail: directory containing watched file was removed\n\ - tail: {} cannot be used, reverting to polling\n\ + tail: {BACKEND} cannot be used, reverting to polling\n\ tail: 'parent_dir/watched_file' has appeared; following new file\n\ tail: 'parent_dir/watched_file' has become inaccessible: No such file or directory\n\ tail: 'parent_dir/watched_file' has appeared; following new file\n\ tail: 'parent_dir/watched_file' has become inaccessible: No such file or directory\n\ - tail: 'parent_dir/watched_file' has appeared; following new file\n", - BACKEND + tail: 'parent_dir/watched_file' has appeared; following new file\n" ); let expected_stdout = "foo\nbar\nfoo\nbar\n"; @@ -1593,7 +1563,6 @@ fn test_retry9() { at.truncate(user_path, "foo\n"); let mut p = ts .ucmd() - .set_stdin(Stdio::null()) .arg("-F") .arg("-s.1") .arg("--max-unchanged-stats=1") @@ -1666,7 +1635,7 @@ fn test_follow_descriptor_vs_rename1() { for _ in 0..2 { at.touch(file_a); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -1726,7 +1695,7 @@ fn test_follow_descriptor_vs_rename2() { for _ in 0..2 { at.touch(file_a); at.touch(file_b); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -1788,7 +1757,7 @@ fn test_follow_name_retry_headers() { let mut delay = 1500; for _ in 0..2 { - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -1850,7 +1819,7 @@ fn test_follow_name_remove() { for i in 0..2 { at.copy(source, source_copy); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -1898,7 +1867,7 @@ fn test_follow_name_truncate1() { let expected_stderr = format!("{}: {}: file truncated\n", ts.util_name, source); let args = ["--follow=name", source]; - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); let delay = 1000; p.make_assertion().is_alive(); @@ -1940,7 +1909,7 @@ fn test_follow_name_truncate2() { let expected_stderr = format!("{}: {}: file truncated\n", ts.util_name, source); let args = ["--follow=name", source]; - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); let delay = 1000; p.make_assertion().is_alive(); @@ -1983,7 +1952,7 @@ fn test_follow_name_truncate3() { let expected_stdout = "x\n"; let args = ["--follow=name", source]; - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); let delay = 1000; p.make_assertion_with_delay(delay).is_alive(); @@ -2012,7 +1981,7 @@ fn test_follow_name_truncate4() { for i in 0..2 { at.append("file", "foobar\n"); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -2061,7 +2030,7 @@ fn test_follow_truncate_fast() { at.truncate("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); at.truncate("f", "11\n12\n13\n14\n15\n"); @@ -2118,7 +2087,7 @@ fn test_follow_name_move_create1() { let delay = 500; let args = ["--follow=name", source]; - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -2171,7 +2140,7 @@ fn test_follow_name_move_create2() { let mut delay = 500; for i in 0..2 { - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -2246,7 +2215,7 @@ fn test_follow_name_move1() { let mut delay = 500; #[allow(clippy::needless_range_loop)] for i in 0..2 { - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -2310,9 +2279,8 @@ fn test_follow_name_move2() { let file2 = "file2"; let expected_stdout = format!( - "==> {0} <==\n{0}_content\n\n==> {1} <==\n{1}_content\n{0}_content\n\ - more_{1}_content\n\n==> {0} <==\nmore_{0}_content\n", - file1, file2 + "==> {file1} <==\n{file1}_content\n\n==> {file2} <==\n{file2}_content\n{file1}_content\n\ + more_{file2}_content\n\n==> {file1} <==\nmore_{file1}_content\n" ); let mut expected_stderr = format!( "{0}: {1}: No such file or directory\n\ @@ -2328,7 +2296,7 @@ fn test_follow_name_move2() { at.truncate(file1, "file1_content\n"); at.truncate(file2, "file2_content\n"); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); at.rename(file1, file2); @@ -2392,7 +2360,7 @@ fn test_follow_name_move_retry1() { let mut delay = 1500; for _ in 0..2 { at.touch(source); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); @@ -2467,9 +2435,8 @@ fn test_follow_name_move_retry2() { let file2 = "b"; let expected_stdout = format!( - "==> {0} <==\n\n==> {1} <==\n\n==> {0} <==\nx\n\n==> {1} <==\ - \nx\n\n==> {0} <==\nx2\n\n==> {1} <==\ny\n\n==> {0} <==\nz\n", - file1, file2 + "==> {file1} <==\n\n==> {file2} <==\n\n==> {file1} <==\nx\n\n==> {file2} <==\ + \nx\n\n==> {file1} <==\nx2\n\n==> {file2} <==\ny\n\n==> {file1} <==\nz\n" ); let mut expected_stderr = format!( "{0}: '{1}' has become inaccessible: No such file or directory\n\ @@ -2485,7 +2452,7 @@ fn test_follow_name_move_retry2() { at.touch(file1); at.touch(file2); - let mut p = ts.ucmd().set_stdin(Stdio::null()).args(&args).run_no_wait(); + let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); at.truncate(file1, "x\n"); @@ -2537,12 +2504,7 @@ fn test_follow_inotify_only_regular() { let ts = TestScenario::new(util_name!()); - let mut p = ts - .ucmd() - .set_stdin(Stdio::null()) - .arg("-f") - .arg("/dev/null") - .run_no_wait(); + let mut p = ts.ucmd().arg("-f").arg("/dev/null").run_no_wait(); p.make_assertion_with_delay(200).is_alive(); p.kill() @@ -2555,10 +2517,9 @@ fn test_follow_inotify_only_regular() { #[test] fn test_no_such_file() { new_ucmd!() - .set_stdin(Stdio::null()) .arg("missing") .fails() - .stderr_is("tail: cannot open 'missing' for reading: No such file or directory") + .stderr_is("tail: cannot open 'missing' for reading: No such file or directory\n") .no_stdout() .code_is(1); } @@ -3483,7 +3444,7 @@ fn test_when_argument_file_is_a_directory() { let at = &ts.fixtures; at.mkdir("dir"); - let expected = "tail: error reading 'dir': Is a directory"; + let expected = "tail: error reading 'dir': Is a directory\n"; ts.ucmd() .arg("dir") .fails() @@ -3521,7 +3482,7 @@ fn test_when_argument_file_is_a_symlink() { at.symlink_file("dir", "dir_link"); - let expected = "tail: error reading 'dir_link': Is a directory"; + let expected = "tail: error reading 'dir_link': Is a directory\n"; ts.ucmd() .arg("dir_link") .fails() @@ -3539,7 +3500,7 @@ fn test_when_argument_file_is_a_symlink_to_directory_then_error() { at.mkdir("dir"); at.symlink_file("dir", "dir_link"); - let expected = "tail: error reading 'dir_link': Is a directory"; + let expected = "tail: error reading 'dir_link': Is a directory\n"; ts.ucmd() .arg("dir_link") .fails() @@ -3597,17 +3558,17 @@ fn test_when_argument_file_is_non_existent_unix_socket_address_then_error() { #[cfg(all(not(target_os = "freebsd"), not(target_os = "macos")))] let expected_stderr = format!( - "tail: cannot open '{}' for reading: No such device or address", + "tail: cannot open '{}' for reading: No such device or address\n", socket ); #[cfg(target_os = "freebsd")] let expected_stderr = format!( - "tail: cannot open '{}' for reading: Operation not supported", + "tail: cannot open '{}' for reading: Operation not supported\n", socket ); #[cfg(target_os = "macos")] let expected_stderr = format!( - "tail: cannot open '{}' for reading: Operation not supported on socket", + "tail: cannot open '{}' for reading: Operation not supported on socket\n", socket ); @@ -3886,8 +3847,7 @@ fn test_args_when_settings_check_warnings_then_shows_warnings() { let expected_stdout = format!( "tail: warning: --retry ignored; --retry is useful only when following\n\ - {}", - file_data + {file_data}" ); scene .ucmd() @@ -3899,8 +3859,7 @@ fn test_args_when_settings_check_warnings_then_shows_warnings() { let expected_stdout = format!( "tail: warning: --retry only effective for the initial open\n\ - {}", - file_data + {file_data}" ); let mut child = scene .ucmd() @@ -3917,8 +3876,7 @@ fn test_args_when_settings_check_warnings_then_shows_warnings() { let expected_stdout = format!( "tail: warning: PID ignored; --pid=PID is useful only when following\n\ - {}", - file_data + {file_data}" ); scene .ucmd() @@ -3931,8 +3889,7 @@ fn test_args_when_settings_check_warnings_then_shows_warnings() { let expected_stdout = format!( "tail: warning: --retry ignored; --retry is useful only when following\n\ tail: warning: PID ignored; --pid=PID is useful only when following\n\ - {}", - file_data + {file_data}" ); scene .ucmd() @@ -3998,9 +3955,8 @@ fn test_args_when_settings_check_warnings_follow_indefinitely_then_warning() { let expected_stdout = format!( "tail: warning: following standard input indefinitely is ineffective\n\ ==> data <==\n\ - {}\n\ - ==> standard input <==\n", - file_data + {file_data}\n\ + ==> standard input <==\n" ); // tail -f data - < /dev/ptmx let mut child = scene @@ -4090,10 +4046,9 @@ fn test_args_when_settings_check_warnings_follow_indefinitely_then_no_warning() let pipe_data = "pipe data"; let expected_stdout = format!( "==> standard input <==\n\ - {}\n\ - ==> {} <==\n\ - {}", - pipe_data, file_name, file_data + {pipe_data}\n\ + ==> {file_name} <==\n\ + {file_data}" ); let mut child = scene .ucmd() @@ -4122,10 +4077,9 @@ fn test_args_when_settings_check_warnings_follow_indefinitely_then_no_warning() { let expected_stdout = format!( "==> standard input <==\n\ - {}\n\ - ==> {} <==\n\ - {}", - fifo_data, file_name, file_data + {fifo_data}\n\ + ==> {file_name} <==\n\ + {file_data}" ); let mut child = scene .ucmd() @@ -4143,10 +4097,9 @@ fn test_args_when_settings_check_warnings_follow_indefinitely_then_no_warning() let expected_stdout = format!( "==> standard input <==\n\ - {}\n\ - ==> {} <==\n\ - {}", - fifo_data, file_name, file_data + {fifo_data}\n\ + ==> {file_name} <==\n\ + {file_data}" ); let mut child = scene .ucmd() diff --git a/tests/by-util/test_tee.rs b/tests/by-util/test_tee.rs index 5a2f26724..5dc5a2871 100644 --- a/tests/by-util/test_tee.rs +++ b/tests/by-util/test_tee.rs @@ -70,7 +70,7 @@ fn test_tee_append() { fn test_tee_no_more_writeable_1() { // equals to 'tee /dev/full out2 (); + let content = (1..=10).map(|x| format!("{x}\n")).collect::(); let file_out = "tee_file_out"; ucmd.arg("/dev/full") @@ -90,7 +90,7 @@ fn test_tee_no_more_writeable_2() { // but currently there is no way to redirect stdout to /dev/full // so this test is disabled let (_at, mut ucmd) = at_and_ucmd!(); - let _content = (1..=10).map(|x| format!("{}\n", x)).collect::(); + let _content = (1..=10).map(|x| format!("{x}\n")).collect::(); let file_out_a = "tee_file_out_a"; let file_out_b = "tee_file_out_b"; @@ -111,7 +111,7 @@ mod linux_only { use crate::common::util::*; use std::fs::File; - use std::process::Output; + use std::process::{Output, Stdio}; fn make_broken_pipe() -> File { use libc::c_int; @@ -130,11 +130,12 @@ mod linux_only { } fn run_tee(proc: &mut UCommand) -> (String, Output) { - let content = (1..=100000).map(|x| format!("{}\n", x)).collect::(); + let content = (1..=100000).map(|x| format!("{x}\n")).collect::(); #[allow(deprecated)] let output = proc .ignore_stdin_write_error() + .set_stdin(Stdio::piped()) .run_no_wait() .pipe_in_and_wait_with_output(content.as_bytes()); @@ -203,9 +204,7 @@ mod linux_only { contents.len() ); assert!(contents.starts_with(&compare), - "Expected truncated output to be a prefix of the correct output, but it isn't.\n Correct: {}\n Compare: {}", - contents, - compare); + "Expected truncated output to be a prefix of the correct output, but it isn't.\n Correct: {contents}\n Compare: {compare}"); } #[test] diff --git a/tests/by-util/test_test.rs b/tests/by-util/test_test.rs index ff1a49ba1..146809f48 100644 --- a/tests/by-util/test_test.rs +++ b/tests/by-util/test_test.rs @@ -15,12 +15,12 @@ use std::thread::sleep; #[test] fn test_empty_test_equivalent_to_false() { - new_ucmd!().run().status_code(1); + new_ucmd!().run().code_is(1); } #[test] fn test_empty_string_is_false() { - new_ucmd!().arg("").run().status_code(1); + new_ucmd!().arg("").run().code_is(1); } #[test] @@ -61,24 +61,24 @@ fn test_some_literals() { // run the inverse of all these tests for test in &tests { - scenario.ucmd().arg("!").arg(test).run().status_code(1); + scenario.ucmd().arg("!").arg(test).run().code_is(1); } } #[test] fn test_double_not_is_false() { - new_ucmd!().args(&["!", "!"]).run().status_code(1); + new_ucmd!().args(&["!", "!"]).run().code_is(1); } #[test] fn test_and_not_is_false() { - new_ucmd!().args(&["-a", "!"]).run().status_code(1); + new_ucmd!().args(&["-a", "!"]).run().code_is(1); } #[test] fn test_not_and_is_false() { // `-a` is a literal here & has nonzero length - new_ucmd!().args(&["!", "-a"]).run().status_code(1); + new_ucmd!().args(&["!", "-a"]).run().code_is(1); } #[test] @@ -96,12 +96,12 @@ fn test_negated_or() { new_ucmd!() .args(&["!", "foo", "-o", "bar"]) .run() - .status_code(1); + .code_is(1); new_ucmd!().args(&["foo", "-o", "!", "bar"]).succeeds(); new_ucmd!() .args(&["!", "foo", "-o", "!", "bar"]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -112,10 +112,10 @@ fn test_string_length_of_nothing() { #[test] fn test_string_length_of_empty() { - new_ucmd!().args(&["-n", ""]).run().status_code(1); + new_ucmd!().args(&["-n", ""]).run().code_is(1); // STRING equivalent to -n STRING - new_ucmd!().arg("").run().status_code(1); + new_ucmd!().arg("").run().code_is(1); } #[test] @@ -136,14 +136,14 @@ fn test_zero_len_equals_zero_len() { #[test] fn test_zero_len_not_equals_zero_len_is_false() { - new_ucmd!().args(&["", "!=", ""]).run().status_code(1); + new_ucmd!().args(&["", "!=", ""]).run().code_is(1); } #[test] fn test_double_equal_is_string_comparison_op() { // undocumented but part of the GNU test suite new_ucmd!().args(&["t", "==", "t"]).succeeds(); - new_ucmd!().args(&["t", "==", "f"]).run().status_code(1); + new_ucmd!().args(&["t", "==", "f"]).run().code_is(1); } #[test] @@ -165,12 +165,7 @@ fn test_string_comparison() { // run the inverse of all these tests for test in &tests { - scenario - .ucmd() - .arg("!") - .args(&test[..]) - .run() - .status_code(1); + scenario.ucmd().arg("!").args(&test[..]).run().code_is(1); } } @@ -180,7 +175,7 @@ fn test_dangling_string_comparison_is_error() { new_ucmd!() .args(&["missing_something", "="]) .run() - .status_code(2) + .code_is(2) .stderr_is("test: missing argument after '='"); } @@ -202,7 +197,7 @@ fn test_string_operator_is_literal_after_bang() { ]; for test in &tests { - scenario.ucmd().args(&test[..]).run().status_code(1); + scenario.ucmd().args(&test[..]).run().code_is(1); } } @@ -251,12 +246,7 @@ fn test_some_int_compares() { // run the inverse of all these tests for test in &tests { - scenario - .ucmd() - .arg("!") - .args(&test[..]) - .run() - .status_code(1); + scenario.ucmd().arg("!").args(&test[..]).run().code_is(1); } } @@ -288,12 +278,7 @@ fn test_negative_int_compare() { // run the inverse of all these tests for test in &tests { - scenario - .ucmd() - .arg("!") - .args(&test[..]) - .run() - .status_code(1); + scenario.ucmd().arg("!").args(&test[..]).run().code_is(1); } } @@ -302,8 +287,8 @@ fn test_float_inequality_is_error() { new_ucmd!() .args(&["123.45", "-ge", "6"]) .run() - .status_code(2) - .stderr_is("test: invalid integer '123.45'"); + .code_is(2) + .stderr_is("test: invalid integer '123.45'\n"); } #[test] @@ -320,16 +305,16 @@ fn test_invalid_utf8_integer_compare() { cmd.raw.arg(arg); cmd.run() - .status_code(2) - .stderr_is("test: invalid integer $'fo\\x80o'"); + .code_is(2) + .stderr_is("test: invalid integer $'fo\\x80o'\n"); let mut cmd = new_ucmd!(); cmd.raw.arg(arg); cmd.arg("-eq").arg("456"); cmd.run() - .status_code(2) - .stderr_is("test: invalid integer $'fo\\x80o'"); + .code_is(2) + .stderr_is("test: invalid integer $'fo\\x80o'\n"); } #[test] @@ -347,11 +332,11 @@ fn test_file_is_newer_than_and_older_than_itself() { new_ucmd!() .args(&["regular_file", "-nt", "regular_file"]) .run() - .status_code(1); + .code_is(1); new_ucmd!() .args(&["regular_file", "-ot", "regular_file"]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -417,7 +402,7 @@ fn test_nonexistent_file_does_not_exist() { new_ucmd!() .args(&["-e", "nonexistent_file"]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -425,7 +410,7 @@ fn test_nonexistent_file_is_not_regular() { new_ucmd!() .args(&["-f", "nonexistent_file"]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -517,7 +502,7 @@ fn test_nonexistent_file_size_test_is_false() { new_ucmd!() .args(&["-s", "nonexistent_file"]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -583,15 +568,12 @@ fn test_file_is_sticky() { #[test] fn test_file_is_not_sticky() { - new_ucmd!() - .args(&["-k", "regular_file"]) - .run() - .status_code(1); + new_ucmd!().args(&["-k", "regular_file"]).run().code_is(1); } #[test] fn test_solo_empty_parenthetical_is_error() { - new_ucmd!().args(&["(", ")"]).run().status_code(2); + new_ucmd!().args(&["(", ")"]).run().code_is(2); } #[test] @@ -630,7 +612,7 @@ fn test_parenthesized_literal() { .arg(test) .arg(")") .run() - .status_code(1); + .code_is(1); } } @@ -638,7 +620,7 @@ fn test_parenthesized_literal() { fn test_parenthesized_op_compares_literal_parenthesis() { // ensure we aren’t treating this case as “string length of literal equal // sign” - new_ucmd!().args(&["(", "=", ")"]).run().status_code(1); + new_ucmd!().args(&["(", "=", ")"]).run().code_is(1); } #[test] @@ -659,21 +641,13 @@ fn test_parenthesized_string_comparison() { // run the inverse of all these tests for test in &tests { - scenario - .ucmd() - .arg("!") - .args(&test[..]) - .run() - .status_code(1); + scenario.ucmd().arg("!").args(&test[..]).run().code_is(1); } } #[test] fn test_parenthesized_right_parenthesis_as_literal() { - new_ucmd!() - .args(&["(", "-f", ")", ")"]) - .run() - .status_code(1); + new_ucmd!().args(&["(", "-f", ")", ")"]).run().code_is(1); } #[test] @@ -688,7 +662,7 @@ fn test_nonexistent_file_not_owned_by_euid() { new_ucmd!() .args(&["-O", "nonexistent_file"]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -711,7 +685,7 @@ fn test_nonexistent_file_not_owned_by_egid() { new_ucmd!() .args(&["-G", "nonexistent_file"]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -732,7 +706,7 @@ fn test_op_precedence_and_or_1_overridden_by_parentheses() { new_ucmd!() .args(&["(", " ", "-o", "", ")", "-a", ""]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -747,7 +721,7 @@ fn test_op_precedence_and_or_2_overridden_by_parentheses() { new_ucmd!() .args(&["", "-a", "(", "", "-o", " ", ")", "-a", " "]) .run() - .status_code(1); + .code_is(1); } #[test] @@ -772,7 +746,7 @@ fn test_negated_boolean_precedence() { ]; for test in &negative_tests { - scenario.ucmd().args(&test[..]).run().status_code(1); + scenario.ucmd().args(&test[..]).run().code_is(1); } } @@ -785,25 +759,25 @@ fn test_bang_bool_op_precedence() { new_ucmd!() .args(&["!", "a value", "-o", "another value"]) .run() - .status_code(1); + .code_is(1); // Introducing a UOP — even one that is equivalent to a bare string — causes // bang to invert only the first term new_ucmd!() .args(&["!", "-n", "", "-a", ""]) .run() - .status_code(1); + .code_is(1); new_ucmd!() .args(&["!", "", "-a", "-n", ""]) .run() - .status_code(1); + .code_is(1); // for compound Boolean expressions, bang inverts the _next_ expression // only, not the entire compound expression new_ucmd!() .args(&["!", "", "-a", "", "-a", ""]) .run() - .status_code(1); + .code_is(1); // parentheses can override this new_ucmd!() @@ -817,7 +791,7 @@ fn test_inverted_parenthetical_bool_op_precedence() { new_ucmd!() .args(&["!", "a value", "-o", "another value"]) .run() - .status_code(1); + .code_is(1); // only the parenthetical is inverted, not the entire expression new_ucmd!() @@ -831,7 +805,7 @@ fn test_dangling_parenthesis() { new_ucmd!() .args(&["(", "(", "a", "!=", "b", ")", "-o", "-n", "c"]) .run() - .status_code(2); + .code_is(2); new_ucmd!() .args(&["(", "(", "a", "!=", "b", ")", "-o", "-n", "c", ")"]) .succeeds(); @@ -852,22 +826,28 @@ fn test_erroneous_parenthesized_expression() { new_ucmd!() .args(&["a", "!=", "(", "b", "-a", "b", ")", "!=", "c"]) .run() - .status_code(2) - .stderr_is("test: extra argument 'b'"); + .code_is(2) + .stderr_is("test: extra argument 'b'\n"); } #[test] fn test_or_as_filename() { + new_ucmd!().args(&["x", "-a", "-z", "-o"]).run().code_is(1); +} + +#[test] +#[ignore = "TODO: Busybox has this working"] +fn test_filename_or_with_equal() { new_ucmd!() - .args(&["x", "-a", "-z", "-o"]) + .args(&["-f", "=", "a", "-o", "b"]) .run() - .status_code(1); + .code_is(0); } #[test] #[ignore = "GNU considers this an error"] fn test_string_length_and_nothing() { - new_ucmd!().args(&["-n", "a", "-a"]).run().status_code(2); + new_ucmd!().args(&["-n", "a", "-a"]).run().code_is(2); } #[test] @@ -883,7 +863,7 @@ fn test_bracket_syntax_failure() { let scenario = TestScenario::new("["); let mut ucmd = scenario.ucmd(); - ucmd.args(&["1", "-eq", "2", "]"]).run().status_code(1); + ucmd.args(&["1", "-eq", "2", "]"]).run().code_is(1); } #[test] @@ -894,8 +874,8 @@ fn test_bracket_syntax_missing_right_bracket() { // Missing closing bracket takes precedence over other possible errors. ucmd.args(&["1", "-eq"]) .run() - .status_code(2) - .stderr_is("[: missing ']'"); + .code_is(2) + .stderr_is("[: missing ']'\n"); } #[test] diff --git a/tests/by-util/test_timeout.rs b/tests/by-util/test_timeout.rs index 2dc8da8fe..79d128d51 100644 --- a/tests/by-util/test_timeout.rs +++ b/tests/by-util/test_timeout.rs @@ -13,7 +13,7 @@ fn test_invalid_arg() { fn test_subcommand_return_code() { new_ucmd!().arg("1").arg("true").succeeds(); - new_ucmd!().arg("1").arg("false").run().status_code(1); + new_ucmd!().arg("1").arg("false").run().code_is(1); } #[test] @@ -48,11 +48,11 @@ fn test_verbose() { new_ucmd!() .args(&[verbose_flag, ".1", "sleep", "10"]) .fails() - .stderr_only("timeout: sending signal TERM to command 'sleep'"); + .stderr_only("timeout: sending signal TERM to command 'sleep'\n"); new_ucmd!() .args(&[verbose_flag, "-s0", "-k.1", ".1", "sleep", "10"]) .fails() - .stderr_only("timeout: sending signal EXIT to command 'sleep'\ntimeout: sending signal KILL to command 'sleep'"); + .stderr_only("timeout: sending signal EXIT to command 'sleep'\ntimeout: sending signal KILL to command 'sleep'\n"); } } diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 3585fcf97..7ae8a3905 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -52,7 +52,7 @@ fn str_to_filetime(format: &str, s: &str) -> FileTime { let d = match time::OffsetDateTime::now_local() { Ok(now) => now, Err(e) => { - panic!("Error {} retrieving the OffsetDateTime::now_local", e); + panic!("Error {e} retrieving the OffsetDateTime::now_local"); } }; let offset_dt = tm.assume_offset(d.offset()); @@ -654,7 +654,7 @@ fn get_dst_switch_hour() -> Option { let now = match time::OffsetDateTime::now_local() { Ok(now) => now, Err(e) => { - panic!("Error {} retrieving the OffsetDateTime::now_local", e); + panic!("Error {e} retrieving the OffsetDateTime::now_local"); } }; @@ -712,8 +712,7 @@ fn test_touch_no_such_file_error_msg() { let path_str = path.to_str().unwrap(); new_ucmd!().arg(&path).fails().stderr_only(format!( - "touch: cannot touch '{}': No such file or directory", - path_str + "touch: cannot touch '{path_str}': No such file or directory\n" )); } @@ -755,7 +754,7 @@ fn test_touch_permission_denied_error_msg() { let full_path = at.plus_as_string(path_str); ucmd.arg(&full_path).fails().stderr_only(format!( - "touch: cannot touch '{}': Permission denied", + "touch: cannot touch '{}': Permission denied\n", &full_path )); } @@ -763,10 +762,7 @@ fn test_touch_permission_denied_error_msg() { #[test] fn test_touch_no_args() { let mut ucmd = new_ucmd!(); - ucmd.fails().stderr_only( - r##"touch: missing file operand -Try 'touch --help' for more information."##, - ); + ucmd.fails().no_stdout().usage_error("missing file operand"); } #[test] diff --git a/tests/by-util/test_tr.rs b/tests/by-util/test_tr.rs index 7f60f88a1..0a098801b 100644 --- a/tests/by-util/test_tr.rs +++ b/tests/by-util/test_tr.rs @@ -777,7 +777,10 @@ fn check_against_gnu_tr_tests_range_a_a() { .stdout_is("zbc"); } +// FIXME: Since pr https://github.com/uutils/coreutils/pull/4261: +// stderr ends with 2 newlines but expected is only 1. #[test] +#[cfg(disabled_until_fixed)] fn check_against_gnu_tr_tests_null() { // ['null', qw(a ''), {IN=>''}, {OUT=>''}, {EXIT=>1}, // {ERR=>"$prog: when not truncating set1, string2 must be non-empty\n"}], @@ -852,7 +855,10 @@ fn check_against_gnu_tr_tests_rep_3() { .stdout_is("1x2"); } +// FIXME: Since pr https://github.com/uutils/coreutils/pull/4261: +// stderr ends with 2 newlines but expected is only 1. #[test] +#[cfg(disabled_until_fixed)] fn check_against_gnu_tr_tests_o_rep_1() { // # Another couple octal repeat count tests. // ['o-rep-1', qw('[b*08]' '[x*]'), {IN=>''}, {OUT=>''}, {EXIT=>1}, @@ -925,7 +931,7 @@ fn check_against_gnu_tr_tests_bs_at_end() { .pipe_in(r"\") .succeeds() .stdout_is("x") - .stderr_is("tr: warning: an unescaped backslash at end of string is not portable"); + .stderr_is("tr: warning: an unescaped backslash at end of string is not portable\n"); } #[test] @@ -938,7 +944,7 @@ fn check_against_gnu_tr_tests_ross_0a() { .args(&["-cs", "[:upper:]", "X[Y*]"]) .pipe_in("") .fails() - .stderr_is("tr: when translating with complemented character classes,\nstring2 must map all characters in the domain to one"); + .stderr_is("tr: when translating with complemented character classes,\nstring2 must map all characters in the domain to one\n"); } #[test] @@ -1026,6 +1032,10 @@ fn check_against_gnu_tr_tests_ross_6() { .stdout_is(""); } +// FIXME: Since pr https://github.com/uutils/coreutils/pull/4261: +// stderr ends with 2 newlines but expected is only 1. +#[test] +#[cfg(disabled_until_fixed)] #[test] fn check_against_gnu_tr_tests_empty_eq() { // # Ensure that these fail. @@ -1039,6 +1049,10 @@ fn check_against_gnu_tr_tests_empty_eq() { .stderr_is("tr: missing equivalence class character '[==]'\n"); } +// FIXME: Since pr https://github.com/uutils/coreutils/pull/4261: +// stderr ends with 2 newlines but expected is only 1. +#[test] +#[cfg(disabled_until_fixed)] #[test] fn check_against_gnu_tr_tests_empty_cc() { // ['empty-cc', qw('[::]' x), {IN=>''}, {OUT=>''}, {EXIT=>1}, diff --git a/tests/by-util/test_truncate.rs b/tests/by-util/test_truncate.rs index 52c419e8d..f306a32a9 100644 --- a/tests/by-util/test_truncate.rs +++ b/tests/by-util/test_truncate.rs @@ -19,13 +19,8 @@ fn test_increase_file_size() { ucmd.args(&["-s", "+5K", FILE1]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -36,13 +31,8 @@ fn test_increase_file_size_kb() { ucmd.args(&["-s", "+5KB", FILE1]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -66,13 +56,8 @@ fn test_reference() { .succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -83,13 +68,8 @@ fn test_decrease_file_size() { file.write_all(b"1234567890").unwrap(); ucmd.args(&["--size=-4", FILE2]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -100,13 +80,8 @@ fn test_space_in_size() { file.write_all(b"1234567890").unwrap(); ucmd.args(&["--size", " 4", FILE2]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -134,13 +109,8 @@ fn test_at_most_shrinks() { file.write_all(b"1234567890").unwrap(); ucmd.args(&["--size", "<4", FILE2]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -151,13 +121,8 @@ fn test_at_most_no_change() { file.write_all(b"1234567890").unwrap(); ucmd.args(&["--size", "<40", FILE2]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -168,13 +133,8 @@ fn test_at_least_grows() { file.write_all(b"1234567890").unwrap(); ucmd.args(&["--size", ">15", FILE2]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -185,13 +145,8 @@ fn test_at_least_no_change() { file.write_all(b"1234567890").unwrap(); ucmd.args(&["--size", ">4", FILE2]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -202,13 +157,8 @@ fn test_round_down() { file.write_all(b"1234567890").unwrap(); ucmd.args(&["--size", "/4", FILE2]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -219,13 +169,8 @@ fn test_round_up() { file.write_all(b"1234567890").unwrap(); ucmd.args(&["--size", "%4", FILE2]).succeeds(); file.seek(SeekFrom::End(0)).unwrap(); - let actual = file.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -238,13 +183,8 @@ fn test_size_and_reference() { ucmd.args(&["--reference", FILE1, "--size", "+5", FILE2]) .succeeds(); file2.seek(SeekFrom::End(0)).unwrap(); - let actual = file2.seek(SeekFrom::Current(0)).unwrap(); - assert!( - expected == actual, - "expected '{}' got '{}'", - expected, - actual - ); + let actual = file2.stream_position().unwrap(); + assert!(expected == actual, "expected '{expected}' got '{actual}'"); } #[test] @@ -308,13 +248,13 @@ fn test_truncate_bytes_size() { .args(&["--size", "1024R", "file"]) .fails() .code_is(1) - .stderr_only("truncate: Invalid number: '1024R'"); + .stderr_only("truncate: Invalid number: '1024R'\n"); #[cfg(not(target_pointer_width = "128"))] new_ucmd!() .args(&["--size", "1Y", "file"]) .fails() .code_is(1) - .stderr_only("truncate: Invalid number: '1Y': Value too large for defined data type"); + .stderr_only("truncate: Invalid number: '1Y': Value too large for defined data type\n"); } /// Test that truncating a non-existent file creates that file. diff --git a/tests/by-util/test_uname.rs b/tests/by-util/test_uname.rs index 7cd165d0f..c446da6c5 100644 --- a/tests/by-util/test_uname.rs +++ b/tests/by-util/test_uname.rs @@ -28,8 +28,11 @@ fn test_uname_processor() { #[test] fn test_uname_hardware_platform() { - let result = new_ucmd!().arg("-i").succeeds(); - assert_eq!(result.stdout_str().trim_end(), "unknown"); + new_ucmd!() + .arg("-i") + .succeeds() + .stdout_str_apply(str::trim_end) + .stdout_only("unknown"); } #[test] @@ -104,10 +107,11 @@ fn test_uname_operating_system() { .succeeds() .stdout_is("Redox\n"); #[cfg(target_os = "windows")] - new_ucmd!() - .arg("--operating-system") - .succeeds() - .stdout_is("Windows NT\n"); + { + let result = new_ucmd!().arg("--operating-system").succeeds(); + println!("{:?}", result.stdout_str()); + assert!(result.stdout_str().starts_with("MS/Windows")); + } } #[test] @@ -117,3 +121,11 @@ fn test_uname_help() { .succeeds() .stdout_contains("system information"); } + +#[test] +fn test_uname_output_for_invisible_chars() { + // let re = regex::Regex::new("[^[[:print:]]]").unwrap(); // matches invisible (and emojis) + let re = regex::Regex::new("[^[[:print:]]\\p{Other_Symbol}]").unwrap(); // matches invisible (not emojis) + let result = new_ucmd!().arg("--all").succeeds(); + assert_eq!(re.find(result.stdout_str().trim_end()), None); +} diff --git a/tests/by-util/test_uniq.rs b/tests/by-util/test_uniq.rs index 22a56c0e2..8acd15e0a 100644 --- a/tests/by-util/test_uniq.rs +++ b/tests/by-util/test_uniq.rs @@ -168,8 +168,8 @@ fn test_invalid_utf8() { .run() .failure() .stderr_only( - "uniq: failed to convert line to utf8: invalid utf-8 sequence of 1 bytes from index 0", - ); + "uniq: failed to convert line to utf8: invalid utf-8 sequence of 1 bytes from index 0\n", + ); } #[test] diff --git a/tests/by-util/test_wc.rs b/tests/by-util/test_wc.rs index db0df44a0..bbc057972 100644 --- a/tests/by-util/test_wc.rs +++ b/tests/by-util/test_wc.rs @@ -26,7 +26,7 @@ fn test_count_bytes_large_stdin() { 128 * 1024, ] { let data = vec_of_size(n); - let expected = format!("{}\n", n); + let expected = format!("{n}\n"); new_ucmd!() .args(&["-c"]) .pipe_in(data) diff --git a/tests/by-util/test_who.rs b/tests/by-util/test_who.rs index 6acba2099..6f98c8b9d 100644 --- a/tests/by-util/test_who.rs +++ b/tests/by-util/test_who.rs @@ -44,8 +44,8 @@ fn test_heading() { // specifically number of TABs between "TIME" and "COMMENT" may be variant let actual = ts.ucmd().arg(opt).succeeds().stdout_move_str(); let expect = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); let v_actual: Vec<&str> = actual.split_whitespace().collect(); let v_expect: Vec<&str> = expect.split_whitespace().collect(); assert_eq!(v_actual, v_expect); @@ -165,8 +165,8 @@ fn test_users() { for opt in ["-u", "--users", "--us"] { let actual = ts.ucmd().arg(opt).succeeds().stdout_move_str(); let expect = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); - println!("actual: {:?}", actual); - println!("expect: {:?}", expect); + println!("actual: {actual:?}"); + println!("expect: {expect:?}"); let mut v_actual: Vec<&str> = actual.split_whitespace().collect(); let mut v_expect: Vec<&str> = expect.split_whitespace().collect(); diff --git a/tests/by-util/test_whoami.rs b/tests/by-util/test_whoami.rs index a64dbb7cd..044f27c57 100644 --- a/tests/by-util/test_whoami.rs +++ b/tests/by-util/test_whoami.rs @@ -43,7 +43,7 @@ fn test_normal_compare_env() { if whoami == "nobody" { println!("test skipped:"); } else if !is_ci() { - new_ucmd!().succeeds().stdout_is(format!("{}\n", whoami)); + new_ucmd!().succeeds().stdout_is(format!("{whoami}\n")); } else { println!("test skipped:"); } diff --git a/tests/common/util.rs b/tests/common/util.rs index fb3c8fb8d..7229deb5a 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -3,7 +3,7 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -//spell-checker: ignore (linux) rlimit prlimit coreutil ggroups uchild uncaptured +//spell-checker: ignore (linux) rlimit prlimit coreutil ggroups uchild uncaptured scmd #![allow(dead_code)] @@ -20,12 +20,14 @@ use std::fs::{self, hard_link, remove_file, File, OpenOptions}; use std::io::{self, BufWriter, Read, Result, Write}; #[cfg(unix)] use std::os::unix::fs::{symlink as symlink_dir, symlink as symlink_file, PermissionsExt}; +#[cfg(unix)] +use std::os::unix::process::ExitStatusExt; #[cfg(windows)] use std::os::windows::fs::{symlink_dir, symlink_file}; #[cfg(windows)] use std::path::MAIN_SEPARATOR; use std::path::{Path, PathBuf}; -use std::process::{Child, Command, Output, Stdio}; +use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::rc::Rc; use std::sync::mpsc::{self, RecvTimeoutError}; use std::thread::{sleep, JoinHandle}; @@ -73,10 +75,7 @@ pub struct CmdResult { //tmpd is used for convenience functions for asserts against fixtures tmpd: Option>, /// exit status for command (if there is one) - code: Option, - /// zero-exit from running the Command? - /// see [`success`] - success: bool, + exit_status: Option, /// captured standard output after running the Command stdout: Vec, /// captured standard error after running the Command @@ -84,26 +83,233 @@ pub struct CmdResult { } impl CmdResult { - pub fn new( + pub fn new( bin_path: String, util_name: Option, tmpd: Option>, - code: Option, - success: bool, - stdout: &[u8], - stderr: &[u8], - ) -> Self { + exit_status: Option, + stdout: T, + stderr: U, + ) -> Self + where + T: Into>, + U: Into>, + { Self { bin_path, util_name, tmpd, - code, - success, - stdout: stdout.to_vec(), - stderr: stderr.to_vec(), + exit_status, + stdout: stdout.into(), + stderr: stderr.into(), } } + /// Apply a function to `stdout` as bytes and return a new [`CmdResult`] + pub fn stdout_apply<'a, F, R>(&'a self, function: F) -> Self + where + F: Fn(&'a [u8]) -> R, + R: Into>, + { + Self::new( + self.bin_path.clone(), + self.util_name.clone(), + self.tmpd.clone(), + self.exit_status, + function(&self.stdout), + self.stderr.as_slice(), + ) + } + + /// Apply a function to `stdout` as `&str` and return a new [`CmdResult`] + pub fn stdout_str_apply<'a, F, R>(&'a self, function: F) -> Self + where + F: Fn(&'a str) -> R, + R: Into>, + { + Self::new( + self.bin_path.clone(), + self.util_name.clone(), + self.tmpd.clone(), + self.exit_status, + function(self.stdout_str()), + self.stderr.as_slice(), + ) + } + + /// Apply a function to `stderr` as bytes and return a new [`CmdResult`] + pub fn stderr_apply<'a, F, R>(&'a self, function: F) -> Self + where + F: Fn(&'a [u8]) -> R, + R: Into>, + { + Self::new( + self.bin_path.clone(), + self.util_name.clone(), + self.tmpd.clone(), + self.exit_status, + self.stdout.as_slice(), + function(&self.stderr), + ) + } + + /// Apply a function to `stderr` as `&str` and return a new [`CmdResult`] + pub fn stderr_str_apply<'a, F, R>(&'a self, function: F) -> Self + where + F: Fn(&'a str) -> R, + R: Into>, + { + Self::new( + self.bin_path.clone(), + self.util_name.clone(), + self.tmpd.clone(), + self.exit_status, + self.stdout.as_slice(), + function(self.stderr_str()), + ) + } + + /// Assert `stdout` as bytes with a predicate function returning a `bool`. + #[track_caller] + pub fn stdout_check<'a, F>(&'a self, predicate: F) -> &Self + where + F: Fn(&'a [u8]) -> bool, + { + assert!( + predicate(&self.stdout), + "Predicate for stdout as `bytes` evaluated to false.\nstdout='{:?}'\nstderr='{:?}'\n", + &self.stdout, + &self.stderr + ); + self + } + + /// Assert `stdout` as `&str` with a predicate function returning a `bool`. + #[track_caller] + pub fn stdout_str_check<'a, F>(&'a self, predicate: F) -> &Self + where + F: Fn(&'a str) -> bool, + { + assert!( + predicate(self.stdout_str()), + "Predicate for stdout as `str` evaluated to false.\nstdout='{}'\nstderr='{}'\n", + self.stdout_str(), + self.stderr_str() + ); + self + } + + /// Assert `stderr` as bytes with a predicate function returning a `bool`. + #[track_caller] + pub fn stderr_check<'a, F>(&'a self, predicate: F) -> &Self + where + F: Fn(&'a [u8]) -> bool, + { + assert!( + predicate(&self.stderr), + "Predicate for stderr as `bytes` evaluated to false.\nstdout='{:?}'\nstderr='{:?}'\n", + &self.stdout, + &self.stderr + ); + self + } + + /// Assert `stderr` as `&str` with a predicate function returning a `bool`. + #[track_caller] + pub fn stderr_str_check<'a, F>(&'a self, predicate: F) -> &Self + where + F: Fn(&'a str) -> bool, + { + assert!( + predicate(self.stderr_str()), + "Predicate for stderr as `str` evaluated to false.\nstdout='{}'\nstderr='{}'\n", + self.stdout_str(), + self.stderr_str() + ); + self + } + + /// Return the exit status of the child process, if any. + /// + /// Returns None if the child process is still running or hasn't been started. + pub fn try_exit_status(&self) -> Option { + self.exit_status + } + + /// Return the exit status of the child process. + /// + /// # Panics + /// + /// If the child process is still running or hasn't been started. + pub fn exit_status(&self) -> ExitStatus { + self.try_exit_status() + .expect("Program must be run first or has not finished, yet") + } + + /// Return the signal the child process received if any. + /// + /// # Platform specific behavior + /// + /// This method is only available on unix systems. + #[cfg(unix)] + pub fn signal(&self) -> Option { + self.exit_status().signal() + } + + /// Assert that the given signal `value` equals the signal the child process received. + /// + /// See also [`std::os::unix::process::ExitStatusExt::signal`]. + /// + /// # Platform specific behavior + /// + /// This assertion method is only available on unix systems. + #[cfg(unix)] + #[track_caller] + pub fn signal_is(&self, value: i32) -> &Self { + let actual = self.signal().unwrap_or_else(|| { + panic!( + "Expected process to be terminated by the '{}' signal, but exit status is: '{}'", + value, + self.try_exit_status() + .map_or("Not available".to_string(), |e| e.to_string()) + ) + }); + + assert_eq!(actual, value); + self + } + + /// Assert that the given signal `name` equals the signal the child process received. + /// + /// Strings like `SIGINT`, `INT` or a number like `15` are all valid names. See also + /// [`std::os::unix::process::ExitStatusExt::signal`] and + /// [`uucore::signals::signal_by_name_or_value`] + /// + /// # Platform specific behavior + /// + /// This assertion method is only available on unix systems. + #[cfg(unix)] + #[track_caller] + pub fn signal_name_is(&self, name: &str) -> &Self { + use uucore::signals::signal_by_name_or_value; + let expected: i32 = signal_by_name_or_value(name) + .unwrap_or_else(|| panic!("Invalid signal name or value: '{name}'")) + .try_into() + .unwrap(); + + let actual = self.signal().unwrap_or_else(|| { + panic!( + "Expected process to be terminated by the '{}' signal, but exit status is: '{}'", + name, + self.try_exit_status() + .map_or("Not available".to_string(), |e| e.to_string()) + ) + }); + + assert_eq!(actual, expected); + self + } + /// Returns a reference to the program's standard output as a slice of bytes pub fn stdout(&self) -> &[u8] { &self.stdout @@ -151,10 +357,10 @@ impl CmdResult { /// Returns the program's exit code /// Panics if not run or has not finished yet for example when run with `run_no_wait()` pub fn code(&self) -> i32 { - self.code - .expect("Program must be run first or has not finished, yet") + self.exit_status().code().unwrap() } + #[track_caller] pub fn code_is(&self, expected_code: i32) -> &Self { assert_eq!(self.code(), expected_code); self @@ -171,13 +377,14 @@ impl CmdResult { /// Returns whether the program succeeded pub fn succeeded(&self) -> bool { - self.success + self.exit_status.map_or(true, |e| e.success()) } /// asserts that the command resulted in a success (zero) status code + #[track_caller] pub fn success(&self) -> &Self { assert!( - self.success, + self.succeeded(), "Command was expected to succeed.\nstdout = {}\n stderr = {}", self.stdout_str(), self.stderr_str() @@ -186,9 +393,10 @@ impl CmdResult { } /// asserts that the command resulted in a failure (non-zero) status code + #[track_caller] pub fn failure(&self) -> &Self { assert!( - !self.success, + !self.succeeded(), "Command was expected to fail.\nstdout = {}\n stderr = {}", self.stdout_str(), self.stderr_str() @@ -196,17 +404,12 @@ impl CmdResult { self } - /// asserts that the command's exit code is the same as the given one - pub fn status_code(&self, code: i32) -> &Self { - assert_eq!(self.code, Some(code)); - self - } - /// asserts that the command resulted in empty (zero-length) stderr stream output /// generally, it's better to use `stdout_only()` instead, /// but you might find yourself using this function if /// 1. you can not know exactly what stdout will be or /// 2. you know that stdout will also be empty + #[track_caller] pub fn no_stderr(&self) -> &Self { assert!( self.stderr.is_empty(), @@ -222,6 +425,7 @@ impl CmdResult { /// but you might find yourself using this function if /// 1. you can not know exactly what stderr will be or /// 2. you know that stderr will also be empty + #[track_caller] pub fn no_stdout(&self) -> &Self { assert!( self.stdout.is_empty(), @@ -232,6 +436,7 @@ impl CmdResult { } /// Assert that there is output to neither stderr nor stdout. + #[track_caller] pub fn no_output(&self) -> &Self { self.no_stdout().no_stderr() } @@ -239,12 +444,14 @@ impl CmdResult { /// asserts that the command resulted in stdout stream output that equals the /// passed in value, trailing whitespace are kept to force strict comparison (#1235) /// `stdout_only()` is a better choice unless stderr may or will be non-empty + #[track_caller] pub fn stdout_is>(&self, msg: T) -> &Self { assert_eq!(self.stdout_str(), String::from(msg.as_ref())); self } /// like `stdout_is`, but succeeds if any elements of `expected` matches stdout. + #[track_caller] pub fn stdout_is_any + std::fmt::Debug>(&self, expected: &[T]) -> &Self { assert!( expected.iter().any(|msg| self.stdout_str() == msg.as_ref()), @@ -256,6 +463,7 @@ impl CmdResult { } /// Like `stdout_is` but newlines are normalized to `\n`. + #[track_caller] pub fn normalized_newlines_stdout_is>(&self, msg: T) -> &Self { let msg = msg.as_ref().replace("\r\n", "\n"); assert_eq!(self.stdout_str().replace("\r\n", "\n"), msg); @@ -264,12 +472,18 @@ impl CmdResult { /// asserts that the command resulted in stdout stream output, /// whose bytes equal those of the passed in slice + #[track_caller] pub fn stdout_is_bytes>(&self, msg: T) -> &Self { - assert_eq!(self.stdout, msg.as_ref()); + assert_eq!(self.stdout, msg.as_ref(), + "stdout as bytes wasn't equal to expected bytes. Result as strings:\nstdout ='{:?}'\nexpected='{:?}'", + std::str::from_utf8(&self.stdout), + std::str::from_utf8(msg.as_ref()), + ); self } /// like `stdout_is()`, but expects the contents of the file at the provided relative path + #[track_caller] pub fn stdout_is_fixture>(&self, file_rel_path: T) -> &Self { let contents = read_scenario_fixture(&self.tmpd, file_rel_path); self.stdout_is(String::from_utf8(contents).unwrap()) @@ -291,6 +505,7 @@ impl CmdResult { /// new_ucmd!().succeeds().stdout_is_fixture_bytes("expected.bin"); /// } /// ``` + #[track_caller] pub fn stdout_is_fixture_bytes>(&self, file_rel_path: T) -> &Self { let contents = read_scenario_fixture(&self.tmpd, file_rel_path); self.stdout_is_bytes(contents) @@ -298,6 +513,7 @@ impl CmdResult { /// like `stdout_is_fixture()`, but replaces the data in fixture file based on values provided in `template_vars` /// command output + #[track_caller] pub fn stdout_is_templated_fixture>( &self, file_rel_path: T, @@ -312,6 +528,7 @@ impl CmdResult { } /// like `stdout_is_templated_fixture`, but succeeds if any replacement by `template_vars` results in the actual stdout. + #[track_caller] pub fn stdout_is_templated_fixture_any>( &self, file_rel_path: T, @@ -328,25 +545,32 @@ impl CmdResult { self.stdout_is_any(&possible_values.collect::>()); } - /// asserts that the command resulted in stderr stream output that equals the - /// passed in value, when both are trimmed of trailing whitespace + /// assert that the command resulted in stderr stream output that equals the + /// passed in value. + /// /// `stderr_only` is a better choice unless stdout may or will be non-empty + #[track_caller] pub fn stderr_is>(&self, msg: T) -> &Self { - assert_eq!( - self.stderr_str().trim_end(), - String::from(msg.as_ref()).trim_end() - ); + assert_eq!(self.stderr_str(), msg.as_ref()); self } /// asserts that the command resulted in stderr stream output, /// whose bytes equal those of the passed in slice + #[track_caller] pub fn stderr_is_bytes>(&self, msg: T) -> &Self { - assert_eq!(self.stderr, msg.as_ref()); + assert_eq!( + &self.stderr, + msg.as_ref(), + "stderr as bytes wasn't equal to expected bytes. Result as strings:\nstderr ='{:?}'\nexpected='{:?}'", + std::str::from_utf8(&self.stderr), + std::str::from_utf8(msg.as_ref()) + ); self } /// Like `stdout_is_fixture`, but for stderr + #[track_caller] pub fn stderr_is_fixture>(&self, file_rel_path: T) -> &Self { let contents = read_scenario_fixture(&self.tmpd, file_rel_path); self.stderr_is(String::from_utf8(contents).unwrap()) @@ -356,6 +580,7 @@ impl CmdResult { /// 1. the command resulted in stdout stream output that equals the /// passed in value /// 2. the command resulted in empty (zero-length) stderr stream output + #[track_caller] pub fn stdout_only>(&self, msg: T) -> &Self { self.no_stderr().stdout_is(msg) } @@ -364,11 +589,13 @@ impl CmdResult { /// 1. the command resulted in a stdout stream whose bytes /// equal those of the passed in value /// 2. the command resulted in an empty stderr stream + #[track_caller] pub fn stdout_only_bytes>(&self, msg: T) -> &Self { self.no_stderr().stdout_is_bytes(msg) } /// like `stdout_only()`, but expects the contents of the file at the provided relative path + #[track_caller] pub fn stdout_only_fixture>(&self, file_rel_path: T) -> &Self { let contents = read_scenario_fixture(&self.tmpd, file_rel_path); self.stdout_only_bytes(contents) @@ -378,6 +605,7 @@ impl CmdResult { /// 1. the command resulted in stderr stream output that equals the /// passed in value, when both are trimmed of trailing whitespace /// 2. the command resulted in empty (zero-length) stdout stream output + #[track_caller] pub fn stderr_only>(&self, msg: T) -> &Self { self.no_stdout().stderr_is(msg) } @@ -386,12 +614,14 @@ impl CmdResult { /// 1. the command resulted in a stderr stream whose bytes equal the ones /// of the passed value /// 2. the command resulted in an empty stdout stream + #[track_caller] pub fn stderr_only_bytes>(&self, msg: T) -> &Self { self.no_stdout().stderr_is_bytes(msg) } + #[track_caller] pub fn fails_silently(&self) -> &Self { - assert!(!self.success); + assert!(!self.succeeded()); assert!(self.stderr.is_empty()); self } @@ -404,15 +634,17 @@ impl CmdResult { /// `msg` should be the same as the one provided to `UUsageError::new` or `show_error!` /// /// 2. the command resulted in empty (zero-length) stdout stream output + #[track_caller] pub fn usage_error>(&self, msg: T) -> &Self { self.stderr_only(format!( - "{0}: {2}\nTry '{1} {0} --help' for more information.", + "{0}: {2}\nTry '{1} {0} --help' for more information.\n", self.util_name.as_ref().unwrap(), // This shouldn't be called using a normal command self.bin_path, msg.as_ref() )) } + #[track_caller] pub fn stdout_contains>(&self, cmp: T) -> &Self { assert!( self.stdout_str().contains(cmp.as_ref()), @@ -423,6 +655,7 @@ impl CmdResult { self } + #[track_caller] pub fn stderr_contains>(&self, cmp: T) -> &Self { assert!( self.stderr_str().contains(cmp.as_ref()), @@ -433,6 +666,7 @@ impl CmdResult { self } + #[track_caller] pub fn stdout_does_not_contain>(&self, cmp: T) -> &Self { assert!( !self.stdout_str().contains(cmp.as_ref()), @@ -443,11 +677,13 @@ impl CmdResult { self } + #[track_caller] pub fn stderr_does_not_contain>(&self, cmp: T) -> &Self { assert!(!self.stderr_str().contains(cmp.as_ref())); self } + #[track_caller] pub fn stdout_matches(&self, regex: ®ex::Regex) -> &Self { assert!( regex.is_match(self.stdout_str().trim()), @@ -457,6 +693,7 @@ impl CmdResult { self } + #[track_caller] pub fn stdout_does_not_match(&self, regex: ®ex::Regex) -> &Self { assert!( !regex.is_match(self.stdout_str().trim()), @@ -1081,6 +1318,7 @@ impl UCommand { "{}", MULTIPLE_STDIN_MEANINGLESS ); + self.set_stdin(Stdio::piped()); self.bytes_into_stdin = Some(input.into()); self } @@ -1146,8 +1384,7 @@ impl UCommand { let command = self .raw - // TODO: use Stdio::null() as default to avoid accidental deadlocks ? - .stdin(self.stdin.take().unwrap_or_else(Stdio::piped)) + .stdin(self.stdin.take().unwrap_or_else(Stdio::null)) .stdout(Stdio::from(output.try_clone().unwrap())) .stderr(Stdio::from(output.try_clone().unwrap())); captured_stdout = Some(output); @@ -1173,8 +1410,7 @@ impl UCommand { }; self.raw - // TODO: use Stdio::null() as default to avoid accidental deadlocks ? - .stdin(self.stdin.take().unwrap_or_else(Stdio::piped)) + .stdin(self.stdin.take().unwrap_or_else(Stdio::null)) .stdout(stdout) .stderr(stderr) }; @@ -1218,6 +1454,7 @@ impl UCommand { /// Spawns the command, feeds the stdin if any, waits for the result, /// asserts success, and returns a command result. + #[track_caller] pub fn succeeds(&mut self) -> CmdResult { let cmd_result = self.run(); cmd_result.success(); @@ -1226,6 +1463,7 @@ impl UCommand { /// Spawns the command, feeds the stdin if any, waits for the result, /// asserts failure, and returns a command result. + #[track_caller] pub fn fails(&mut self) -> CmdResult { let cmd_result = self.run(); cmd_result.failure(); @@ -1354,12 +1592,10 @@ impl<'a> UChildAssertion<'a> { } fn with_output(&mut self, mode: AssertionMode) -> CmdResult { - let (code, success) = match self.uchild.is_alive() { - true => (None, true), - false => { - let status = self.uchild.raw.wait().unwrap(); - (status.code(), status.success()) - } + let exit_status = if self.uchild.is_alive() { + None + } else { + Some(self.uchild.raw.wait().unwrap()) }; let (stdout, stderr) = match mode { AssertionMode::All => ( @@ -1376,8 +1612,7 @@ impl<'a> UChildAssertion<'a> { bin_path: self.uchild.bin_path.clone(), util_name: self.uchild.util_name.clone(), tmpd: self.uchild.tmpd.clone(), - code, - success, + exit_status, stdout, stderr, } @@ -1415,6 +1650,7 @@ impl<'a> UChildAssertion<'a> { } // Assert that the child process is alive + #[track_caller] pub fn is_alive(&mut self) -> &mut Self { match self .uchild @@ -1436,6 +1672,7 @@ impl<'a> UChildAssertion<'a> { } // Assert that the child process has exited + #[track_caller] pub fn is_not_alive(&mut self) -> &mut Self { match self .uchild @@ -1604,8 +1841,7 @@ impl UChild { bin_path, util_name, tmpd, - code: output.status.code(), - success: output.status.success(), + exit_status: Some(output.status), stdout: output.stdout, stderr: output.stderr, }) @@ -1987,7 +2223,7 @@ pub fn host_name_for(util_name: &str) -> Cow { if util_name.starts_with('g') && util_name != "groups" { util_name.into() } else { - format!("g{}", util_name).into() + format!("g{util_name}").into() } } #[cfg(target_os = "linux")] @@ -2138,8 +2374,7 @@ pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result< ts.bin_path.as_os_str().to_str().unwrap().to_string(), Some(ts.util_name.clone()), Some(result.tmpd()), - Some(result.code()), - result.succeeded(), + result.exit_status, stdout.as_bytes(), stderr.as_bytes(), )) @@ -2215,151 +2450,160 @@ mod tests { // spell-checker:ignore (tests) asdfsadfa use super::*; + #[cfg(unix)] + pub fn run_cmd>(cmd: T) -> CmdResult { + let mut ucmd = UCommand::new_from_tmp::<&str, String>( + "sh", + &None, + Rc::new(tempfile::tempdir().unwrap()), + true, + ); + ucmd.arg("-c"); + ucmd.arg(cmd); + ucmd.run() + } + + #[cfg(windows)] + pub fn run_cmd>(cmd: T) -> CmdResult { + let mut ucmd = UCommand::new_from_tmp::<&str, String>( + "cmd", + &None, + Rc::new(tempfile::tempdir().unwrap()), + true, + ); + ucmd.arg("/C"); + ucmd.arg(cmd); + ucmd.run() + } + #[test] - fn test_code_is() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: Some(32), - success: false, - stdout: "".into(), - stderr: "".into(), - }; - res.code_is(32); + fn test_command_result_when_no_output_with_exit_32() { + let result = run_cmd("exit 32"); + + if cfg!(windows) { + std::assert!(result.bin_path.ends_with("cmd")); + } else { + std::assert!(result.bin_path.ends_with("sh")); + } + + std::assert!(result.util_name.is_none()); + std::assert!(result.tmpd.is_some()); + + assert!(result.exit_status.is_some()); + std::assert_eq!(result.code(), 32); + result.code_is(32); + assert!(!result.succeeded()); + result.failure(); + result.fails_silently(); + assert!(result.stderr.is_empty()); + assert!(result.stdout.is_empty()); + result.no_output(); + result.no_stderr(); + result.no_stdout(); } #[test] #[should_panic] - fn test_code_is_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: Some(32), - success: false, - stdout: "".into(), - stderr: "".into(), - }; - res.code_is(1); + fn test_command_result_when_exit_32_then_success_panic() { + run_cmd("exit 32").success(); } #[test] - fn test_failure() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: false, - stdout: "".into(), - stderr: "".into(), - }; - res.failure(); + fn test_command_result_when_no_output_with_exit_0() { + let result = run_cmd("exit 0"); + + assert!(result.exit_status.is_some()); + std::assert_eq!(result.code(), 0); + result.code_is(0); + assert!(result.succeeded()); + result.success(); + assert!(result.stderr.is_empty()); + assert!(result.stdout.is_empty()); + result.no_output(); + result.no_stderr(); + result.no_stdout(); } #[test] #[should_panic] - fn test_failure_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "".into(), - stderr: "".into(), - }; - res.failure(); - } - - #[test] - fn test_success() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "".into(), - stderr: "".into(), - }; - res.success(); + fn test_command_result_when_exit_0_then_failure_panics() { + run_cmd("exit 0").failure(); } #[test] #[should_panic] - fn test_success_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: false, - stdout: "".into(), - stderr: "".into(), - }; - res.success(); + fn test_command_result_when_exit_0_then_silent_failure_panics() { + run_cmd("exit 0").fails_silently(); } #[test] - fn test_no_stderr_output() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "".into(), - stderr: "".into(), - }; - res.no_stderr(); - res.no_stdout(); + fn test_command_result_when_stdout_with_exit_0() { + #[cfg(windows)] + let (result, vector, string) = ( + run_cmd("echo hello& exit 0"), + vec![b'h', b'e', b'l', b'l', b'o', b'\r', b'\n'], + "hello\r\n", + ); + #[cfg(not(windows))] + let (result, vector, string) = ( + run_cmd("echo hello; exit 0"), + vec![b'h', b'e', b'l', b'l', b'o', b'\n'], + "hello\n", + ); + + assert!(result.exit_status.is_some()); + std::assert_eq!(result.code(), 0); + result.code_is(0); + assert!(result.succeeded()); + result.success(); + assert!(result.stderr.is_empty()); + std::assert_eq!(result.stdout, vector); + result.no_stderr(); + result.stdout_is(string); + result.stdout_is_bytes(&vector); + result.stdout_only(string); + result.stdout_only_bytes(&vector); } #[test] - #[should_panic] - fn test_no_stderr_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "".into(), - stderr: "asdfsadfa".into(), - }; + fn test_command_result_when_stderr_with_exit_0() { + #[cfg(windows)] + let (result, vector, string) = ( + run_cmd("echo hello>&2& exit 0"), + vec![b'h', b'e', b'l', b'l', b'o', b'\r', b'\n'], + "hello\r\n", + ); + #[cfg(not(windows))] + let (result, vector, string) = ( + run_cmd("echo hello >&2; exit 0"), + vec![b'h', b'e', b'l', b'l', b'o', b'\n'], + "hello\n", + ); - res.no_stderr(); - } - - #[test] - #[should_panic] - fn test_no_stdout_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "asdfsadfa".into(), - stderr: "".into(), - }; - - res.no_stdout(); + assert!(result.exit_status.is_some()); + std::assert_eq!(result.code(), 0); + result.code_is(0); + assert!(result.succeeded()); + result.success(); + assert!(result.stdout.is_empty()); + result.no_stdout(); + std::assert_eq!(result.stderr, vector); + result.stderr_is(string); + result.stderr_is_bytes(&vector); + result.stderr_only(string); + result.stderr_only_bytes(&vector); } #[test] fn test_std_does_not_contain() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "This is a likely error message\n".into(), - stderr: "This is a likely error message\n".into(), - }; + #[cfg(windows)] + let res = run_cmd( + "(echo This is a likely error message& echo This is a likely error message>&2) & exit 0", + ); + #[cfg(not(windows))] + let res = run_cmd( + "echo This is a likely error message; echo This is a likely error message >&2; exit 0", + ); res.stdout_does_not_contain("unlikely"); res.stderr_does_not_contain("unlikely"); } @@ -2367,15 +2611,10 @@ mod tests { #[test] #[should_panic] fn test_stdout_does_not_contain_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "This is a likely error message\n".into(), - stderr: "".into(), - }; + #[cfg(windows)] + let res = run_cmd("echo This is a likely error message& exit 0"); + #[cfg(not(windows))] + let res = run_cmd("echo This is a likely error message; exit 0"); res.stdout_does_not_contain("likely"); } @@ -2383,30 +2622,25 @@ mod tests { #[test] #[should_panic] fn test_stderr_does_not_contain_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "".into(), - stderr: "This is a likely error message\n".into(), - }; + #[cfg(windows)] + let res = run_cmd("echo This is a likely error message>&2 & exit 0"); + #[cfg(not(windows))] + let res = run_cmd("echo This is a likely error message >&2; exit 0"); res.stderr_does_not_contain("likely"); } #[test] fn test_stdout_matches() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "This is a likely error message\n".into(), - stderr: "This is a likely error message\n".into(), - }; + #[cfg(windows)] + let res = run_cmd( + "(echo This is a likely error message& echo This is a likely error message>&2 ) & exit 0", + ); + #[cfg(not(windows))] + let res = run_cmd( + "echo This is a likely error message; echo This is a likely error message >&2; exit 0", + ); + let positive = regex::Regex::new(".*likely.*").unwrap(); let negative = regex::Regex::new(".*unlikely.*").unwrap(); res.stdout_matches(&positive); @@ -2416,70 +2650,188 @@ mod tests { #[test] #[should_panic] fn test_stdout_matches_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "This is a likely error message\n".into(), - stderr: "This is a likely error message\n".into(), - }; - let negative = regex::Regex::new(".*unlikely.*").unwrap(); + #[cfg(windows)] + let res = run_cmd( + "(echo This is a likely error message& echo This is a likely error message>&2) & exit 0", + ); + #[cfg(not(windows))] + let res = run_cmd( + "echo This is a likely error message; echo This is a likely error message >&2; exit 0", + ); + let negative = regex::Regex::new(".*unlikely.*").unwrap(); res.stdout_matches(&negative); } #[test] #[should_panic] fn test_stdout_not_matches_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "This is a likely error message\n".into(), - stderr: "This is a likely error message\n".into(), - }; - let positive = regex::Regex::new(".*likely.*").unwrap(); + #[cfg(windows)] + let res = run_cmd( + "(echo This is a likely error message& echo This is a likely error message>&2) & exit 0", + ); + #[cfg(not(windows))] + let res = run_cmd( + "echo This is a likely error message; echo This is a likely error message >&2; exit 0", + ); + let positive = regex::Regex::new(".*likely.*").unwrap(); res.stdout_does_not_match(&positive); } + #[cfg(feature = "echo")] #[test] fn test_normalized_newlines_stdout_is() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "A\r\nB\nC".into(), - stderr: "".into(), - }; + let ts = TestScenario::new("echo"); + let res = ts.ucmd().args(&["-ne", "A\r\nB\nC"]).run(); res.normalized_newlines_stdout_is("A\r\nB\nC"); res.normalized_newlines_stdout_is("A\nB\nC"); res.normalized_newlines_stdout_is("A\nB\r\nC"); } + #[cfg(feature = "echo")] #[test] #[should_panic] fn test_normalized_newlines_stdout_is_fail() { - let res = CmdResult { - bin_path: String::new(), - util_name: None, - tmpd: None, - code: None, - success: true, - stdout: "A\r\nB\nC".into(), - stderr: "".into(), - }; + let ts = TestScenario::new("echo"); + let res = ts.ucmd().args(&["-ne", "A\r\nB\nC"]).run(); res.normalized_newlines_stdout_is("A\r\nB\nC\n"); } + #[cfg(feature = "echo")] + #[test] + fn test_cmd_result_stdout_check_and_stdout_str_check() { + let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); + + result.stdout_str_check(|stdout| stdout.ends_with("world\n")); + result.stdout_check(|stdout| stdout.get(0..2).unwrap().eq(&[b'H', b'e'])); + result.no_stderr(); + } + + #[cfg(feature = "echo")] + #[test] + fn test_cmd_result_stderr_check_and_stderr_str_check() { + let ts = TestScenario::new("echo"); + let result = run_cmd(format!( + "{} {} Hello world >&2", + ts.bin_path.display(), + ts.util_name + )); + + result.stderr_str_check(|stderr| stderr.ends_with("world\n")); + result.stderr_check(|stderr| stderr.get(0..2).unwrap().eq(&[b'H', b'e'])); + result.no_stdout(); + } + + #[cfg(feature = "echo")] + #[test] + #[should_panic] + fn test_cmd_result_stdout_str_check_when_false_then_panics() { + let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); + result.stdout_str_check(str::is_empty); + } + + #[cfg(feature = "echo")] + #[test] + #[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()); + } + + #[cfg(feature = "echo")] + #[test] + #[should_panic] + fn test_cmd_result_stderr_str_check_when_false_then_panics() { + let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); + result.stderr_str_check(|s| !s.is_empty()); + } + + #[cfg(feature = "echo")] + #[test] + #[should_panic] + fn test_cmd_result_stderr_check_when_false_then_panics() { + let result = TestScenario::new("echo").ucmd().arg("Hello world").run(); + result.stderr_check(|s| !s.is_empty()); + } + + #[cfg(feature = "echo")] + #[test] + #[should_panic] + fn test_cmd_result_stdout_check_when_predicate_panics_then_panic() { + let result = TestScenario::new("echo").ucmd().run(); + result.stdout_str_check(|_| panic!("Just testing")); + } + + #[cfg(feature = "echo")] + #[cfg(unix)] + #[test] + fn test_cmd_result_signal_when_normal_exit_then_no_signal() { + let result = TestScenario::new("echo").ucmd().run(); + assert!(result.signal().is_none()); + } + + #[cfg(feature = "sleep")] + #[cfg(unix)] + #[test] + #[should_panic = "Program must be run first or has not finished"] + fn test_cmd_result_signal_when_still_running_then_panic() { + let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); + + child + .make_assertion() + .is_alive() + .with_current_output() + .signal(); + } + + #[cfg(feature = "sleep")] + #[cfg(unix)] + #[test] + fn test_cmd_result_signal_when_kill_then_signal() { + let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); + + child.kill(); + child + .make_assertion() + .is_not_alive() + .with_current_output() + .signal_is(9) + .signal_name_is("SIGKILL") + .signal_name_is("KILL") + .signal_name_is("9") + .signal() + .expect("Signal was none"); + + let result = child.wait().unwrap(); + result + .signal_is(9) + .signal_name_is("SIGKILL") + .signal_name_is("KILL") + .signal_name_is("9") + .signal() + .expect("Signal was none"); + } + + #[cfg(feature = "sleep")] + #[cfg(unix)] + #[rstest] + #[case::signal_full_name_lower_case("sigkill")] + #[case::signal_short_name_lower_case("kill")] + #[case::signal_only_part_of_name("IGKILL")] // spell-checker: disable-line + #[case::signal_just_sig("SIG")] + #[case::signal_value_too_high("100")] + #[case::signal_value_negative("-1")] + #[should_panic = "Invalid signal name or value"] + fn test_cmd_result_signal_when_invalid_signal_name_then_panic(#[case] signal_name: &str) { + let mut child = TestScenario::new("sleep").ucmd().arg("60").run_no_wait(); + child.kill(); + let result = child.wait().unwrap(); + result.signal_name_is(signal_name); + } + #[test] #[cfg(unix)] fn test_parse_coreutil_version() { @@ -2668,7 +3020,7 @@ mod tests { #[test] fn test_uchild_when_pipe_in() { let ts = TestScenario::new("cat"); - let mut child = ts.ucmd().run_no_wait(); + let mut child = ts.ucmd().set_stdin(Stdio::piped()).run_no_wait(); child.pipe_in("content"); child.wait().unwrap().stdout_only("content").success(); @@ -2693,6 +3045,7 @@ mod tests { let mut child = ts .ucmd() + .set_stdin(Stdio::piped()) .stderr_to_stdout() .args(&["-riv", "a"]) .run_no_wait(); @@ -2793,10 +3146,7 @@ mod tests { Err(error) if error.kind() == io::ErrorKind::Other => { std::assert_eq!(error.to_string(), "wait: Timeout of '1s' reached"); } - Err(error) => panic!( - "Assertion failed: Expected error with timeout but was: {}", - error - ), + Err(error) => panic!("Assertion failed: Expected error with timeout but was: {error}"), Ok(_) => panic!("Assertion failed: Expected timeout of `wait`."), } } @@ -2825,10 +3175,7 @@ mod tests { Err(error) if error.kind() == io::ErrorKind::Other => { std::assert_eq!(error.to_string(), "kill: Timeout of '0s' reached"); } - Err(error) => panic!( - "Assertion failed: Expected error with timeout but was: {}", - error - ), + Err(error) => panic!("Assertion failed: Expected error with timeout but was: {error}"), Ok(_) => panic!("Assertion failed: Expected timeout of `try_kill`."), } } diff --git a/tests/fixtures/cut/whitespace_delimited.expected b/tests/fixtures/cut/whitespace_delimited.expected new file mode 100644 index 000000000..cb064b7d2 --- /dev/null +++ b/tests/fixtures/cut/whitespace_delimited.expected @@ -0,0 +1,5 @@ +foo:bar:baz:qux:quux +one:two:three:four:five:six:seven +alpha:beta:gamma:delta:epsilon:zeta:eta:theta:iota:kappa:lambda:mu +the quick fox over the dog +sally sells down the seashore are the seashells sally sells diff --git a/tests/fixtures/sum/bsd_multiple_files.expected b/tests/fixtures/sum/bsd_multiple_files.expected index 1b05ee27f..941a2a512 100644 --- a/tests/fixtures/sum/bsd_multiple_files.expected +++ b/tests/fixtures/sum/bsd_multiple_files.expected @@ -1,2 +1,2 @@ -8109 1 lorem_ipsum.txt -1814 1 alice_in_wonderland.txt +08109 1 lorem_ipsum.txt +01814 1 alice_in_wonderland.txt diff --git a/tests/fixtures/sum/bsd_single_file.expected b/tests/fixtures/sum/bsd_single_file.expected index 3cffc4337..293ada3bd 100644 --- a/tests/fixtures/sum/bsd_single_file.expected +++ b/tests/fixtures/sum/bsd_single_file.expected @@ -1 +1 @@ -8109 1 +08109 1 lorem_ipsum.txt diff --git a/tests/fixtures/sum/bsd_stdin.expected b/tests/fixtures/sum/bsd_stdin.expected index 3cffc4337..4843ba082 100644 --- a/tests/fixtures/sum/bsd_stdin.expected +++ b/tests/fixtures/sum/bsd_stdin.expected @@ -1 +1 @@ -8109 1 +08109 1 diff --git a/util/android-commands.sh b/util/android-commands.sh index 1cc217692..42e27ad88 100755 --- a/util/android-commands.sh +++ b/util/android-commands.sh @@ -120,6 +120,7 @@ build () { tests () { probe='/sdcard/tests.probe' + export RUST_BACKTRACE=1 command="'cd ~/coreutils && timeout --preserve-status --verbose -k 1m 60m cargo test --features feat_os_unix_android --no-fail-fast >/sdcard/tests.log 2>&1; echo \$? >$probe'" run_termux_command "$command" "$probe" return_code=$? diff --git a/util/publish.sh b/util/publish.sh index f4fe105f5..d9039fa60 100755 --- a/util/publish.sh +++ b/util/publish.sh @@ -35,7 +35,7 @@ TOTAL_ORDER=$(echo -e $PARTIAL_ORDER | tsort | tac) TOTAL_ORDER=${TOTAL_ORDER#ROOT} set -e -for dir in src/uucore/ src/uucore_procs/ src/uu/stdbuf/src/libstdbuf/; do +for dir in src/uucore_procs/ src/uucore/ src/uu/stdbuf/src/libstdbuf/; do ( cd "$dir" #shellcheck disable=SC2086 diff --git a/util/update-version.sh b/util/update-version.sh index fe24e1de3..4b7b6d554 100755 --- a/util/update-version.sh +++ b/util/update-version.sh @@ -11,8 +11,8 @@ # 6) Run util/publish.sh --do-it # 7) In some cases, you might have to fix dependencies and run import -FROM="0.0.15" -TO="0.0.16" +FROM="0.0.16" +TO="0.0.17" PROGS=$(ls -1d src/uu/*/Cargo.toml src/uu/stdbuf/src/libstdbuf/Cargo.toml src/uucore/Cargo.toml Cargo.toml)