Merge branch 'main' into dependabot/cargo/blake3-1.3.2

This commit is contained in:
Sylvestre Ledru 2023-01-27 21:10:06 +01:00 committed by GitHub
commit 13fac01d31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
322 changed files with 3527 additions and 2674 deletions

View file

@ -1,11 +1,11 @@
name: CICD 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 (env/flags) Awarnings Ccodegen Coverflow Cpanic Dwarnings RUSTDOCFLAGS RUSTFLAGS Zpanic
# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain # spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain
# spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy # spell-checker:ignore (people) 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 (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 gnueabihf issuecomment maint nullglob onexitbegin onexitend pell runtest tempfile testsuite uutils DESTDIR multisize Swatinem # 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: env:
PROJECT_NAME: coreutils PROJECT_NAME: coreutils
@ -50,7 +50,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;; ''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
@ -102,7 +102,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;; ''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
@ -116,6 +116,7 @@ jobs:
outputs CARGO_FEATURES_OPTION outputs CARGO_FEATURES_OPTION
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt} rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt}
rustup toolchain install stable -c rustfmt --profile minimal rustup toolchain install stable -c rustfmt --profile minimal
rustup default stable rustup default stable
@ -150,7 +151,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;; ''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
@ -170,11 +171,13 @@ jobs:
- name: Install/setup prerequisites - name: Install/setup prerequisites
shell: bash shell: bash
run: | run: |
## Install/setup prerequisites
case '${{ matrix.job.os }}' in case '${{ matrix.job.os }}' in
macos-latest) brew install coreutils ;; # needed for show-utils.sh macos-latest) brew install coreutils ;; # needed for show-utils.sh
esac esac
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rustup toolchain install stable -c clippy --profile minimal rustup toolchain install stable -c clippy --profile minimal
rustup default stable rustup default stable
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -206,7 +209,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;; ''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
@ -257,7 +260,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;; ''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
@ -276,6 +279,7 @@ jobs:
outputs CARGO_UTILITY_LIST_OPTIONS outputs CARGO_UTILITY_LIST_OPTIONS
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rustup toolchain install stable -c clippy --profile minimal rustup toolchain install stable -c clippy --profile minimal
rustup default stable rustup default stable
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -299,7 +303,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # target-specific options
# * CARGO_FEATURES_OPTION # * CARGO_FEATURES_OPTION
unset CARGO_FEATURES_OPTION unset CARGO_FEATURES_OPTION
@ -307,6 +311,7 @@ jobs:
outputs CARGO_FEATURES_OPTION outputs CARGO_FEATURES_OPTION
- name: Install `rust` toolchain (v${{ env.RUST_MIN_SRV }}) - name: Install `rust` toolchain (v${{ env.RUST_MIN_SRV }})
run: | run: |
## Install `rust` toolchain (v${{ env.RUST_MIN_SRV }})
rustup toolchain install ${{ env.RUST_MIN_SRV }} --profile minimal rustup toolchain install ${{ env.RUST_MIN_SRV }} --profile minimal
rustup default ${{ env.RUST_MIN_SRV }} rustup default ${{ env.RUST_MIN_SRV }}
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -347,6 +352,7 @@ jobs:
run: cargo test -v ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -p uucore -p coreutils run: cargo test -v ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -p uucore -p coreutils
env: env:
RUSTFLAGS: "-Awarnings --cfg unsound_local_offset" RUSTFLAGS: "-Awarnings --cfg unsound_local_offset"
RUST_BACKTRACE: "1"
deps: deps:
name: Dependencies name: Dependencies
@ -360,6 +366,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rustup toolchain install stable --profile minimal rustup toolchain install stable --profile minimal
rustup default stable rustup default stable
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -383,6 +390,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rustup toolchain install stable --profile minimal rustup toolchain install stable --profile minimal
rustup default stable rustup default stable
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -394,6 +402,8 @@ jobs:
shell: bash shell: bash
run: | run: |
make test make test
env:
RUST_BACKTRACE: "1"
build_rust_stable: build_rust_stable:
@ -412,11 +422,14 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rustup toolchain install stable --profile minimal rustup toolchain install stable --profile minimal
rustup default stable rustup default stable
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- name: Test - name: Test
run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
env:
RUST_BACKTRACE: "1"
build_rust_nightly: build_rust_nightly:
name: Build/nightly name: Build/nightly
@ -434,11 +447,14 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rustup toolchain install nightly --profile minimal rustup toolchain install nightly --profile minimal
rustup default nightly rustup default nightly
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- name: Test - name: Test
run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
env:
RUST_BACKTRACE: "1"
compute_size: compute_size:
name: Binary sizes name: Binary sizes
@ -459,26 +475,29 @@ jobs:
sudo apt-get install jq sudo apt-get install jq
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rustup toolchain install stable --profile minimal rustup toolchain install stable --profile minimal
rustup default stable rustup default stable
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- name: "`make install`" - name: "`make install`"
shell: bash shell: bash
run: | run: |
## `make install`
make install DESTDIR=target/size-release/ make install DESTDIR=target/size-release/
make install MULTICALL=y DESTDIR=target/size-multi-release/ make install MULTICALL=y DESTDIR=target/size-multi-release/
# strip the results # strip the results
strip target/size*/usr/local/bin/* strip target/size*/usr/local/bin/*
- name: "Compute sizes" - name: Compute uutil release sizes
shell: bash shell: bash
run: | run: |
## Compute uutil release sizes
SIZE=$(du -s target/size-release/usr/local/bin/|awk '{print $1}') 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 \ jq -n \
--arg date "$(date --rfc-email)" \ --arg date "$(date --rfc-email)" \
--arg sha "$GITHUB_SHA" \ --arg sha "$GITHUB_SHA" \
--arg size "$SIZE" \ --arg size "$SIZE" \
--arg multisize "$SIZEMULTI" \ --arg multisize "$SIZE_MULTI" \
'{($date): { sha: $sha, size: $size, multisize: $multisize, }}' > size-result.json '{($date): { sha: $sha, size: $size, multisize: $multisize, }}' > size-result.json
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
with: with:
@ -526,7 +545,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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
TOOLCHAIN="stable" ## default to "stable" 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) # * 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/*/} REF_NAME=${GITHUB_REF#refs/*/}
unset REF_BRANCH ; case "${GITHUB_REF}" in refs/heads/*) REF_BRANCH=${GITHUB_REF#refs/heads/} ;; esac; 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; 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 outputs REF_NAME REF_BRANCH REF_TAG REF_SHAS
# parse target # parse target
unset TARGET_ARCH unset TARGET_ARCH
@ -597,7 +616,7 @@ jobs:
# ** pass needed environment into `cross` container (iff `cross` not already configured via "Cross.toml") # ** pass needed environment into `cross` container (iff `cross` not already configured via "Cross.toml")
if [ "${CARGO_CMD}" = 'cross' ] && [ ! -e "Cross.toml" ] ; then if [ "${CARGO_CMD}" = 'cross' ] && [ ! -e "Cross.toml" ] ; then
cargo install --version 0.2.1 cross 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 fi
# * test only library and/or binaries for arm-type targets # * 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; unset CARGO_TEST_OPTIONS ; case '${{ matrix.job.target }}' in aarch64-* | arm-*) CARGO_TEST_OPTIONS="--bins" ;; esac;
@ -645,6 +664,7 @@ jobs:
esac esac
- name: rust toolchain ~ install - name: rust toolchain ~ install
run: | run: |
## rust toolchain ~ install
rustup toolchain install ${{ env.RUST_MIN_SRV }} -t ${{ matrix.job.target }} --profile minimal rustup toolchain install ${{ env.RUST_MIN_SRV }} -t ${{ matrix.job.target }} --profile minimal
rustup default ${{ env.RUST_MIN_SRV }} rustup default ${{ env.RUST_MIN_SRV }}
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -655,7 +675,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## Dependent VARs setup ## 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 # * determine sub-crate utility list
UTILITY_LIST="$(./util/show-utils.sh ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }})" UTILITY_LIST="$(./util/show-utils.sh ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }})"
echo UTILITY_LIST=${UTILITY_LIST} echo UTILITY_LIST=${UTILITY_LIST}
@ -687,18 +707,25 @@ jobs:
- name: Build - name: Build
shell: bash shell: bash
run: | run: |
## Build
${{ steps.vars.outputs.CARGO_CMD }} +${{ env.RUST_MIN_SRV }} build --release \ ${{ 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 }} --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
- name: Test - name: Test
shell: bash shell: bash
run: | run: |
## Test
${{ steps.vars.outputs.CARGO_CMD }} +${{ env.RUST_MIN_SRV }} test --target=${{ matrix.job.target }} \ ${{ 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 }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
env:
RUST_BACKTRACE: "1"
- name: Test individual utilities - name: Test individual utilities
shell: bash shell: bash
run: | run: |
## Test individual utilities
${{ steps.vars.outputs.CARGO_CMD }} +${{ env.RUST_MIN_SRV }} test --target=${{ matrix.job.target }} \ ${{ 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 }} ${{ 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 - name: Archive executable artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
@ -771,10 +798,11 @@ jobs:
run: | run: |
## Install/setup prerequisites ## Install/setup prerequisites
make prepare-busytest make prepare-busytest
- name: "Run BusyBox test suite" - name: Run BusyBox test suite
id: summary id: summary
shell: bash shell: bash
run: | run: |
## Run BusyBox test suite
set -v set -v
cp .busybox-config target/debug/.config cp .busybox-config target/debug/.config
## Run BusyBox test suite ## Run BusyBox test suite
@ -835,16 +863,20 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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: actions/checkout@v3
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- name: rust toolchain ~ install - name: rust toolchain ~ install
run: | run: |
## rust toolchain ~ install
rustup toolchain install ${{ env.RUST_MIN_SRV }} --profile minimal rustup toolchain install ${{ env.RUST_MIN_SRV }} --profile minimal
rustup default ${{ env.RUST_MIN_SRV }} rustup default ${{ env.RUST_MIN_SRV }}
- name: "Build coreutils as multiple binaries" - name: Build coreutils as multiple binaries
shell: bash shell: bash
run: | run: |
## Build individual uutil binaries
set -v set -v
make make
- name: Install/setup prerequisites - name: Install/setup prerequisites
@ -852,12 +884,12 @@ jobs:
run: | run: |
## Install/setup prerequisites ## Install/setup prerequisites
make toybox-src make toybox-src
- name: "Run Toybox test suite" - name: Run Toybox test suite
id: summary id: summary
shell: bash shell: bash
run: | run: |
set -v
## Run Toybox test suite ## Run Toybox test suite
set -v
cd tmp/toybox-*/ cd tmp/toybox-*/
make defconfig make defconfig
make tests &> tmp.log || true make tests &> tmp.log || true
@ -1023,6 +1055,7 @@ jobs:
cd "${WORKSPACE}" cd "${WORKSPACE}"
unset FAULT unset FAULT
cargo build || FAULT=1 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 --features '${{ matrix.job.features }}' || FAULT=1 ; fi
if (test -z "\$FAULT"); then cargo test --all-features -p uucore || 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 # Clean to avoid to rsync back the files
@ -1050,7 +1083,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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
TOOLCHAIN="nightly" ## default to "nightly" toolchain (required for certain required unstable compiler flags) ## !maint: refactor when stable channel has needed support 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 # * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files
@ -1093,6 +1126,7 @@ jobs:
esac esac
- name: rust toolchain ~ install - name: rust toolchain ~ install
run: | run: |
## rust toolchain ~ install
rustup toolchain install ${{ steps.vars.outputs.TOOLCHAIN }} --profile minimal rustup toolchain install ${{ steps.vars.outputs.TOOLCHAIN }} --profile minimal
rustup default ${{ steps.vars.outputs.TOOLCHAIN }} rustup default ${{ steps.vars.outputs.TOOLCHAIN }}
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -1101,7 +1135,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## Dependent VARs setup ## 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 # * determine sub-crate utility list
UTILITY_LIST="$(./util/show-utils.sh ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }})" 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;)" CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo -n "-puu_${u} "; done;)"
@ -1113,6 +1147,7 @@ jobs:
RUSTC_WRAPPER: "" RUSTC_WRAPPER: ""
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
RUSTDOCFLAGS: "-Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort"
RUST_BACKTRACE: "1"
# RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }}
- name: Test - name: Test
run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast
@ -1121,6 +1156,7 @@ jobs:
RUSTC_WRAPPER: "" RUSTC_WRAPPER: ""
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
RUSTDOCFLAGS: "-Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort"
RUST_BACKTRACE: "1"
# RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }}
- name: Test individual utilities - name: Test individual utilities
run: cargo test --no-fail-fast ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} run: cargo test --no-fail-fast ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }}
@ -1129,6 +1165,7 @@ jobs:
RUSTC_WRAPPER: "" RUSTC_WRAPPER: ""
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
RUSTDOCFLAGS: "-Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort"
RUST_BACKTRACE: "1"
# RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }} # RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }}
- name: "`grcov` ~ install" - name: "`grcov` ~ install"
id: build_grcov id: build_grcov

View file

@ -32,12 +32,13 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # 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)" ) RUST_MIN_SRV=$(grep -P "^\s+RUST_MIN_SRV:" .github/workflows/CICD.yml | grep -Po "(?<=\x22)\d+[.]\d+(?:[.]\d+)?(?=\x22)" )
outputs RUST_MIN_SRV outputs RUST_MIN_SRV
- name: Install `rust` toolchain (v${{ steps.vars.outputs.RUST_MIN_SRV }}) - name: Install `rust` toolchain (v${{ steps.vars.outputs.RUST_MIN_SRV }})
run: | run: |
## Install `rust` toolchain (v${{ steps.vars.outputs.RUST_MIN_SRV }})
rustup toolchain install ${{ steps.vars.outputs.RUST_MIN_SRV }} --profile minimal rustup toolchain install ${{ steps.vars.outputs.RUST_MIN_SRV }} --profile minimal
rustup default ${{ steps.vars.outputs.RUST_MIN_SRV }} rustup default ${{ steps.vars.outputs.RUST_MIN_SRV }}
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@ -94,7 +95,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # target-specific options
# * CARGO_FEATURES_OPTION # * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ; CARGO_FEATURES_OPTION='' ;
@ -102,6 +103,7 @@ jobs:
outputs CARGO_FEATURES_OPTION outputs CARGO_FEATURES_OPTION
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt} rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt}
rustup toolchain install stable -c rustfmt --profile minimal rustup toolchain install stable -c rustfmt --profile minimal
rustup default stable rustup default stable

View file

@ -1,6 +1,11 @@
name: GnuTests 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` # * note: to run a single test => `REPO/util/run-gnu-test.sh PATH/TO/TEST/SCRIPT`
@ -23,7 +28,7 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## 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 # * config
path_GNU="gnu" path_GNU="gnu"
path_GNU_tests="${path_GNU}/tests" path_GNU_tests="${path_GNU}/tests"
@ -67,6 +72,7 @@ jobs:
path: "${{ steps.vars.outputs.path_reference }}" path: "${{ steps.vars.outputs.path_reference }}"
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt} rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt}
rustup toolchain install stable -c rustfmt --profile minimal rustup toolchain install stable -c rustfmt --profile minimal
rustup default stable rustup default stable
@ -79,6 +85,7 @@ jobs:
- name: Add various locales - name: Add various locales
shell: bash shell: bash
run: | run: |
## Add various locales
echo "Before:" echo "Before:"
locale -a locale -a
## Some tests fail with 'cannot change locale (en_US.ISO-8859-1): No such file or directory' ## 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 - name: Run GNU tests
shell: bash shell: bash
run: | run: |
## Run GNU tests
path_GNU='${{ steps.vars.outputs.path_GNU }}' path_GNU='${{ steps.vars.outputs.path_GNU }}'
path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}'
bash "${path_UUTILS}/util/run-gnu-test.sh" bash "${path_UUTILS}/util/run-gnu-test.sh"
- name: Run GNU root tests - name: Run GNU root tests
shell: bash shell: bash
run: | run: |
## Run GNU root tests
path_GNU='${{ steps.vars.outputs.path_GNU }}' path_GNU='${{ steps.vars.outputs.path_GNU }}'
path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}'
bash "${path_UUTILS}/util/run-gnu-test.sh" run-root bash "${path_UUTILS}/util/run-gnu-test.sh" run-root
- name: Extract testing info into JSON - name: Extract testing info into JSON
shell: bash shell: bash
run : | run : |
## Extract testing info into JSON
path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}' 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 }} 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 - name: Extract/summarize testing info
id: summary id: summary
shell: bash shell: bash
run: | run: |
path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}'
## Extract/summarize testing info ## 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 }}' SUITE_LOG_FILE='${{ steps.vars.outputs.SUITE_LOG_FILE }}'
ROOT_SUITE_LOG_FILE='${{ steps.vars.outputs.ROOT_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 - name: Compare test failures VS reference
shell: bash shell: bash
run: | run: |
## Compare test failures VS reference
have_new_failures="" have_new_failures=""
REF_LOG_FILE='${{ steps.vars.outputs.path_reference }}/test-logs/test-suite.log' 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' 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 if: success() || failure() # run regardless of prior step success/failure
shell: bash shell: bash
run: | run: |
## Compare test summary VS reference
REF_SUMMARY_FILE='${{ steps.vars.outputs.path_reference }}/test-summary/gnu-result.json' REF_SUMMARY_FILE='${{ steps.vars.outputs.path_reference }}/test-summary/gnu-result.json'
if test -f "${REF_SUMMARY_FILE}"; then if test -f "${REF_SUMMARY_FILE}"; then
echo "Reference SHA1/ID: $(sha1sum -- "${REF_SUMMARY_FILE}")" echo "Reference SHA1/ID: $(sha1sum -- "${REF_SUMMARY_FILE}")"
@ -280,15 +293,18 @@ jobs:
submodules: recursive submodules: recursive
- name: Install `rust` toolchain - name: Install `rust` toolchain
run: | run: |
## Install `rust` toolchain
rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt} rm -f "${HOME}/.cargo/bin/"{rustfmt,cargo-fmt}
rustup toolchain install nightly -c rustfmt --profile minimal rustup toolchain install nightly -c rustfmt --profile minimal
rustup default nightly rustup default nightly
- name: Install dependencies - name: Install dependencies
run: | run: |
## Install dependencies
sudo apt update sudo apt update
sudo apt install autoconf autopoint bison texinfo gperf gcc g++ gdb python3-pyinotify jq valgrind libexpect-perl -y sudo apt install autoconf autopoint bison texinfo gperf gcc g++ gdb python3-pyinotify jq valgrind libexpect-perl -y
- name: Add various locales - name: Add various locales
run: | run: |
## Add various locales
echo "Before:" echo "Before:"
locale -a locale -a
## Some tests fail with 'cannot change locale (en_US.ISO-8859-1): No such file or directory' ## 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" RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
RUSTDOCFLAGS: "-Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort"
run: | run: |
## Build binaries
cd uutils cd uutils
UU_MAKE_PROFILE=debug bash util/build-gnu.sh UU_MAKE_PROFILE=debug bash util/build-gnu.sh
- name: Run GNU tests - name: Run GNU tests

218
Cargo.lock generated
View file

@ -326,7 +326,7 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]] [[package]]
name = "coreutils" name = "coreutils"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"atty", "atty",
"chrono", "chrono",
@ -1633,9 +1633,9 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]] [[package]]
name = "platform-info" name = "platform-info"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4278b2b54a23c9a91d5bae9b09e21d566f8b23890491951160b05d64f29d1d8b" checksum = "4e7c23cfae725ae06d9e43010153fa77bdfa8c827bf08fe4beeb2a3514e6be12"
dependencies = [ dependencies = [
"libc", "libc",
"winapi", "winapi",
@ -2328,7 +2328,7 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]] [[package]]
name = "uu_arch" name = "uu_arch"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"platform-info", "platform-info",
@ -2337,7 +2337,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_base32" name = "uu_base32"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2345,7 +2345,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_base64" name = "uu_base64"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"uu_base32", "uu_base32",
"uucore", "uucore",
@ -2353,7 +2353,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_basename" name = "uu_basename"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2361,7 +2361,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_basenc" name = "uu_basenc"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uu_base32", "uu_base32",
@ -2370,7 +2370,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_cat" name = "uu_cat"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"atty", "atty",
"clap", "clap",
@ -2381,7 +2381,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chcon" name = "uu_chcon"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"fts-sys", "fts-sys",
@ -2393,7 +2393,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chgrp" name = "uu_chgrp"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2401,7 +2401,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chmod" name = "uu_chmod"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2410,7 +2410,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chown" name = "uu_chown"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2418,7 +2418,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chroot" name = "uu_chroot"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2426,7 +2426,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_cksum" name = "uu_cksum"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2434,7 +2434,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_comm" name = "uu_comm"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2442,7 +2442,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_cp" name = "uu_cp"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"exacl", "exacl",
@ -2458,7 +2458,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_csplit" name = "uu_csplit"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"regex", "regex",
@ -2468,7 +2468,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_cut" name = "uu_cut"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"atty", "atty",
"bstr", "bstr",
@ -2479,7 +2479,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_date" name = "uu_date"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -2490,7 +2490,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_dd" name = "uu_dd"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"gcd", "gcd",
@ -2501,7 +2501,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_df" name = "uu_df"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"unicode-width", "unicode-width",
@ -2510,7 +2510,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_dir" name = "uu_dir"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uu_ls", "uu_ls",
@ -2519,7 +2519,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_dircolors" name = "uu_dircolors"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2527,7 +2527,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_dirname" name = "uu_dirname"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2535,7 +2535,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_du" name = "uu_du"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -2546,7 +2546,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_echo" name = "uu_echo"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2554,7 +2554,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_env" name = "uu_env"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
@ -2564,7 +2564,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_expand" name = "uu_expand"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"unicode-width", "unicode-width",
@ -2573,7 +2573,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_expr" name = "uu_expr"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"num-bigint", "num-bigint",
@ -2584,7 +2584,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_factor" name = "uu_factor"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"coz", "coz",
@ -2598,7 +2598,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_false" name = "uu_false"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2606,7 +2606,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_fmt" name = "uu_fmt"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"unicode-width", "unicode-width",
@ -2615,7 +2615,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_fold" name = "uu_fold"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2623,7 +2623,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_groups" name = "uu_groups"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2631,7 +2631,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_hashsum" name = "uu_hashsum"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"blake2b_simd", "blake2b_simd",
"blake3", "blake3",
@ -2649,7 +2649,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_head" name = "uu_head"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -2658,7 +2658,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_hostid" name = "uu_hostid"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2667,7 +2667,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_hostname" name = "uu_hostname"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"hostname", "hostname",
@ -2677,7 +2677,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_id" name = "uu_id"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"selinux", "selinux",
@ -2686,7 +2686,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_install" name = "uu_install"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"file_diff", "file_diff",
@ -2698,7 +2698,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_join" name = "uu_join"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -2707,7 +2707,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_kill" name = "uu_kill"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
@ -2716,7 +2716,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_link" name = "uu_link"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2724,7 +2724,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_ln" name = "uu_ln"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2732,7 +2732,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_logname" name = "uu_logname"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2741,7 +2741,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_ls" name = "uu_ls"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"atty", "atty",
"chrono", "chrono",
@ -2759,7 +2759,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mkdir" name = "uu_mkdir"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2767,7 +2767,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mkfifo" name = "uu_mkfifo"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2776,7 +2776,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mknod" name = "uu_mknod"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2785,7 +2785,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mktemp" name = "uu_mktemp"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"rand", "rand",
@ -2795,7 +2795,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_more" name = "uu_more"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"atty", "atty",
"clap", "clap",
@ -2808,7 +2808,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mv" name = "uu_mv"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"fs_extra", "fs_extra",
@ -2818,7 +2818,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_nice" name = "uu_nice"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2828,7 +2828,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_nl" name = "uu_nl"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"regex", "regex",
@ -2837,7 +2837,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_nohup" name = "uu_nohup"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"atty", "atty",
"clap", "clap",
@ -2847,7 +2847,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_nproc" name = "uu_nproc"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2857,7 +2857,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_numfmt" name = "uu_numfmt"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2865,7 +2865,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_od" name = "uu_od"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"clap", "clap",
@ -2875,7 +2875,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_paste" name = "uu_paste"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2883,7 +2883,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_pathchk" name = "uu_pathchk"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2892,7 +2892,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_pinky" name = "uu_pinky"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2900,7 +2900,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_pr" name = "uu_pr"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"itertools", "itertools",
@ -2912,7 +2912,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_printenv" name = "uu_printenv"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2920,7 +2920,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_printf" name = "uu_printf"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2928,7 +2928,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_ptx" name = "uu_ptx"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"regex", "regex",
@ -2937,7 +2937,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_pwd" name = "uu_pwd"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2945,7 +2945,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_readlink" name = "uu_readlink"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2953,7 +2953,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_realpath" name = "uu_realpath"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2961,7 +2961,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_relpath" name = "uu_relpath"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2969,7 +2969,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_rm" name = "uu_rm"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2981,7 +2981,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_rmdir" name = "uu_rmdir"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2990,7 +2990,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_runcon" name = "uu_runcon"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3001,7 +3001,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_seq" name = "uu_seq"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"clap", "clap",
@ -3012,7 +3012,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_shred" name = "uu_shred"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"rand", "rand",
@ -3021,7 +3021,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_shuf" name = "uu_shuf"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -3032,7 +3032,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_sleep" name = "uu_sleep"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3040,7 +3040,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_sort" name = "uu_sort"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"binary-heap-plus", "binary-heap-plus",
"clap", "clap",
@ -3059,7 +3059,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_split" name = "uu_split"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -3068,7 +3068,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_stat" name = "uu_stat"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3076,7 +3076,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_stdbuf" name = "uu_stdbuf"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"tempfile", "tempfile",
@ -3086,7 +3086,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_stdbuf_libstdbuf" name = "uu_stdbuf_libstdbuf"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"cpp", "cpp",
"cpp_build", "cpp_build",
@ -3096,7 +3096,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_stty" name = "uu_stty"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
@ -3105,7 +3105,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_sum" name = "uu_sum"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3113,7 +3113,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_sync" name = "uu_sync"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3124,7 +3124,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tac" name = "uu_tac"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -3135,7 +3135,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tail" name = "uu_tail"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"atty", "atty",
"clap", "clap",
@ -3151,7 +3151,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tee" name = "uu_tee"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3161,7 +3161,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_test" name = "uu_test"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3171,7 +3171,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_timeout" name = "uu_timeout"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3181,7 +3181,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_touch" name = "uu_touch"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"filetime", "filetime",
@ -3192,7 +3192,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tr" name = "uu_tr"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"nom", "nom",
@ -3201,7 +3201,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_true" name = "uu_true"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3209,7 +3209,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_truncate" name = "uu_truncate"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3217,7 +3217,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tsort" name = "uu_tsort"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3225,7 +3225,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tty" name = "uu_tty"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"atty", "atty",
"clap", "clap",
@ -3235,7 +3235,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_uname" name = "uu_uname"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"platform-info", "platform-info",
@ -3244,7 +3244,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_unexpand" name = "uu_unexpand"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"unicode-width", "unicode-width",
@ -3253,7 +3253,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_uniq" name = "uu_uniq"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"strum", "strum",
@ -3263,7 +3263,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_unlink" name = "uu_unlink"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3271,7 +3271,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_uptime" name = "uu_uptime"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -3280,7 +3280,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_users" name = "uu_users"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3288,7 +3288,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_vdir" name = "uu_vdir"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uu_ls", "uu_ls",
@ -3297,7 +3297,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_wc" name = "uu_wc"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"bytecount", "bytecount",
"clap", "clap",
@ -3310,7 +3310,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_who" name = "uu_who"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3318,7 +3318,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_whoami" name = "uu_whoami"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3328,7 +3328,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_yes" name = "uu_yes"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3338,7 +3338,7 @@ dependencies = [
[[package]] [[package]]
name = "uucore" name = "uucore"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"clap", "clap",
"data-encoding", "data-encoding",
@ -3363,7 +3363,7 @@ dependencies = [
[[package]] [[package]]
name = "uucore_procs" name = "uucore_procs"
version = "0.0.16" version = "0.0.17"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -5,7 +5,7 @@
[package] [package]
name = "coreutils" name = "coreutils"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust" 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 ## project-specific feature shortcodes
nightly = [] nightly = []
test_unimplemented = [] 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 ## feature sets
## (common/core and Tier1) feature sets ## (common/core and Tier1) feature sets
# "feat_common_core" == baseline core set of utilities which can be built/run on most targets # "feat_common_core" == baseline core set of utilities which can be built/run on most targets
@ -115,13 +129,15 @@ feat_Tier1 = [
"nproc", "nproc",
"sync", "sync",
"touch", "touch",
"uname",
"whoami", "whoami",
] ]
## (primary platforms) feature sets ## (primary platforms) feature sets
# "feat_os_macos" == set of utilities which can be built/run on the MacOS platform # "feat_os_macos" == set of utilities which can be built/run on the MacOS platform
feat_os_macos = [ feat_os_macos = [
"feat_os_unix", ## == a modern/usual *nix platform "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" == set of utilities which can be built/run on modern/usual *nix platforms
feat_os_unix = [ feat_os_unix = [
@ -141,31 +157,21 @@ feat_os_unix_gnueabihf = [
"feat_Tier1", "feat_Tier1",
# #
"feat_require_unix", "feat_require_unix",
"feat_require_unix_hostid",
"feat_require_unix_utmpx", "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: <https://musl.libc.org/about.html>) # "feat_os_unix_musl" == set of utilities which can be built/run on targets binding to the "musl" library (ref: <https://musl.libc.org/about.html>)
feat_os_unix_musl = [ feat_os_unix_musl = [
"feat_Tier1", "feat_Tier1",
# #
"feat_require_unix", "feat_require_unix",
"feat_require_hostid", "feat_require_unix_hostid",
] ]
feat_os_unix_android = [ feat_os_unix_android = [
"feat_Tier1", "feat_Tier1",
# #
"feat_require_unix", "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) ## 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 # ** 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", "stty",
"timeout", "timeout",
"tty", "tty",
"uname",
] ]
# "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support # "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support
# * ref: <https://wiki.musl-libc.org/faq.html#Q:-Why-is-the-utmp/wtmp-functionality-only-implemented-as-stubs?> # * ref: <https://wiki.musl-libc.org/faq.html#Q:-Why-is-the-utmp/wtmp-functionality-only-implemented-as-stubs?>
@ -204,8 +209,8 @@ feat_require_unix_utmpx = [
"users", "users",
"who", "who",
] ]
# "feat_require_hostid" == set of utilities requiring gethostid in libc (only some unixes provide) # "feat_require_unix_hostid" == set of utilities requiring gethostid in libc (only some unixes provide)
feat_require_hostid = [ feat_require_unix_hostid = [
"hostid", "hostid",
] ]
# "feat_require_selinux" == set of utilities depending on SELinux. # "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) # * 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" ] test = [ "uu_test" ]
uudoc = [ "zip" ]
[workspace] [workspace]
@ -267,113 +271,113 @@ once_cell = "1.13.1"
phf = "0.11.1" phf = "0.11.1"
selinux = { version="0.3", optional = true } selinux = { version="0.3", optional = true }
textwrap = { version="0.16.0", features=["terminal_size"] } 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"] } zip = { version = "0.6.3", optional=true, default_features=false, features=["deflate"] }
# * uutils # * 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" } arch = { optional=true, version="0.0.17", package="uu_arch", path="src/uu/arch" }
base32 = { optional=true, version="0.0.16", package="uu_base32", path="src/uu/base32" } base32 = { optional=true, version="0.0.17", package="uu_base32", path="src/uu/base32" }
base64 = { optional=true, version="0.0.16", package="uu_base64", path="src/uu/base64" } base64 = { optional=true, version="0.0.17", package="uu_base64", path="src/uu/base64" }
basename = { optional=true, version="0.0.16", package="uu_basename", path="src/uu/basename" } basename = { optional=true, version="0.0.17", package="uu_basename", path="src/uu/basename" }
basenc = { optional=true, version="0.0.16", package="uu_basenc", path="src/uu/basenc" } basenc = { optional=true, version="0.0.17", package="uu_basenc", path="src/uu/basenc" }
cat = { optional=true, version="0.0.16", package="uu_cat", path="src/uu/cat" } cat = { optional=true, version="0.0.17", package="uu_cat", path="src/uu/cat" }
chcon = { optional=true, version="0.0.16", package="uu_chcon", path="src/uu/chcon" } chcon = { optional=true, version="0.0.17", package="uu_chcon", path="src/uu/chcon" }
chgrp = { optional=true, version="0.0.16", package="uu_chgrp", path="src/uu/chgrp" } chgrp = { optional=true, version="0.0.17", package="uu_chgrp", path="src/uu/chgrp" }
chmod = { optional=true, version="0.0.16", package="uu_chmod", path="src/uu/chmod" } chmod = { optional=true, version="0.0.17", package="uu_chmod", path="src/uu/chmod" }
chown = { optional=true, version="0.0.16", package="uu_chown", path="src/uu/chown" } chown = { optional=true, version="0.0.17", package="uu_chown", path="src/uu/chown" }
chroot = { optional=true, version="0.0.16", package="uu_chroot", path="src/uu/chroot" } chroot = { optional=true, version="0.0.17", package="uu_chroot", path="src/uu/chroot" }
cksum = { optional=true, version="0.0.16", package="uu_cksum", path="src/uu/cksum" } cksum = { optional=true, version="0.0.17", package="uu_cksum", path="src/uu/cksum" }
comm = { optional=true, version="0.0.16", package="uu_comm", path="src/uu/comm" } comm = { optional=true, version="0.0.17", package="uu_comm", path="src/uu/comm" }
cp = { optional=true, version="0.0.16", package="uu_cp", path="src/uu/cp" } cp = { optional=true, version="0.0.17", package="uu_cp", path="src/uu/cp" }
csplit = { optional=true, version="0.0.16", package="uu_csplit", path="src/uu/csplit" } csplit = { optional=true, version="0.0.17", package="uu_csplit", path="src/uu/csplit" }
cut = { optional=true, version="0.0.16", package="uu_cut", path="src/uu/cut" } cut = { optional=true, version="0.0.17", package="uu_cut", path="src/uu/cut" }
date = { optional=true, version="0.0.16", package="uu_date", path="src/uu/date" } date = { optional=true, version="0.0.17", package="uu_date", path="src/uu/date" }
dd = { optional=true, version="0.0.16", package="uu_dd", path="src/uu/dd" } dd = { optional=true, version="0.0.17", package="uu_dd", path="src/uu/dd" }
df = { optional=true, version="0.0.16", package="uu_df", path="src/uu/df" } df = { optional=true, version="0.0.17", package="uu_df", path="src/uu/df" }
dir = { optional=true, version="0.0.16", package="uu_dir", path="src/uu/dir" } dir = { optional=true, version="0.0.17", package="uu_dir", path="src/uu/dir" }
dircolors= { optional=true, version="0.0.16", package="uu_dircolors", path="src/uu/dircolors" } dircolors= { optional=true, version="0.0.17", package="uu_dircolors", path="src/uu/dircolors" }
dirname = { optional=true, version="0.0.16", package="uu_dirname", path="src/uu/dirname" } dirname = { optional=true, version="0.0.17", package="uu_dirname", path="src/uu/dirname" }
du = { optional=true, version="0.0.16", package="uu_du", path="src/uu/du" } du = { optional=true, version="0.0.17", package="uu_du", path="src/uu/du" }
echo = { optional=true, version="0.0.16", package="uu_echo", path="src/uu/echo" } echo = { optional=true, version="0.0.17", package="uu_echo", path="src/uu/echo" }
env = { optional=true, version="0.0.16", package="uu_env", path="src/uu/env" } env = { optional=true, version="0.0.17", package="uu_env", path="src/uu/env" }
expand = { optional=true, version="0.0.16", package="uu_expand", path="src/uu/expand" } expand = { optional=true, version="0.0.17", package="uu_expand", path="src/uu/expand" }
expr = { optional=true, version="0.0.16", package="uu_expr", path="src/uu/expr" } expr = { optional=true, version="0.0.17", package="uu_expr", path="src/uu/expr" }
factor = { optional=true, version="0.0.16", package="uu_factor", path="src/uu/factor" } factor = { optional=true, version="0.0.17", package="uu_factor", path="src/uu/factor" }
false = { optional=true, version="0.0.16", package="uu_false", path="src/uu/false" } false = { optional=true, version="0.0.17", package="uu_false", path="src/uu/false" }
fmt = { optional=true, version="0.0.16", package="uu_fmt", path="src/uu/fmt" } fmt = { optional=true, version="0.0.17", package="uu_fmt", path="src/uu/fmt" }
fold = { optional=true, version="0.0.16", package="uu_fold", path="src/uu/fold" } fold = { optional=true, version="0.0.17", package="uu_fold", path="src/uu/fold" }
groups = { optional=true, version="0.0.16", package="uu_groups", path="src/uu/groups" } groups = { optional=true, version="0.0.17", package="uu_groups", path="src/uu/groups" }
hashsum = { optional=true, version="0.0.16", package="uu_hashsum", path="src/uu/hashsum" } hashsum = { optional=true, version="0.0.17", package="uu_hashsum", path="src/uu/hashsum" }
head = { optional=true, version="0.0.16", package="uu_head", path="src/uu/head" } head = { optional=true, version="0.0.17", package="uu_head", path="src/uu/head" }
hostid = { optional=true, version="0.0.16", package="uu_hostid", path="src/uu/hostid" } hostid = { optional=true, version="0.0.17", package="uu_hostid", path="src/uu/hostid" }
hostname = { optional=true, version="0.0.16", package="uu_hostname", path="src/uu/hostname" } hostname = { optional=true, version="0.0.17", package="uu_hostname", path="src/uu/hostname" }
id = { optional=true, version="0.0.16", package="uu_id", path="src/uu/id" } id = { optional=true, version="0.0.17", package="uu_id", path="src/uu/id" }
install = { optional=true, version="0.0.16", package="uu_install", path="src/uu/install" } install = { optional=true, version="0.0.17", package="uu_install", path="src/uu/install" }
join = { optional=true, version="0.0.16", package="uu_join", path="src/uu/join" } join = { optional=true, version="0.0.17", package="uu_join", path="src/uu/join" }
kill = { optional=true, version="0.0.16", package="uu_kill", path="src/uu/kill" } kill = { optional=true, version="0.0.17", package="uu_kill", path="src/uu/kill" }
link = { optional=true, version="0.0.16", package="uu_link", path="src/uu/link" } link = { optional=true, version="0.0.17", package="uu_link", path="src/uu/link" }
ln = { optional=true, version="0.0.16", package="uu_ln", path="src/uu/ln" } ln = { optional=true, version="0.0.17", package="uu_ln", path="src/uu/ln" }
ls = { optional=true, version="0.0.16", package="uu_ls", path="src/uu/ls" } ls = { optional=true, version="0.0.17", package="uu_ls", path="src/uu/ls" }
logname = { optional=true, version="0.0.16", package="uu_logname", path="src/uu/logname" } logname = { optional=true, version="0.0.17", package="uu_logname", path="src/uu/logname" }
mkdir = { optional=true, version="0.0.16", package="uu_mkdir", path="src/uu/mkdir" } mkdir = { optional=true, version="0.0.17", package="uu_mkdir", path="src/uu/mkdir" }
mkfifo = { optional=true, version="0.0.16", package="uu_mkfifo", path="src/uu/mkfifo" } mkfifo = { optional=true, version="0.0.17", package="uu_mkfifo", path="src/uu/mkfifo" }
mknod = { optional=true, version="0.0.16", package="uu_mknod", path="src/uu/mknod" } mknod = { optional=true, version="0.0.17", package="uu_mknod", path="src/uu/mknod" }
mktemp = { optional=true, version="0.0.16", package="uu_mktemp", path="src/uu/mktemp" } mktemp = { optional=true, version="0.0.17", package="uu_mktemp", path="src/uu/mktemp" }
more = { optional=true, version="0.0.16", package="uu_more", path="src/uu/more" } more = { optional=true, version="0.0.17", package="uu_more", path="src/uu/more" }
mv = { optional=true, version="0.0.16", package="uu_mv", path="src/uu/mv" } mv = { optional=true, version="0.0.17", package="uu_mv", path="src/uu/mv" }
nice = { optional=true, version="0.0.16", package="uu_nice", path="src/uu/nice" } nice = { optional=true, version="0.0.17", package="uu_nice", path="src/uu/nice" }
nl = { optional=true, version="0.0.16", package="uu_nl", path="src/uu/nl" } nl = { optional=true, version="0.0.17", package="uu_nl", path="src/uu/nl" }
nohup = { optional=true, version="0.0.16", package="uu_nohup", path="src/uu/nohup" } nohup = { optional=true, version="0.0.17", package="uu_nohup", path="src/uu/nohup" }
nproc = { optional=true, version="0.0.16", package="uu_nproc", path="src/uu/nproc" } nproc = { optional=true, version="0.0.17", package="uu_nproc", path="src/uu/nproc" }
numfmt = { optional=true, version="0.0.16", package="uu_numfmt", path="src/uu/numfmt" } numfmt = { optional=true, version="0.0.17", package="uu_numfmt", path="src/uu/numfmt" }
od = { optional=true, version="0.0.16", package="uu_od", path="src/uu/od" } od = { optional=true, version="0.0.17", package="uu_od", path="src/uu/od" }
paste = { optional=true, version="0.0.16", package="uu_paste", path="src/uu/paste" } paste = { optional=true, version="0.0.17", package="uu_paste", path="src/uu/paste" }
pathchk = { optional=true, version="0.0.16", package="uu_pathchk", path="src/uu/pathchk" } pathchk = { optional=true, version="0.0.17", package="uu_pathchk", path="src/uu/pathchk" }
pinky = { optional=true, version="0.0.16", package="uu_pinky", path="src/uu/pinky" } pinky = { optional=true, version="0.0.17", package="uu_pinky", path="src/uu/pinky" }
pr = { optional=true, version="0.0.16", package="uu_pr", path="src/uu/pr" } pr = { optional=true, version="0.0.17", package="uu_pr", path="src/uu/pr" }
printenv = { optional=true, version="0.0.16", package="uu_printenv", path="src/uu/printenv" } printenv = { optional=true, version="0.0.17", package="uu_printenv", path="src/uu/printenv" }
printf = { optional=true, version="0.0.16", package="uu_printf", path="src/uu/printf" } printf = { optional=true, version="0.0.17", package="uu_printf", path="src/uu/printf" }
ptx = { optional=true, version="0.0.16", package="uu_ptx", path="src/uu/ptx" } ptx = { optional=true, version="0.0.17", package="uu_ptx", path="src/uu/ptx" }
pwd = { optional=true, version="0.0.16", package="uu_pwd", path="src/uu/pwd" } pwd = { optional=true, version="0.0.17", package="uu_pwd", path="src/uu/pwd" }
readlink = { optional=true, version="0.0.16", package="uu_readlink", path="src/uu/readlink" } readlink = { optional=true, version="0.0.17", package="uu_readlink", path="src/uu/readlink" }
realpath = { optional=true, version="0.0.16", package="uu_realpath", path="src/uu/realpath" } realpath = { optional=true, version="0.0.17", package="uu_realpath", path="src/uu/realpath" }
relpath = { optional=true, version="0.0.16", package="uu_relpath", path="src/uu/relpath" } relpath = { optional=true, version="0.0.17", package="uu_relpath", path="src/uu/relpath" }
rm = { optional=true, version="0.0.16", package="uu_rm", path="src/uu/rm" } rm = { optional=true, version="0.0.17", package="uu_rm", path="src/uu/rm" }
rmdir = { optional=true, version="0.0.16", package="uu_rmdir", path="src/uu/rmdir" } rmdir = { optional=true, version="0.0.17", package="uu_rmdir", path="src/uu/rmdir" }
runcon = { optional=true, version="0.0.16", package="uu_runcon", path="src/uu/runcon" } runcon = { optional=true, version="0.0.17", package="uu_runcon", path="src/uu/runcon" }
seq = { optional=true, version="0.0.16", package="uu_seq", path="src/uu/seq" } seq = { optional=true, version="0.0.17", package="uu_seq", path="src/uu/seq" }
shred = { optional=true, version="0.0.16", package="uu_shred", path="src/uu/shred" } shred = { optional=true, version="0.0.17", package="uu_shred", path="src/uu/shred" }
shuf = { optional=true, version="0.0.16", package="uu_shuf", path="src/uu/shuf" } shuf = { optional=true, version="0.0.17", package="uu_shuf", path="src/uu/shuf" }
sleep = { optional=true, version="0.0.16", package="uu_sleep", path="src/uu/sleep" } sleep = { optional=true, version="0.0.17", package="uu_sleep", path="src/uu/sleep" }
sort = { optional=true, version="0.0.16", package="uu_sort", path="src/uu/sort" } sort = { optional=true, version="0.0.17", package="uu_sort", path="src/uu/sort" }
split = { optional=true, version="0.0.16", package="uu_split", path="src/uu/split" } split = { optional=true, version="0.0.17", package="uu_split", path="src/uu/split" }
stat = { optional=true, version="0.0.16", package="uu_stat", path="src/uu/stat" } stat = { optional=true, version="0.0.17", package="uu_stat", path="src/uu/stat" }
stdbuf = { optional=true, version="0.0.16", package="uu_stdbuf", path="src/uu/stdbuf" } stdbuf = { optional=true, version="0.0.17", package="uu_stdbuf", path="src/uu/stdbuf" }
stty = { optional=true, version="0.0.16", package="uu_stty", path="src/uu/stty" } stty = { optional=true, version="0.0.17", package="uu_stty", path="src/uu/stty" }
sum = { optional=true, version="0.0.16", package="uu_sum", path="src/uu/sum" } sum = { optional=true, version="0.0.17", package="uu_sum", path="src/uu/sum" }
sync = { optional=true, version="0.0.16", package="uu_sync", path="src/uu/sync" } sync = { optional=true, version="0.0.17", package="uu_sync", path="src/uu/sync" }
tac = { optional=true, version="0.0.16", package="uu_tac", path="src/uu/tac" } tac = { optional=true, version="0.0.17", package="uu_tac", path="src/uu/tac" }
tail = { optional=true, version="0.0.16", package="uu_tail", path="src/uu/tail" } tail = { optional=true, version="0.0.17", package="uu_tail", path="src/uu/tail" }
tee = { optional=true, version="0.0.16", package="uu_tee", path="src/uu/tee" } tee = { optional=true, version="0.0.17", package="uu_tee", path="src/uu/tee" }
timeout = { optional=true, version="0.0.16", package="uu_timeout", path="src/uu/timeout" } timeout = { optional=true, version="0.0.17", package="uu_timeout", path="src/uu/timeout" }
touch = { optional=true, version="0.0.16", package="uu_touch", path="src/uu/touch" } touch = { optional=true, version="0.0.17", package="uu_touch", path="src/uu/touch" }
tr = { optional=true, version="0.0.16", package="uu_tr", path="src/uu/tr" } tr = { optional=true, version="0.0.17", package="uu_tr", path="src/uu/tr" }
true = { optional=true, version="0.0.16", package="uu_true", path="src/uu/true" } true = { optional=true, version="0.0.17", package="uu_true", path="src/uu/true" }
truncate = { optional=true, version="0.0.16", package="uu_truncate", path="src/uu/truncate" } truncate = { optional=true, version="0.0.17", package="uu_truncate", path="src/uu/truncate" }
tsort = { optional=true, version="0.0.16", package="uu_tsort", path="src/uu/tsort" } tsort = { optional=true, version="0.0.17", package="uu_tsort", path="src/uu/tsort" }
tty = { optional=true, version="0.0.16", package="uu_tty", path="src/uu/tty" } tty = { optional=true, version="0.0.17", package="uu_tty", path="src/uu/tty" }
uname = { optional=true, version="0.0.16", package="uu_uname", path="src/uu/uname" } uname = { optional=true, version="0.0.17", package="uu_uname", path="src/uu/uname" }
unexpand = { optional=true, version="0.0.16", package="uu_unexpand", path="src/uu/unexpand" } unexpand = { optional=true, version="0.0.17", package="uu_unexpand", path="src/uu/unexpand" }
uniq = { optional=true, version="0.0.16", package="uu_uniq", path="src/uu/uniq" } uniq = { optional=true, version="0.0.17", package="uu_uniq", path="src/uu/uniq" }
unlink = { optional=true, version="0.0.16", package="uu_unlink", path="src/uu/unlink" } unlink = { optional=true, version="0.0.17", package="uu_unlink", path="src/uu/unlink" }
uptime = { optional=true, version="0.0.16", package="uu_uptime", path="src/uu/uptime" } uptime = { optional=true, version="0.0.17", package="uu_uptime", path="src/uu/uptime" }
users = { optional=true, version="0.0.16", package="uu_users", path="src/uu/users" } users = { optional=true, version="0.0.17", package="uu_users", path="src/uu/users" }
vdir = { optional=true, version="0.0.16", package="uu_vdir", path="src/uu/vdir" } vdir = { optional=true, version="0.0.17", package="uu_vdir", path="src/uu/vdir" }
wc = { optional=true, version="0.0.16", package="uu_wc", path="src/uu/wc" } wc = { optional=true, version="0.0.17", package="uu_wc", path="src/uu/wc" }
who = { optional=true, version="0.0.16", package="uu_who", path="src/uu/who" } who = { optional=true, version="0.0.17", package="uu_who", path="src/uu/who" }
whoami = { optional=true, version="0.0.16", package="uu_whoami", path="src/uu/whoami" } whoami = { optional=true, version="0.0.17", package="uu_whoami", path="src/uu/whoami" }
yes = { optional=true, version="0.0.16", package="uu_yes", path="src/uu/yes" } 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)" # 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" } # 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" tempfile = "3"
time = {version="0.3", features=["local-offset"]} time = {version="0.3", features=["local-offset"]}
unindent = "0.1" 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" walkdir = "2.2"
atty = "0.2" atty = "0.2"
hex-literal = "0.3.1" hex-literal = "0.3.1"

View file

@ -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 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 `util-linux`. Features from more modern pagers (like `less` and `bat`) are
therefore welcomed. 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).

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_arch" name = "uu_arch"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "arch ~ (uutils) display machine architecture" description = "arch ~ (uutils) display machine architecture"
@ -15,9 +15,9 @@ edition = "2021"
path = "src/arch.rs" path = "src/arch.rs"
[dependencies] [dependencies]
platform-info = "1.0.1" platform-info = "1.0.2"
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "arch" name = "arch"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_base32" name = "uu_base32"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "base32 ~ (uutils) decode/encode input (base32-encoding)" description = "base32 ~ (uutils) decode/encode input (base32-encoding)"
@ -16,7 +16,7 @@ path = "src/base32.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "base32" name = "base32"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_base64" name = "uu_base64"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "base64 ~ (uutils) decode/encode input (base64-encoding)" description = "base64 ~ (uutils) decode/encode input (base64-encoding)"
@ -15,8 +15,8 @@ edition = "2021"
path = "src/base64.rs" path = "src/base64.rs"
[dependencies] [dependencies]
uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features = ["encoding"] } uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features = ["encoding"] }
uu_base32 = { version=">=0.0.16", package="uu_base32", path="../base32"} uu_base32 = { version=">=0.0.17", package="uu_base32", path="../base32"}
[[bin]] [[bin]]
name = "base64" name = "base64"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_basename" name = "uu_basename"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "basename ~ (uutils) display PATHNAME with leading directory components removed" description = "basename ~ (uutils) display PATHNAME with leading directory components removed"
@ -16,7 +16,7 @@ path = "src/basename.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "basename" name = "basename"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_basenc" name = "uu_basenc"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "basenc ~ (uutils) decode/encode input" description = "basenc ~ (uutils) decode/encode input"
@ -16,8 +16,8 @@ path = "src/basenc.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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"] }
uu_base32 = { version=">=0.0.16", package="uu_base32", path="../base32"} uu_base32 = { version=">=0.0.17", package="uu_base32", path="../base32"}
[[bin]] [[bin]]
name = "basenc" name = "basenc"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_cat" name = "uu_cat"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "cat ~ (uutils) concatenate and display input" description = "cat ~ (uutils) concatenate and display input"
@ -18,7 +18,7 @@ path = "src/cat.rs"
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
thiserror = "1.0" thiserror = "1.0"
atty = "0.2" 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] [target.'cfg(unix)'.dependencies]
nix = { version = "0.25", default-features = false } nix = { version = "0.25", default-features = false }

View file

@ -35,7 +35,6 @@ use std::os::unix::fs::FileTypeExt;
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use uucore::format_usage; use uucore::format_usage;
static NAME: &str = "cat";
static USAGE: &str = "{} [OPTION]... [FILE]..."; static USAGE: &str = "{} [OPTION]... [FILE]...";
static ABOUT: &str = "Concatenate FILE(s), or standard input, to standard output static ABOUT: &str = "Concatenate FILE(s), or standard input, to standard output
With no FILE, or when FILE is -, read standard input."; 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 { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.name(NAME)
.version(crate_version!()) .version(crate_version!())
.override_usage(format_usage(USAGE)) .override_usage(format_usage(USAGE))
.about(ABOUT) .about(ABOUT)
@ -426,7 +424,7 @@ fn get_input_type(path: &str) -> CatResult<InputType> {
ft if ft.is_file() => Ok(InputType::File), ft if ft.is_file() => Ok(InputType::File),
ft if ft.is_symlink() => Ok(InputType::SymLink), ft if ft.is_symlink() => Ok(InputType::SymLink),
_ => Err(CatError::UnknownFiletype { _ => Err(CatError::UnknownFiletype {
ft_debug: format!("{:?}", ft), ft_debug: format!("{ft:?}"),
}), }),
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chcon" name = "uu_chcon"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chcon ~ (uutils) change file security context" description = "chcon ~ (uutils) change file security context"

View file

@ -70,7 +70,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
return Err(r.into()); return Err(r.into());
} }
return Err(UUsageError::new(libc::EXIT_FAILURE, format!("{}.\n", r))); return Err(UUsageError::new(libc::EXIT_FAILURE, format!("{r}.\n")));
} }
}; };

View file

@ -67,10 +67,10 @@ impl Error {
pub(crate) fn report_full_error(mut err: &dyn std::error::Error) -> String { pub(crate) fn report_full_error(mut err: &dyn std::error::Error) -> String {
let mut desc = String::with_capacity(256); let mut desc = String::with_capacity(256);
write!(desc, "{}", err).unwrap(); write!(desc, "{err}").unwrap();
while let Some(source) = err.source() { while let Some(source) = err.source() {
err = source; err = source;
write!(desc, ". {}", err).unwrap(); write!(desc, ". {err}").unwrap();
} }
desc desc
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chgrp" name = "uu_chgrp"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chgrp ~ (uutils) change the group ownership of FILE" description = "chgrp ~ (uutils) change the group ownership of FILE"
@ -16,7 +16,7 @@ path = "src/chgrp.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "chgrp" name = "chgrp"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chmod" name = "uu_chmod"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chmod ~ (uutils) change mode of FILE" description = "chmod ~ (uutils) change mode of FILE"
@ -17,7 +17,7 @@ path = "src/chmod.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
libc = "0.2.137" 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]] [[bin]]
name = "chmod" name = "chmod"

View file

@ -75,7 +75,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let modes = matches.get_one::<String>(options::MODE).unwrap(); // should always be Some because required let modes = matches.get_one::<String>(options::MODE).unwrap(); // should always be Some because required
let cmode = if mode_had_minus_prefix { let cmode = if mode_had_minus_prefix {
// clap parsing is finished, now put prefix back // clap parsing is finished, now put prefix back
format!("-{}", modes) format!("-{modes}")
} else { } else {
modes.to_string() modes.to_string()
}; };

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chown" name = "uu_chown"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chown ~ (uutils) change the ownership of FILE" description = "chown ~ (uutils) change the ownership of FILE"
@ -16,7 +16,7 @@ path = "src/chown.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "chown" name = "chown"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chroot" name = "uu_chroot"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chroot ~ (uutils) run COMMAND under a new root directory" description = "chroot ~ (uutils) run COMMAND under a new root directory"
@ -16,7 +16,7 @@ path = "src/chroot.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "chroot" name = "chroot"

View file

@ -77,8 +77,8 @@ impl Display for ChrootError {
"cannot change root directory to {}: no such directory", "cannot change root directory to {}: no such directory",
s.quote(), s.quote(),
), ),
Self::SetGidFailed(s, e) => write!(f, "cannot set gid to {}: {}", s, e), Self::SetGidFailed(s, e) => write!(f, "cannot set gid to {s}: {e}"),
Self::SetGroupsFailed(e) => write!(f, "cannot set groups: {}", e), Self::SetGroupsFailed(e) => write!(f, "cannot set groups: {e}"),
Self::SetUserFailed(s, e) => { Self::SetUserFailed(s, e) => {
write!(f, "cannot set user to {}: {}", s.maybe_quote(), e) write!(f, "cannot set user to {}: {}", s.maybe_quote(), e)
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_cksum" name = "uu_cksum"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "cksum ~ (uutils) display CRC and size of input" description = "cksum ~ (uutils) display CRC and size of input"
@ -16,7 +16,7 @@ path = "src/cksum.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "cksum" name = "cksum"

View file

@ -18,7 +18,6 @@ use uucore::{format_usage, show};
const CRC_TABLE_LEN: usize = 256; const CRC_TABLE_LEN: usize = 256;
const CRC_TABLE: [u32; CRC_TABLE_LEN] = generate_crc_table(); const CRC_TABLE: [u32; CRC_TABLE_LEN] = generate_crc_table();
const NAME: &str = "cksum";
const USAGE: &str = "{} [OPTIONS] [FILE]..."; const USAGE: &str = "{} [OPTIONS] [FILE]...";
const ABOUT: &str = "Print CRC and size for each 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() { if files.is_empty() {
let (crc, size) = cksum("-")?; let (crc, size) = cksum("-")?;
println!("{} {}", crc, size); println!("{crc} {size}");
return Ok(()); return Ok(());
} }
for fname in &files { for fname in &files {
match cksum(fname.as_ref()).map_err_context(|| format!("{}", fname.maybe_quote())) { 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), Err(err) => show!(err),
}; };
} }
@ -139,7 +138,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.name(NAME)
.version(crate_version!()) .version(crate_version!())
.about(ABOUT) .about(ABOUT)
.override_usage(format_usage(USAGE)) .override_usage(format_usage(USAGE))

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_comm" name = "uu_comm"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "comm ~ (uutils) compare sorted inputs" description = "comm ~ (uutils) compare sorted inputs"
@ -16,7 +16,7 @@ path = "src/comm.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "comm" name = "comm"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_cp" name = "uu_cp"
version = "0.0.16" version = "0.0.17"
authors = [ authors = [
"Jordy Dickinson <jordy.dickinson@gmail.com>", "Jordy Dickinson <jordy.dickinson@gmail.com>",
"Joshua S. Miller <jsmiller@uchicago.edu>", "Joshua S. Miller <jsmiller@uchicago.edu>",
@ -24,7 +24,7 @@ filetime = "0.2"
libc = "0.2.137" libc = "0.2.137"
quick-error = "2.0.1" quick-error = "2.0.1"
selinux = { version="0.3", optional=true } 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" walkdir = "2.2"
indicatif = "0.17" indicatif = "0.17"

View file

@ -380,7 +380,7 @@ pub(crate) fn copy_directory(
// the target directory. // the target directory.
let context = match Context::new(root, target) { let context = match Context::new(root, target) {
Ok(c) => c, 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. // 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 the attributes from the root directory to the target directory.
copy_attributes(root, target, &options.preserve_attributes)?; copy_attributes(root, target, &options.attributes)?;
Ok(()) Ok(())
} }

View file

@ -24,7 +24,6 @@ use std::os::unix::ffi::OsStrExt;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::fs::{FileTypeExt, PermissionsExt}; use std::os::unix::fs::{FileTypeExt, PermissionsExt};
use std::path::{Path, PathBuf, StripPrefixError}; use std::path::{Path, PathBuf, StripPrefixError};
use std::str::FromStr;
use std::string::ToString; use std::string::ToString;
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
@ -33,6 +32,8 @@ use indicatif::{ProgressBar, ProgressStyle};
#[cfg(unix)] #[cfg(unix)]
use libc::mkfifo; use libc::mkfifo;
use quick_error::ResultExt; use quick_error::ResultExt;
use platform::copy_on_write;
use uucore::backup_control::{self, BackupMode}; use uucore::backup_control::{self, BackupMode};
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{set_exit_code, UClapError, UError, UResult, UUsageError}; 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}; use uucore::{crash, format_usage, prompt_yes, show_error, show_warning};
mod copydir;
use crate::copydir::copy_directory; use crate::copydir::copy_directory;
mod copydir;
mod platform; mod platform;
use platform::copy_on_write;
quick_error! { quick_error! {
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -157,18 +156,51 @@ pub enum CopyMode {
AttrOnly, AttrOnly,
} }
// The ordering here determines the order in which attributes are (re-)applied. #[derive(Debug)]
// In particular, Ownership must be changed first to avoid interfering with mode change. pub struct Attributes {
#[derive(Clone, Eq, PartialEq, Debug, PartialOrd, Ord)]
pub enum Attribute {
#[cfg(unix)] #[cfg(unix)]
Ownership, ownership: Preserve,
Mode, mode: Preserve,
Timestamps, timestamps: Preserve,
#[cfg(feature = "feat_selinux")] context: Preserve,
Context, links: Preserve,
Links, xattr: Preserve,
Xattr, }
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 /// Re-usable, extensible copy options
@ -187,7 +219,7 @@ pub struct Options {
sparse_mode: SparseMode, sparse_mode: SparseMode,
strip_trailing_slashes: bool, strip_trailing_slashes: bool,
reflink_mode: ReflinkMode, reflink_mode: ReflinkMode,
preserve_attributes: Vec<Attribute>, attributes: Attributes,
recursive: bool, recursive: bool,
backup_suffix: String, backup_suffix: String,
target_dir: Option<String>, target_dir: Option<String>,
@ -243,7 +275,6 @@ static PRESERVABLE_ATTRIBUTES: &[&str] = &[
"mode", "mode",
"ownership", "ownership",
"timestamps", "timestamps",
#[cfg(feature = "feat_selinux")]
"context", "context",
"links", "links",
"xattr", "xattr",
@ -254,13 +285,6 @@ static PRESERVABLE_ATTRIBUTES: &[&str] = &[
static PRESERVABLE_ATTRIBUTES: &[&str] = static PRESERVABLE_ATTRIBUTES: &[&str] =
&["mode", "timestamps", "context", "links", "xattr", "all"]; &["mode", "timestamps", "context", "links", "xattr", "all"];
static DEFAULT_ATTRIBUTES: &[Attribute] = &[
Attribute::Mode,
#[cfg(unix)]
Attribute::Ownership,
Attribute::Timestamps,
];
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
const MODE_ARGS: &[&str] = &[ const MODE_ARGS: &[&str] = &[
options::LINK, options::LINK,
@ -552,7 +576,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
clap::error::ErrorKind::DisplayHelp => { clap::error::ErrorKind::DisplayHelp => {
app.print_help()?; 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))), _ => return Err(Box::new(e.with_exit_code(1))),
}; };
} else if let Ok(matches) = matches { } else if let Ok(matches) = matches {
@ -627,46 +651,79 @@ impl CopyMode {
} }
} }
impl FromStr for Attribute { impl Attributes {
type Err = Error; // 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<Self> { fn all() -> Self {
Ok(match &*value.to_lowercase() { Self {
"mode" => Self::Mode,
#[cfg(unix)] #[cfg(unix)]
"ownership" => Self::Ownership, ownership: Preserve::Yes { required: true },
"timestamps" => Self::Timestamps, mode: Preserve::Yes { required: true },
#[cfg(feature = "feat_selinux")] timestamps: Preserve::Yes { required: true },
"context" => Self::Context, context: {
"links" => Self::Links, #[cfg(feature = "feat_selinux")]
"xattr" => Self::Xattr, {
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!( return Err(Error::InvalidArgument(format!(
"invalid attribute {}", "invalid attribute {}",
value.quote() value.quote()
))); )));
} }
}) };
Ok(())
} }
} }
fn add_all_attributes() -> Vec<Attribute> {
use Attribute::*;
let attr = vec![
#[cfg(unix)]
Ownership,
Mode,
Timestamps,
#[cfg(feature = "feat_selinux")]
Context,
Links,
Xattr,
];
attr
}
impl Options { impl Options {
fn from_matches(matches: &ArgMatches) -> CopyResult<Self> { fn from_matches(matches: &ArgMatches) -> CopyResult<Self> {
let not_implemented_opts = vec![ let not_implemented_opts = vec![
@ -689,7 +746,7 @@ impl Options {
let recursive = matches.get_flag(options::RECURSIVE) || matches.get_flag(options::ARCHIVE); let recursive = matches.get_flag(options::RECURSIVE) || matches.get_flag(options::ARCHIVE);
let backup_mode = match backup_control::determine_backup_mode(matches) { 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, Ok(mode) => mode,
}; };
@ -710,22 +767,23 @@ impl Options {
}; };
// Parse attributes to preserve // Parse attributes to preserve
let mut preserve_attributes: Vec<Attribute> = if matches.contains_id(options::PRESERVE) { let attributes: Attributes = if matches.contains_id(options::PRESERVE) {
match matches.get_many::<String>(options::PRESERVE) { match matches.get_many::<String>(options::PRESERVE) {
None => DEFAULT_ATTRIBUTES.to_vec(), None => Attributes::default(),
Some(attribute_strs) => { 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 { for attribute_str in attribute_strs {
attributes_empty = false;
if attribute_str == "all" { if attribute_str == "all" {
attributes = add_all_attributes(); attributes.max(Attributes::all());
break;
} else { } else {
attributes.push(Attribute::from_str(attribute_str)?); attributes.try_set_from_string(attribute_str)?;
} }
} }
// `--preserve` case, use the defaults // `--preserve` case, use the defaults
if attributes.is_empty() { if attributes_empty {
DEFAULT_ATTRIBUTES.to_vec() Attributes::default()
} else { } else {
attributes attributes
} }
@ -733,19 +791,27 @@ impl Options {
} }
} else if matches.get_flag(options::ARCHIVE) { } else if matches.get_flag(options::ARCHIVE) {
// --archive is used. Same as --preserve=all // --archive is used. Same as --preserve=all
add_all_attributes() Attributes::all()
} else if matches.get_flag(options::NO_DEREFERENCE_PRESERVE_LINKS) { } 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) { } else if matches.get_flag(options::PRESERVE_DEFAULT_ATTRIBUTES) {
DEFAULT_ATTRIBUTES.to_vec() Attributes::default()
} else { } else {
vec![] Attributes::none()
}; };
// Make sure ownership is changed before other attributes, #[cfg(not(feature = "feat_selinux"))]
// as chown clears some of the permission and therefore could undo previous changes if let Preserve::Yes { required } = attributes.context {
// if not executed first. let selinux_disabled_error =
preserve_attributes.sort_unstable(); 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 { let options = Self {
attributes_only: matches.get_flag(options::ATTRIBUTES_ONLY), attributes_only: matches.get_flag(options::ATTRIBUTES_ONLY),
@ -799,9 +865,8 @@ impl Options {
"never" => SparseMode::Never, "never" => SparseMode::Never,
_ => { _ => {
return Err(Error::InvalidArgument(format!( return Err(Error::InvalidArgument(format!(
"invalid argument {} for \'sparse\'", "invalid argument {val} for \'sparse\'"
val )));
)))
} }
} }
} else { } else {
@ -812,7 +877,7 @@ impl Options {
backup_suffix, backup_suffix,
overwrite, overwrite,
no_target_dir, no_target_dir,
preserve_attributes, attributes,
recursive, recursive,
target_dir, target_dir,
progress_bar: matches.get_flag(options::PROGRESS_BAR), progress_bar: matches.get_flag(options::PROGRESS_BAR),
@ -826,12 +891,10 @@ impl Options {
} }
fn preserve_hard_links(&self) -> bool { fn preserve_hard_links(&self) -> bool {
for attribute in &self.preserve_attributes { match self.attributes.links {
if *attribute == Attribute::Links { Preserve::No => false,
return true; Preserve::Yes { .. } => true,
}
} }
false
} }
/// Whether to force overwriting the destination file. /// Whether to force overwriting the destination file.
@ -951,6 +1014,22 @@ fn preserve_hardlinks(
Ok(found_hard_link) 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 /// Copy all `sources` to `target`. Returns an
/// `Err(Error::NotAllFilesCopied)` if at least one non-fatal error was /// `Err(Error::NotAllFilesCopied)` if at least one non-fatal error was
/// encountered. /// encountered.
@ -1005,15 +1084,8 @@ fn copy(sources: &[Source], target: &TargetSlice, options: &Options) -> CopyResu
options, options,
&mut symlinked_files, &mut symlinked_files,
) { ) {
match error { if show_error_if_needed(&error) {
// When using --no-clobber, we don't want to show non_fatal_errors = true;
// an error message
Error::NotAllFilesCopied => (),
Error::Skipped => (),
_ => {
show_error!("{}", 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<F: Fn() -> 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. /// Copy the specified attributes from one path to another.
pub(crate) fn copy_attributes( pub(crate) fn copy_attributes(
source: &Path, source: &Path,
dest: &Path, dest: &Path,
attributes: &[Attribute], attributes: &Attributes,
) -> CopyResult<()> { ) -> 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 context = &*format!("{} -> {}", source.quote(), dest.quote());
let source_metadata = fs::symlink_metadata(source).context(context)?; let source_metadata = fs::symlink_metadata(source).context(context)?;
match *attribute {
Attribute::Mode => { // Ownership must be changed first to avoid interfering with mode change.
// The `chmod()` system call that underlies the #[cfg(unix)]
// `fs::set_permissions()` call is unable to change the handle_preserve(&attributes.ownership, || -> CopyResult<()> {
// permissions of a symbolic link. In that case, we just use std::os::unix::prelude::MetadataExt;
// do nothing, since every symbolic link has the same use uucore::perms::wrap_chown;
// permissions. use uucore::perms::Verbosity;
if !dest.is_symlink() { use uucore::perms::VerbosityLevel;
fs::set_permissions(dest, source_metadata.permissions()).context(context)?;
// FIXME: Implement this for windows as well let dest_uid = source_metadata.uid();
#[cfg(feature = "feat_acl")] let dest_gid = source_metadata.gid();
exacl::getfacl(source, None)
.and_then(|acl| exacl::setfacl(&[dest], &acl, None)) wrap_chown(
.map_err(|err| Error::Error(err.to_string()))?; 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(); Ok(())
let dest_gid = source_metadata.gid(); })?;
wrap_chown( handle_preserve(&attributes.timestamps, || -> CopyResult<()> {
dest, let atime = FileTime::from_last_access_time(&source_metadata);
&dest.symlink_metadata().context(context)?, let mtime = FileTime::from_last_modification_time(&source_metadata);
Some(dest_uid), if dest.is_symlink() {
Some(dest_gid), filetime::set_symlink_file_times(dest, atime, mtime)?;
false, } else {
Verbosity { filetime::set_file_times(dest, atime, mtime)?;
groups_only: false, }
level: VerbosityLevel::Normal,
}, 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)?; })?;
} if let Some(context) = context {
Attribute::Timestamps => { context.set_for_path(dest, false, false).map_err(|e| {
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| {
format!( format!(
"failed to get security context of {}: {}", "failed to set security context for {}: {}",
source.display(), dest.display(),
e 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 => { Ok(())
#[cfg(unix)] })?;
{
let xattrs = xattr::list(source)?; handle_preserve(&attributes.xattr, || -> CopyResult<()> {
for attr in xattrs { #[cfg(unix)]
if let Some(attr_value) = xattr::get(source, attr.clone())? { {
xattr::set(dest, attr, &attr_value[..])?; 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(()) Ok(())
} }
@ -1580,7 +1676,8 @@ fn copy_file(
// the user does not have permission to write to the file. // the user does not have permission to write to the file.
fs::set_permissions(dest, dest_permissions).ok(); 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 { if let Some(progress_bar) = progress_bar {
progress_bar.inc(fs::metadata(source)?.len()); progress_bar.inc(fs::metadata(source)?.len());
@ -1759,7 +1856,7 @@ mod tests {
#[test] #[test]
fn test_aligned_ancestors() { 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![ let expected = vec![
(Path::new("a"), Path::new("d/a")), (Path::new("a"), Path::new("d/a")),
(Path::new("a/b"), Path::new("d/a/b")), (Path::new("a/b"), Path::new("d/a/b")),

View file

@ -69,9 +69,7 @@ pub(crate) fn copy_on_write(
// support COW). // support COW).
match reflink_mode { match reflink_mode {
ReflinkMode::Always => { ReflinkMode::Always => {
return Err( return Err(format!("failed to clone {source:?} from {dest:?}: {error}").into())
format!("failed to clone {:?} from {:?}: {}", source, dest, error).into(),
)
} }
_ => { _ => {
if source_is_fifo { if source_is_fifo {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_csplit" name = "uu_csplit"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" 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" 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"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
thiserror = "1.0" thiserror = "1.0"
regex = "1.7.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]] [[bin]]
name = "csplit" name = "csplit"

View file

@ -574,7 +574,7 @@ mod tests {
assert_eq!(input_splitter.add_line_to_buffer(0, line), None); assert_eq!(input_splitter.add_line_to_buffer(0, line), None);
assert_eq!(input_splitter.buffer_len(), 1); assert_eq!(input_splitter.buffer_len(), 1);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { 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.add_line_to_buffer(1, line), None);
assert_eq!(input_splitter.buffer_len(), 2); assert_eq!(input_splitter.buffer_len(), 2);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { match input_splitter.next() {
@ -595,7 +595,7 @@ mod tests {
); );
assert_eq!(input_splitter.buffer_len(), 2); assert_eq!(input_splitter.buffer_len(), 2);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
input_splitter.rewind_buffer(); input_splitter.rewind_buffer();
@ -605,7 +605,7 @@ mod tests {
assert_eq!(line, String::from("bbb")); assert_eq!(line, String::from("bbb"));
assert_eq!(input_splitter.buffer_len(), 1); assert_eq!(input_splitter.buffer_len(), 1);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { match input_splitter.next() {
@ -613,7 +613,7 @@ mod tests {
assert_eq!(line, String::from("ccc")); assert_eq!(line, String::from("ccc"));
assert_eq!(input_splitter.buffer_len(), 0); assert_eq!(input_splitter.buffer_len(), 0);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { match input_splitter.next() {
@ -621,7 +621,7 @@ mod tests {
assert_eq!(line, String::from("ddd")); assert_eq!(line, String::from("ddd"));
assert_eq!(input_splitter.buffer_len(), 0); assert_eq!(input_splitter.buffer_len(), 0);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
assert!(input_splitter.next().is_none()); 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.add_line_to_buffer(0, line), None);
assert_eq!(input_splitter.buffer_len(), 1); assert_eq!(input_splitter.buffer_len(), 1);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { 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.add_line_to_buffer(1, line), None);
assert_eq!(input_splitter.buffer_len(), 2); assert_eq!(input_splitter.buffer_len(), 2);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { 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.add_line_to_buffer(2, line), None);
assert_eq!(input_splitter.buffer_len(), 3); assert_eq!(input_splitter.buffer_len(), 3);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
input_splitter.rewind_buffer(); 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.add_line_to_buffer(0, line), None);
assert_eq!(input_splitter.buffer_len(), 3); assert_eq!(input_splitter.buffer_len(), 3);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { match input_splitter.next() {
@ -683,7 +683,7 @@ mod tests {
assert_eq!(line, String::from("aaa")); assert_eq!(line, String::from("aaa"));
assert_eq!(input_splitter.buffer_len(), 2); assert_eq!(input_splitter.buffer_len(), 2);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { match input_splitter.next() {
@ -691,7 +691,7 @@ mod tests {
assert_eq!(line, String::from("bbb")); assert_eq!(line, String::from("bbb"));
assert_eq!(input_splitter.buffer_len(), 1); assert_eq!(input_splitter.buffer_len(), 1);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { match input_splitter.next() {
@ -699,7 +699,7 @@ mod tests {
assert_eq!(line, String::from("ccc")); assert_eq!(line, String::from("ccc"));
assert_eq!(input_splitter.buffer_len(), 0); assert_eq!(input_splitter.buffer_len(), 0);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
match input_splitter.next() { match input_splitter.next() {
@ -707,7 +707,7 @@ mod tests {
assert_eq!(line, String::from("ddd")); assert_eq!(line, String::from("ddd"));
assert_eq!(input_splitter.buffer_len(), 0); assert_eq!(input_splitter.buffer_len(), 0);
} }
item => panic!("wrong item: {:?}", item), item => panic!("wrong item: {item:?}"),
}; };
assert!(input_splitter.next().is_none()); assert!(input_splitter.next().is_none());

View file

@ -224,35 +224,35 @@ mod tests {
assert_eq!(patterns.len(), 5); assert_eq!(patterns.len(), 5);
match patterns.get(0) { match patterns.get(0) {
Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(1))) => { Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test1.*end$"); assert_eq!(parsed_reg, "test1.*end$");
} }
_ => panic!("expected UpToMatch pattern"), _ => panic!("expected UpToMatch pattern"),
}; };
match patterns.get(1) { match patterns.get(1) {
Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Always)) => { Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Always)) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test2.*end$"); assert_eq!(parsed_reg, "test2.*end$");
} }
_ => panic!("expected UpToMatch pattern"), _ => panic!("expected UpToMatch pattern"),
}; };
match patterns.get(2) { match patterns.get(2) {
Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(5))) => { Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(5))) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test3.*end$"); assert_eq!(parsed_reg, "test3.*end$");
} }
_ => panic!("expected UpToMatch pattern"), _ => panic!("expected UpToMatch pattern"),
}; };
match patterns.get(3) { match patterns.get(3) {
Some(Pattern::UpToMatch(reg, 3, ExecutePattern::Times(1))) => { Some(Pattern::UpToMatch(reg, 3, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test4.*end$"); assert_eq!(parsed_reg, "test4.*end$");
} }
_ => panic!("expected UpToMatch pattern"), _ => panic!("expected UpToMatch pattern"),
}; };
match patterns.get(4) { match patterns.get(4) {
Some(Pattern::UpToMatch(reg, -3, ExecutePattern::Times(1))) => { Some(Pattern::UpToMatch(reg, -3, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test5.*end$"); assert_eq!(parsed_reg, "test5.*end$");
} }
_ => panic!("expected UpToMatch pattern"), _ => panic!("expected UpToMatch pattern"),
@ -277,35 +277,35 @@ mod tests {
assert_eq!(patterns.len(), 5); assert_eq!(patterns.len(), 5);
match patterns.get(0) { match patterns.get(0) {
Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(1))) => { Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test1.*end$"); assert_eq!(parsed_reg, "test1.*end$");
} }
_ => panic!("expected SkipToMatch pattern"), _ => panic!("expected SkipToMatch pattern"),
}; };
match patterns.get(1) { match patterns.get(1) {
Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Always)) => { Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Always)) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test2.*end$"); assert_eq!(parsed_reg, "test2.*end$");
} }
_ => panic!("expected SkipToMatch pattern"), _ => panic!("expected SkipToMatch pattern"),
}; };
match patterns.get(2) { match patterns.get(2) {
Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(5))) => { Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(5))) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test3.*end$"); assert_eq!(parsed_reg, "test3.*end$");
} }
_ => panic!("expected SkipToMatch pattern"), _ => panic!("expected SkipToMatch pattern"),
}; };
match patterns.get(3) { match patterns.get(3) {
Some(Pattern::SkipToMatch(reg, 3, ExecutePattern::Times(1))) => { Some(Pattern::SkipToMatch(reg, 3, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test4.*end$"); assert_eq!(parsed_reg, "test4.*end$");
} }
_ => panic!("expected SkipToMatch pattern"), _ => panic!("expected SkipToMatch pattern"),
}; };
match patterns.get(4) { match patterns.get(4) {
Some(Pattern::SkipToMatch(reg, -3, ExecutePattern::Times(1))) => { Some(Pattern::SkipToMatch(reg, -3, ExecutePattern::Times(1))) => {
let parsed_reg = format!("{}", reg); let parsed_reg = format!("{reg}");
assert_eq!(parsed_reg, "test5.*end$"); assert_eq!(parsed_reg, "test5.*end$");
} }
_ => panic!("expected SkipToMatch pattern"), _ => panic!("expected SkipToMatch pattern"),

View file

@ -42,9 +42,7 @@ impl SplitName {
.unwrap_or(2); .unwrap_or(2);
// translate the custom format into a function // translate the custom format into a function
let fn_split_name: Box<dyn Fn(usize) -> String> = match format_opt { let fn_split_name: Box<dyn Fn(usize) -> String> = match format_opt {
None => Box::new(move |n: usize| -> String { None => Box::new(move |n: usize| -> String { format!("{prefix}{n:0n_digits$}") }),
format!("{}{:0width$}", prefix, n, width = n_digits)
}),
Some(custom) => { Some(custom) => {
let spec = let spec =
Regex::new(r"(?P<ALL>%((?P<FLAG>[0#-])(?P<WIDTH>\d+)?)?(?P<TYPE>[diuoxX]))") Regex::new(r"(?P<ALL>%((?P<FLAG>[0#-])(?P<WIDTH>\d+)?)?(?P<TYPE>[diuoxX]))")
@ -55,23 +53,23 @@ impl SplitName {
let all = captures.name("ALL").unwrap(); let all = captures.name("ALL").unwrap();
let before = custom[0..all.start()].to_owned(); let before = custom[0..all.start()].to_owned();
let after = custom[all.end()..].to_owned(); let after = custom[all.end()..].to_owned();
let n_digits = match captures.name("WIDTH") { let width = match captures.name("WIDTH") {
None => 0, None => 0,
Some(m) => m.as_str().parse::<usize>().unwrap(), Some(m) => m.as_str().parse::<usize>().unwrap(),
}; };
match (captures.name("FLAG"), captures.name("TYPE")) { match (captures.name("FLAG"), captures.name("TYPE")) {
(None, Some(ref t)) => match t.as_str() { (None, Some(ref t)) => match t.as_str() {
"d" | "i" | "u" => Box::new(move |n: usize| -> String { "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 { "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 { "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 { "X" => Box::new(move |n: usize| -> String {
format!("{}{}{:X}{}", prefix, before, n, after) format!("{prefix}{before}{n:X}{after}")
}), }),
_ => return Err(CsplitError::SuffixFormatIncorrect), _ => return Err(CsplitError::SuffixFormatIncorrect),
}, },
@ -82,47 +80,19 @@ impl SplitName {
*/ */
// decimal // decimal
("0", "d" | "i" | "u") => Box::new(move |n: usize| -> String { ("0", "d" | "i" | "u") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:0width$}{after}")
"{}{}{:0width$}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
// octal // octal
("0", "o") => Box::new(move |n: usize| -> String { ("0", "o") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:0width$o}{after}")
"{}{}{:0width$o}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
// lower hexadecimal // lower hexadecimal
("0", "x") => Box::new(move |n: usize| -> String { ("0", "x") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:0width$x}{after}")
"{}{}{:0width$x}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
// upper hexadecimal // upper hexadecimal
("0", "X") => Box::new(move |n: usize| -> String { ("0", "X") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:0width$X}{after}")
"{}{}{:0width$X}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
/* /*
@ -130,36 +100,15 @@ impl SplitName {
*/ */
// octal // octal
("#", "o") => Box::new(move |n: usize| -> String { ("#", "o") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:>#width$o}{after}")
"{}{}{:>#width$o}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
// lower hexadecimal // lower hexadecimal
("#", "x") => Box::new(move |n: usize| -> String { ("#", "x") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:>#width$x}{after}")
"{}{}{:>#width$x}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
// upper hexadecimal // upper hexadecimal
("#", "X") => Box::new(move |n: usize| -> String { ("#", "X") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:>#width$X}{after}")
"{}{}{:>#width$X}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
/* /*
@ -167,47 +116,19 @@ impl SplitName {
*/ */
// decimal // decimal
("-", "d" | "i" | "u") => Box::new(move |n: usize| -> String { ("-", "d" | "i" | "u") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:<#width$}{after}")
"{}{}{:<#width$}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
// octal // octal
("-", "o") => Box::new(move |n: usize| -> String { ("-", "o") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:<#width$o}{after}")
"{}{}{:<#width$o}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
// lower hexadecimal // lower hexadecimal
("-", "x") => Box::new(move |n: usize| -> String { ("-", "x") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:<#width$x}{after}")
"{}{}{:<#width$x}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
// upper hexadecimal // upper hexadecimal
("-", "X") => Box::new(move |n: usize| -> String { ("-", "X") => Box::new(move |n: usize| -> String {
format!( format!("{prefix}{before}{n:<#width$X}{after}")
"{}{}{:<#width$X}{}",
prefix,
before,
n,
after,
width = n_digits
)
}), }),
_ => return Err(CsplitError::SuffixFormatIncorrect), _ => return Err(CsplitError::SuffixFormatIncorrect),

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_cut" name = "uu_cut"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "cut ~ (uutils) display byte/field columns of input lines" description = "cut ~ (uutils) display byte/field columns of input lines"
@ -16,7 +16,7 @@ path = "src/cut.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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" memchr = "2"
bstr = "1.0" bstr = "1.0"
atty = "0.2" atty = "0.2"

View file

@ -16,14 +16,15 @@ use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError}; use uucore::error::{FromIo, UResult, USimpleError};
use self::searcher::Searcher; use self::searcher::Searcher;
use matcher::{ExactMatcher, Matcher, WhitespaceMatcher};
use uucore::ranges::Range; use uucore::ranges::Range;
use uucore::{format_usage, show, show_error, show_if_err}; use uucore::{format_usage, show, show_error, show_if_err};
mod matcher;
mod searcher; mod searcher;
static NAME: &str = "cut";
static USAGE: &str = 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 = static ABOUT: &str =
"Prints specified byte or field columns from each line of stdin or the input files"; "Prints specified byte or field columns from each line of stdin or the input files";
static LONG_HELP: &str = " static LONG_HELP: &str = "
@ -85,6 +86,11 @@ static LONG_HELP: &str = "
--delimiter (-d) option. Setting the delimiter is optional. --delimiter (-d) option. Setting the delimiter is optional.
If not set, a default delimiter of Tab will be used. 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 Optionally Filter based on delimiter
If the --only-delimited (-s) flag is provided, only lines which If the --only-delimited (-s) flag is provided, only lines which
contain the delimiter will be printed contain the delimiter will be printed
@ -111,8 +117,13 @@ struct Options {
zero_terminated: bool, zero_terminated: bool,
} }
enum Delimiter {
Whitespace,
String(String), // FIXME: use char?
}
struct FieldOptions { struct FieldOptions {
delimiter: String, // one char long, String because of UTF8 representation delimiter: Delimiter,
out_delimiter: Option<String>, out_delimiter: Option<String>,
only_delimited: bool, only_delimited: bool,
zero_terminated: bool, zero_terminated: bool,
@ -177,23 +188,22 @@ fn cut_bytes<R: Read>(reader: R, ranges: &[Range], opts: &Options) -> UResult<()
Ok(()) Ok(())
} }
#[allow(clippy::cognitive_complexity)] // Output delimiter is explicitly specified
fn cut_fields_delimiter<R: Read>( fn cut_fields_explicit_out_delim<R: Read, M: Matcher>(
reader: R, reader: R,
matcher: &M,
ranges: &[Range], ranges: &[Range],
delim: &str,
only_delimited: bool, only_delimited: bool,
newline_char: u8, newline_char: u8,
out_delim: &str, out_delim: &str,
) -> UResult<()> { ) -> UResult<()> {
let mut buf_in = BufReader::new(reader); let mut buf_in = BufReader::new(reader);
let mut out = stdout_writer(); let mut out = stdout_writer();
let input_delim_len = delim.len();
let result = buf_in.for_byte_record_with_terminator(newline_char, |line| { let result = buf_in.for_byte_record_with_terminator(newline_char, |line| {
let mut fields_pos = 1; let mut fields_pos = 1;
let mut low_idx = 0; 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; let mut print_delim = false;
if delim_search.peek().is_none() { if delim_search.peek().is_none() {
@ -209,13 +219,17 @@ fn cut_fields_delimiter<R: Read>(
for &Range { low, high } in ranges { for &Range { low, high } in ranges {
if low - fields_pos > 0 { 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) { low_idx = match delim_search.nth(low - fields_pos - 1) {
Some(index) => index + input_delim_len, Some((_, last)) => last,
None => break, None => break,
}; };
} }
// at this point, current field is the first in the range
for _ in 0..=high - low { for _ in 0..=high - low {
// skip printing delimiter if this is the first matching field for this line
if print_delim { if print_delim {
out.write_all(out_delim.as_bytes())?; out.write_all(out_delim.as_bytes())?;
} else { } else {
@ -223,15 +237,17 @@ fn cut_fields_delimiter<R: Read>(
} }
match delim_search.next() { match delim_search.next() {
Some(high_idx) => { // print the current field up to the next field delim
let segment = &line[low_idx..high_idx]; Some((first, last)) => {
let segment = &line[low_idx..first];
out.write_all(segment)?; out.write_all(segment)?;
low_idx = high_idx + input_delim_len; low_idx = last;
fields_pos = high + 1; fields_pos = high + 1;
} }
None => { None => {
// this is the last field in the line, so print the rest
let segment = &line[low_idx..]; let segment = &line[low_idx..];
out.write_all(segment)?; out.write_all(segment)?;
@ -256,32 +272,25 @@ fn cut_fields_delimiter<R: Read>(
Ok(()) Ok(())
} }
#[allow(clippy::cognitive_complexity)] // Output delimiter is the same as input delimiter
fn cut_fields<R: Read>(reader: R, ranges: &[Range], opts: &FieldOptions) -> UResult<()> { fn cut_fields_implicit_out_delim<R: Read, M: Matcher>(
let newline_char = if opts.zero_terminated { b'\0' } else { b'\n' }; reader: R,
if let Some(ref o_delim) = opts.out_delimiter { matcher: &M,
return cut_fields_delimiter( ranges: &[Range],
reader, only_delimited: bool,
ranges, newline_char: u8,
&opts.delimiter, ) -> UResult<()> {
opts.only_delimited,
newline_char,
o_delim,
);
}
let mut buf_in = BufReader::new(reader); let mut buf_in = BufReader::new(reader);
let mut out = stdout_writer(); let mut out = stdout_writer();
let delim_len = opts.delimiter.len();
let result = buf_in.for_byte_record_with_terminator(newline_char, |line| { let result = buf_in.for_byte_record_with_terminator(newline_char, |line| {
let mut fields_pos = 1; let mut fields_pos = 1;
let mut low_idx = 0; 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; let mut print_delim = false;
if delim_search.peek().is_none() { if delim_search.peek().is_none() {
if !opts.only_delimited { if !only_delimited {
out.write_all(line)?; out.write_all(line)?;
if line[line.len() - 1] != newline_char { if line[line.len() - 1] != newline_char {
out.write_all(&[newline_char])?; out.write_all(&[newline_char])?;
@ -293,25 +302,21 @@ fn cut_fields<R: Read>(reader: R, ranges: &[Range], opts: &FieldOptions) -> URes
for &Range { low, high } in ranges { for &Range { low, high } in ranges {
if low - fields_pos > 0 { if low - fields_pos > 0 {
if let Some(delim_pos) = delim_search.nth(low - fields_pos - 1) { if let Some((first, last)) = delim_search.nth(low - fields_pos - 1) {
low_idx = if print_delim { low_idx = if print_delim { first } else { last }
delim_pos
} else {
delim_pos + delim_len
}
} else { } else {
break; break;
} }
} }
match delim_search.nth(high - low) { match delim_search.nth(high - low) {
Some(high_idx) => { Some((first, _)) => {
let segment = &line[low_idx..high_idx]; let segment = &line[low_idx..first];
out.write_all(segment)?; out.write_all(segment)?;
print_delim = true; print_delim = true;
low_idx = high_idx; low_idx = first;
fields_pos = high + 1; fields_pos = high + 1;
} }
None => { None => {
@ -337,6 +342,44 @@ fn cut_fields<R: Read>(reader: R, ranges: &[Range], opts: &FieldOptions) -> URes
Ok(()) Ok(())
} }
fn cut_fields<R: Read>(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<String>, mode: &Mode) { fn cut_files(mut filenames: Vec<String>, mode: &Mode) {
let mut stdin_read = false; let mut stdin_read = false;
@ -387,6 +430,7 @@ mod options {
pub const ZERO_TERMINATED: &str = "zero-terminated"; pub const ZERO_TERMINATED: &str = "zero-terminated";
pub const ONLY_DELIMITED: &str = "only-delimited"; pub const ONLY_DELIMITED: &str = "only-delimited";
pub const OUTPUT_DELIMITER: &str = "output-delimiter"; pub const OUTPUT_DELIMITER: &str = "output-delimiter";
pub const WHITESPACE_DELIMITED: &str = "whitespace-delimited";
pub const COMPLEMENT: &str = "complement"; pub const COMPLEMENT: &str = "complement";
pub const FILE: &str = "file"; 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 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); let zero_terminated = matches.get_flag(options::ZERO_TERMINATED);
match matches.get_one::<String>(options::DELIMITER).map(|s| s.as_str()) { match matches.get_one::<String>(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) => { Some(mut delim) => {
// GNU's `cut` supports `-d=` to set the delimiter to `=`. // GNU's `cut` supports `-d=` to set the delimiter to `=`.
// Clap parsing is limited in this situation, see: // Clap parsing is limited in this situation, see:
@ -474,7 +522,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
Ok(Mode::Fields( Ok(Mode::Fields(
ranges, ranges,
FieldOptions { FieldOptions {
delimiter: delim, delimiter: Delimiter::String(delim),
out_delimiter: out_delim, out_delimiter: out_delim,
only_delimited, only_delimited,
zero_terminated, zero_terminated,
@ -485,7 +533,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
None => Ok(Mode::Fields( None => Ok(Mode::Fields(
ranges, ranges,
FieldOptions { FieldOptions {
delimiter: "\t".to_owned(), delimiter: match whitespace_delimited {
true => Delimiter::Whitespace,
false => Delimiter::String("\t".to_owned()),
},
out_delimiter: out_delim, out_delimiter: out_delim,
only_delimited, only_delimited,
zero_terminated, 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()) 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(_, _) Mode::Bytes(_, _) | Mode::Characters(_, _)
if matches.get_flag(options::ONLY_DELIMITED) => if matches.get_flag(options::ONLY_DELIMITED) =>
{ {
@ -534,7 +590,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.name(NAME)
.version(crate_version!()) .version(crate_version!())
.override_usage(format_usage(USAGE)) .override_usage(format_usage(USAGE))
.about(ABOUT) .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.") .help("specify the delimiter character that separates fields in the input source. Defaults to Tab.")
.value_name("DELIM"), .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(
Arg::new(options::FIELDS) Arg::new(options::FIELDS)
.short('f') .short('f')

126
src/uu/cut/src/matcher.rs Normal file
View file

@ -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
}
}

View file

@ -5,82 +5,77 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // file that was distributed with this source code.
use memchr::memchr; // spell-checker:ignore multispace
pub struct Searcher<'a> { use super::matcher::Matcher;
haystack: &'a [u8],
needle: &'a [u8], // Generic searcher that relies on a specific matcher
pub struct Searcher<'a, 'b, M: Matcher> {
matcher: &'a M,
haystack: &'b [u8],
position: usize, position: usize,
} }
impl<'a> Searcher<'a> { impl<'a, 'b, M: Matcher> Searcher<'a, 'b, M> {
pub fn new(haystack: &'a [u8], needle: &'a [u8]) -> Searcher<'a> { pub fn new(matcher: &'a M, haystack: &'b [u8]) -> Self {
assert!(!needle.is_empty()); Self {
Searcher { matcher,
haystack, haystack,
needle,
position: 0, position: 0,
} }
} }
} }
impl<'a> Iterator for Searcher<'a> { // Iterate over field delimiters
type Item = usize; // 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<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { match self.matcher.next_match(&self.haystack[self.position..]) {
if let Some(match_idx) = memchr(self.needle[0], self.haystack) { Some((first, last)) => {
if self.needle.len() == 1 let result = (first + self.position, last + self.position);
|| self.haystack[match_idx + 1..].starts_with(&self.needle[1..]) self.position += last;
{ Some(result)
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;
} }
None => None,
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod exact_searcher_tests {
use super::super::matcher::ExactMatcher;
use super::*; use super::*;
const NEEDLE: &[u8] = "ab".as_bytes();
#[test] #[test]
fn test_normal() { fn test_normal() {
let iter = Searcher::new("a.a.a".as_bytes(), "a".as_bytes()); let matcher = ExactMatcher::new("a".as_bytes());
let items: Vec<usize> = iter.collect(); let iter = Searcher::new(&matcher, "a.a.a".as_bytes());
assert_eq!(vec![0, 2, 4], items); let items: Vec<(usize, usize)> = iter.collect();
assert_eq!(vec![(0, 1), (2, 3), (4, 5)], items);
} }
#[test] #[test]
fn test_empty() { fn test_empty() {
let iter = Searcher::new("".as_bytes(), "a".as_bytes()); let matcher = ExactMatcher::new("a".as_bytes());
let items: Vec<usize> = iter.collect(); let iter = Searcher::new(&matcher, "".as_bytes());
assert_eq!(vec![] as Vec<usize>, items); let items: Vec<(usize, usize)> = iter.collect();
assert_eq!(vec![] as Vec<(usize, usize)>, items);
} }
fn test_multibyte(line: &[u8], expected: &[usize]) { fn test_multibyte(line: &[u8], expected: &[(usize, usize)]) {
let iter = Searcher::new(line, NEEDLE); let matcher = ExactMatcher::new("ab".as_bytes());
let items: Vec<usize> = iter.collect(); let iter = Searcher::new(&matcher, line);
let items: Vec<(usize, usize)> = iter.collect();
assert_eq!(expected, items); assert_eq!(expected, items);
} }
#[test] #[test]
fn test_multibyte_normal() { fn test_multibyte_normal() {
test_multibyte("...ab...ab...".as_bytes(), &[3, 8]); test_multibyte("...ab...ab...".as_bytes(), &[(3, 5), (8, 10)]);
} }
#[test] #[test]
@ -90,16 +85,101 @@ mod tests {
#[test] #[test]
fn test_multibyte_starting_needle() { fn test_multibyte_starting_needle() {
test_multibyte("ab...ab...".as_bytes(), &[0, 5]); test_multibyte("ab...ab...".as_bytes(), &[(0, 2), (5, 7)]);
} }
#[test] #[test]
fn test_multibyte_trailing_needle() { fn test_multibyte_trailing_needle() {
test_multibyte("...ab...ab".as_bytes(), &[3, 8]); test_multibyte("...ab...ab".as_bytes(), &[(3, 5), (8, 10)]);
} }
#[test] #[test]
fn test_multibyte_first_byte_false_match() { 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);
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_date" name = "uu_date"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "date ~ (uutils) display or set the current time" description = "date ~ (uutils) display or set the current time"
@ -17,7 +17,7 @@ path = "src/date.rs"
[dependencies] [dependencies]
chrono = { version="^0.4.23", default-features=false, features=["std", "alloc", "clock"]} chrono = { version="^0.4.23", default-features=false, features=["std", "alloc", "clock"]}
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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] [target.'cfg(unix)'.dependencies]
libc = "0.2" libc = "0.2"

View file

@ -117,7 +117,7 @@ impl<'a> From<&'a str> for Iso8601Format {
NS => Self::Ns, NS => Self::Ns,
DATE => Self::Date, DATE => Self::Date,
// Should be caught by clap // 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, SECONDS | SECOND => Self::Seconds,
NS => Self::Ns, NS => Self::Ns,
// Should be caught by clap // 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) .format_with_items(format_items)
.to_string() .to_string()
.replace("%f", "%N"); .replace("%f", "%N");
println!("{}", formatted); println!("{formatted}");
} }
Err((input, _err)) => show_error!("invalid date {}", input.quote()), Err((input, _err)) => show_error!("invalid date {}", input.quote()),
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_dd" name = "uu_dd"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "dd ~ (uutils) copy and convert files" description = "dd ~ (uutils) copy and convert files"
@ -18,7 +18,7 @@ path = "src/dd.rs"
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
gcd = "2.0" gcd = "2.0"
libc = "0.2" 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] [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
signal-hook = "0.3.14" signal-hook = "0.3.14"

View file

@ -491,8 +491,8 @@ impl<'a> Output<'a> {
// These objects are counters, initialized to zero. After each // These objects are counters, initialized to zero. After each
// iteration of the main loop, each will be incremented by the // iteration of the main loop, each will be incremented by the
// number of blocks read and written, respectively. // number of blocks read and written, respectively.
let mut rstat = Default::default(); let mut rstat = ReadStat::default();
let mut wstat = Default::default(); let mut wstat = WriteStat::default();
// The time at which the main loop starts executing. // 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); let p = Path::new(&s);
match File::open(p) { match File::open(p) {
Ok(mut f) => { Ok(mut f) => {
f.seek(SeekFrom::Current(0)).is_ok() f.stream_position().is_ok() && f.seek(SeekFrom::End(0)).is_ok() && f.rewind().is_ok()
&& f.seek(SeekFrom::End(0)).is_ok()
&& f.seek(SeekFrom::Start(0)).is_ok()
} }
Err(_) => false, Err(_) => false,
} }

View file

@ -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); let quotient = (n as f64) / (base as f64);
if quotient < 10.0 { if quotient < 10.0 {
format!("{:.1} {}", quotient, suffix) format!("{quotient:.1} {suffix}")
} else { } else {
format!("{} {}", quotient.round(), suffix) format!("{} {}", quotient.round(), suffix)
} }

View file

@ -394,7 +394,7 @@ impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::UnrecognizedOperand(arg) => { Self::UnrecognizedOperand(arg) => {
write!(f, "Unrecognized operand '{}'", arg) write!(f, "Unrecognized operand '{arg}'")
} }
Self::MultipleFmtTable => { Self::MultipleFmtTable => {
write!( write!(
@ -415,37 +415,37 @@ impl std::fmt::Display for ParseError {
// Additional message about 'dd --help' is displayed only in this situation. // Additional message about 'dd --help' is displayed only in this situation.
write!( write!(
f, f,
"invalid input flag: {}\nTry 'dd --help' for more information.", "invalid input flag: {}\nTry '{} --help' for more information.",
arg arg,
uucore::execution_phrase()
) )
} }
Self::ConvFlagNoMatch(arg) => { Self::ConvFlagNoMatch(arg) => {
write!(f, "Unrecognized conv=CONV -> {}", arg) write!(f, "Unrecognized conv=CONV -> {arg}")
} }
Self::MultiplierStringParseFailure(arg) => { Self::MultiplierStringParseFailure(arg) => {
write!(f, "Unrecognized byte multiplier -> {}", arg) write!(f, "Unrecognized byte multiplier -> {arg}")
} }
Self::MultiplierStringOverflow(arg) => { Self::MultiplierStringOverflow(arg) => {
write!( write!(
f, f,
"Multiplier string would overflow on current system -> {}", "Multiplier string would overflow on current system -> {arg}"
arg
) )
} }
Self::BlockUnblockWithoutCBS => { Self::BlockUnblockWithoutCBS => {
write!(f, "conv=block or conv=unblock specified without cbs=N") write!(f, "conv=block or conv=unblock specified without cbs=N")
} }
Self::StatusLevelNotRecognized(arg) => { Self::StatusLevelNotRecognized(arg) => {
write!(f, "status=LEVEL not recognized -> {}", arg) write!(f, "status=LEVEL not recognized -> {arg}")
} }
Self::BsOutOfRange(arg) => { Self::BsOutOfRange(arg) => {
write!(f, "{}=N cannot fit into memory", arg) write!(f, "{arg}=N cannot fit into memory")
} }
Self::Unimplemented(arg) => { Self::Unimplemented(arg) => {
write!(f, "feature not implemented on this system -> {}", arg) write!(f, "feature not implemented on this system -> {arg}")
} }
Self::InvalidNumber(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<u64, ParseError> {
fn parse_bytes_no_x(full: &str, s: &str) -> Result<u64, ParseError> { fn parse_bytes_no_x(full: &str, s: &str) -> Result<u64, ParseError> {
let parser = SizeParser { let parser = SizeParser {
capital_b_bytes: true, capital_b_bytes: true,
..Default::default()
}; };
let (num, multiplier) = match (s.find('c'), s.rfind('w'), s.rfind('b')) { let (num, multiplier) = match (s.find('c'), s.rfind('w'), s.rfind('b')) {
(None, None, None) => match parser.parse(s) { (None, None, None) => match parser.parse(s) {

View file

@ -56,29 +56,28 @@ fn unimplemented_flags_should_error() {
// The following flags are not implemented // The following flags are not implemented
for flag in ["cio", "nocache", "nolinks", "text", "binary"] { for flag in ["cio", "nocache", "nolinks", "text", "binary"] {
let args = vec![format!("iflag={}", flag)]; let args = vec![format!("iflag={flag}")];
if Parser::new() if Parser::new()
.parse(&args.iter().map(AsRef::as_ref).collect::<Vec<_>>()[..]) .parse(&args.iter().map(AsRef::as_ref).collect::<Vec<_>>()[..])
.is_ok() .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() if Parser::new()
.parse(&args.iter().map(AsRef::as_ref).collect::<Vec<_>>()[..]) .parse(&args.iter().map(AsRef::as_ref).collect::<Vec<_>>()[..])
.is_ok() .is_ok()
{ {
succeeded.push(format!("iflag={}", flag)); succeeded.push(format!("iflag={flag}"));
} }
} }
assert!( assert!(
succeeded.is_empty(), succeeded.is_empty(),
"The following flags did not panic as expected: {:?}", "The following flags did not panic as expected: {succeeded:?}"
succeeded
); );
} }

View file

@ -100,7 +100,7 @@ impl ProgUpdate {
match self.read_stat.records_truncated { match self.read_stat.records_truncated {
0 => {} 0 => {}
1 => writeln!(w, "1 truncated record")?, 1 => writeln!(w, "1 truncated record")?,
n => writeln!(w, "{} truncated records", n)?, n => writeln!(w, "{n} truncated records")?,
} }
Ok(()) Ok(())
} }
@ -154,29 +154,19 @@ impl ProgUpdate {
match btotal { match btotal {
1 => write!( 1 => write!(
w, w,
"{}{} byte copied, {:.1} s, {}/s{}", "{carriage_return}{btotal} byte copied, {duration:.1} s, {transfer_rate}/s{newline}",
carriage_return, btotal, duration, transfer_rate, newline,
), ),
0..=999 => write!( 0..=999 => write!(
w, w,
"{}{} bytes copied, {:.1} s, {}/s{}", "{carriage_return}{btotal} bytes copied, {duration:.1} s, {transfer_rate}/s{newline}",
carriage_return, btotal, duration, transfer_rate, newline,
), ),
1000..=1023 => write!( 1000..=1023 => write!(
w, w,
"{}{} bytes ({}) copied, {:.1} s, {}/s{}", "{carriage_return}{btotal} bytes ({btotal_metric}) copied, {duration:.1} s, {transfer_rate}/s{newline}",
carriage_return, btotal, btotal_metric, duration, transfer_rate, newline,
), ),
_ => write!( _ => write!(
w, w,
"{}{} bytes ({}, {}) copied, {:.1} s, {}/s{}", "{carriage_return}{btotal} bytes ({btotal_metric}, {btotal_bin}) copied, {duration:.1} s, {transfer_rate}/s{newline}",
carriage_return,
btotal,
btotal_metric,
btotal_bin,
duration,
transfer_rate,
newline,
), ),
} }
} }
@ -455,10 +445,7 @@ pub(crate) fn gen_prog_updater(
register_linux_signal_handler(sigval.clone()).unwrap_or_else(|e| { register_linux_signal_handler(sigval.clone()).unwrap_or_else(|e| {
if Some(StatusLevel::None) != print_level { if Some(StatusLevel::None) != print_level {
eprintln!( eprintln!("Internal dd Warning: Unable to register signal handler \n\t{e}");
"Internal dd Warning: Unable to register signal handler \n\t{}",
e
);
} }
}); });

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_df" name = "uu_df"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "df ~ (uutils) display file system information" description = "df ~ (uutils) display file system information"
@ -16,7 +16,7 @@ path = "src/df.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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" unicode-width = "0.1.9"
[[bin]] [[bin]]

View file

@ -91,12 +91,12 @@ pub(crate) fn to_magnitude_and_suffix(n: u128, suffix_type: SuffixType) -> Strin
let suffix = suffixes[i]; let suffix = suffixes[i];
if rem == 0 { if rem == 0 {
format!("{}{}", quot, suffix) format!("{quot}{suffix}")
} else { } else {
let tenths_place = rem / (bases[i] / 10); let tenths_place = rem / (bases[i] / 10);
if rem % (bases[i] / 10) == 0 { if rem % (bases[i] / 10) == 0 {
format!("{}.{}{}", quot, tenths_place, suffix) format!("{quot}.{tenths_place}{suffix}")
} else if tenths_place + 1 == 10 || quot >= 10 { } else if tenths_place + 1 == 10 || quot >= 10 {
format!("{}{}", quot + 1, suffix) format!("{}{}", quot + 1, suffix)
} else { } else {
@ -205,7 +205,7 @@ impl fmt::Display for BlockSize {
to_magnitude_and_suffix(*n as u128, SuffixType::Si) to_magnitude_and_suffix(*n as u128, SuffixType::Si)
}; };
write!(f, "{}", s) write!(f, "{s}")
} }
} }
} }

View file

@ -105,11 +105,11 @@ impl Default for Options {
Self { Self {
show_local_fs: Default::default(), show_local_fs: Default::default(),
show_all_fs: Default::default(), show_all_fs: Default::default(),
block_size: Default::default(), block_size: BlockSize::default(),
human_readable: Default::default(), human_readable: Option::default(),
header_mode: Default::default(), header_mode: HeaderMode::default(),
include: Default::default(), include: Option::default(),
exclude: Default::default(), exclude: Option::default(),
sync: Default::default(), sync: Default::default(),
show_total: Default::default(), show_total: Default::default(),
columns: vec![ columns: vec![
@ -146,10 +146,10 @@ impl fmt::Display for OptionsError {
} }
// TODO This needs to vary based on whether `--block-size` // TODO This needs to vary based on whether `--block-size`
// or `-B` were provided. // 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` // TODO This needs to vary based on whether `--block-size`
// or `-B` were provided. // 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!( Self::ColumnError(ColumnError::MultipleColumns(s)) => write!(
f, f,
"option --output: field {} used more than once", "option --output: field {} used more than once",

View file

@ -438,7 +438,7 @@ impl fmt::Display for Table {
Alignment::Left => { Alignment::Left => {
if is_last_col { if is_last_col {
// no trailing spaces in last column // no trailing spaces in last column
write!(f, "{}", elem)?; write!(f, "{elem}")?;
} else { } else {
write!(f, "{:<width$}", elem, width = self.widths[i])?; write!(f, "{:<width$}", elem, width = self.widths[i])?;
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_dir" name = "uu_dir"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "shortcut to ls -C -b" description = "shortcut to ls -C -b"
@ -16,8 +16,8 @@ path = "src/dir.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo", "env"] } clap = { version = "4.0", features = ["wrap_help", "cargo", "env"] }
uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["entries", "fs"] } uucore = { version=">=0.0.17", package="uucore", path="../../uucore", features=["entries", "fs"] }
uu_ls = { version = ">=0.0.16", path="../ls"} uu_ls = { version = ">=0.0.17", path="../ls"}
[[bin]] [[bin]]
name = "dir" name = "dir"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_dircolors" name = "uu_dircolors"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "dircolors ~ (uutils) display commands to set LS_COLORS" description = "dircolors ~ (uutils) display commands to set LS_COLORS"
@ -16,7 +16,7 @@ path = "src/dircolors.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "dircolors" name = "dircolors"

View file

@ -103,7 +103,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
), ),
)); ));
} }
println!("{}", INTERNAL_DB); println!("{INTERNAL_DB}");
return Ok(()); return Ok(());
} }
@ -157,7 +157,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
match result { match result {
Ok(s) => { Ok(s) => {
println!("{}", s); println!("{s}");
Ok(()) Ok(())
} }
Err(s) => { Err(s) => {
@ -368,23 +368,23 @@ where
if state != ParseState::Pass { if state != ParseState::Pass {
if key.starts_with('.') { if key.starts_with('.') {
if *fmt == OutputFmt::Display { 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 { } else {
result.push_str(format!("*{}={}:", key, val).as_str()); result.push_str(format!("*{key}={val}:").as_str());
} }
} else if key.starts_with('*') { } else if key.starts_with('*') {
if *fmt == OutputFmt::Display { 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 { } 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" { } else if lower == "options" || lower == "color" || lower == "eightbit" {
// Slackware only. Ignore // Slackware only. Ignore
} else if let Some(s) = table.get(lower.as_str()) { } else if let Some(s) = table.get(lower.as_str()) {
if *fmt == OutputFmt::Display { 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 { } else {
result.push_str(format!("{}={}:", s, val).as_str()); result.push_str(format!("{s}={val}:").as_str());
} }
} else { } else {
return Err(format!( return Err(format!(

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_dirname" name = "uu_dirname"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "dirname ~ (uutils) display parent directory of PATHNAME" description = "dirname ~ (uutils) display parent directory of PATHNAME"
@ -16,7 +16,7 @@ path = "src/dirname.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "dirname" name = "dirname"

View file

@ -63,7 +63,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} }
} }
} }
print!("{}", separator); print!("{separator}");
} }
} else { } else {
return Err(UUsageError::new(1, "missing operand")); return Err(UUsageError::new(1, "missing operand"));

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_du" name = "uu_du"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "du ~ (uutils) display disk usage" 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 # For the --exclude & --exclude-from options
glob = "0.3.0" glob = "0.3.0"
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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] [target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Storage_FileSystem", "Win32_Foundation"] } windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Storage_FileSystem", "Win32_Foundation"] }

View file

@ -389,7 +389,7 @@ fn convert_size_human(size: u64, multiplier: u64, _block_size: u64) -> String {
if size == 0 { if size == 0 {
return "0".to_string(); return "0".to_string();
} }
format!("{}B", size) format!("{size}B")
} }
fn convert_size_b(size: u64, _multiplier: u64, _block_size: u64) -> String { 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.", 'birth' and 'creation' arguments are not supported on this platform.",
s.quote() 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(); let time_str = tm.format(time_format_str).to_string();
print!("{}\t{}\t", convert_size(size), time_str); print!("{}\t{}\t", convert_size(size), time_str);
print_verbatim(stat.path).unwrap(); print_verbatim(stat.path).unwrap();
print!("{}", line_separator); print!("{line_separator}");
} }
} else if !summarize || index == len - 1 { } else if !summarize || index == len - 1 {
print!("{}\t", convert_size(size)); print!("{}\t", convert_size(size));
print_verbatim(stat.path).unwrap(); print_verbatim(stat.path).unwrap();
print!("{}", line_separator); print!("{line_separator}");
} }
if options.total && index == (len - 1) { if options.total && index == (len - 1) {
// The last element will be the total size of the the path under // 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 { if options.total {
print!("{}\ttotal", convert_size(grand_total)); print!("{}\ttotal", convert_size(grand_total));
print!("{}", line_separator); print!("{line_separator}");
} }
Ok(()) Ok(())

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_echo" name = "uu_echo"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "echo ~ (uutils) display TEXT" description = "echo ~ (uutils) display TEXT"
@ -16,7 +16,7 @@ path = "src/echo.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "echo" name = "echo"

View file

@ -13,7 +13,6 @@ use std::str::Chars;
use uucore::error::{FromIo, UResult}; use uucore::error::{FromIo, UResult};
use uucore::format_usage; use uucore::format_usage;
const NAME: &str = "echo";
const ABOUT: &str = "display a line of text"; const ABOUT: &str = "display a line of text";
const USAGE: &str = "{} [OPTIONS]... [STRING]..."; const USAGE: &str = "{} [OPTIONS]... [STRING]...";
const AFTER_HELP: &str = r#" const AFTER_HELP: &str = r#"
@ -104,7 +103,7 @@ fn print_escaped(input: &str, mut output: impl Write) -> io::Result<bool> {
// because printing char slices is apparently not available in the standard library // because printing char slices is apparently not available in the standard library
for ch in &buffer[start..] { 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 { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.name(NAME)
// TrailingVarArg specifies the final positional argument is a VarArg // TrailingVarArg specifies the final positional argument is a VarArg
// and it doesn't attempts the parse any further args. // and it doesn't attempts the parse any further args.
// Final argument must have multiple(true) or the usage string equivalent. // 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; break;
} }
} else { } else {
write!(output, "{}", input)?; write!(output, "{input}")?;
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_env" name = "uu_env"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND" description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND"
@ -17,7 +17,7 @@ path = "src/env.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
rust-ini = "0.18.0" 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] [target.'cfg(unix)'.dependencies]
nix = { version = "0.25", default-features = false, features = ["signal"] } nix = { version = "0.25", default-features = false, features = ["signal"] }

View file

@ -210,7 +210,7 @@ fn run_env(args: impl uucore::Args) -> UResult<()> {
Err(error) => { Err(error) => {
return Err(USimpleError::new( return Err(USimpleError::new(
125, 125,
format!("cannot change directory to \"{}\": {}", d, error), format!("cannot change directory to \"{d}\": {error}"),
)); ));
} }
}; };

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_expand" name = "uu_expand"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "expand ~ (uutils) convert input tabs to spaces" description = "expand ~ (uutils) convert input tabs to spaces"
@ -17,7 +17,7 @@ path = "src/expand.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
unicode-width = "0.1.5" unicode-width = "0.1.5"
uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } uucore = { version=">=0.0.17", package="uucore", path="../../uucore" }
[[bin]] [[bin]]
name = "expand" name = "expand"

View file

@ -255,7 +255,7 @@ fn expand_shortcuts(args: &[String]) -> Vec<String> {
arg[1..] arg[1..]
.split(',') .split(',')
.filter(|s| !s.is_empty()) .filter(|s| !s.is_empty())
.for_each(|s| processed_args.push(format!("--tabs={}", s))); .for_each(|s| processed_args.push(format!("--tabs={s}")));
} else { } else {
processed_args.push(arg.to_string()); processed_args.push(arg.to_string());
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_expr" name = "uu_expr"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "expr ~ (uutils) display the value of EXPRESSION" 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-bigint = "0.4.0"
num-traits = "0.2.15" num-traits = "0.2.15"
onig = { version = "~6.4", default-features = false } 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]] [[bin]]
name = "expr" name = "expr"

View file

@ -73,8 +73,8 @@ fn process_expr(token_strings: &[&str]) -> Result<String, String> {
} }
fn print_expr_ok(expr_result: &str) -> UResult<()> { fn print_expr_ok(expr_result: &str) -> UResult<()> {
println!("{}", expr_result); println!("{expr_result}");
if expr_result == "0" || expr_result.is_empty() { if expr_result.parse::<i32>() == Ok(0) || expr_result.is_empty() {
Err(1.into()) Err(1.into())
} else { } else {
Ok(()) Ok(())

View file

@ -151,7 +151,7 @@ impl AstNode {
"index" => Ok(prefix_operator_index(&operand_values)), "index" => Ok(prefix_operator_index(&operand_values)),
"substr" => Ok(prefix_operator_substr(&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<Box<AstNode>, String>) {
println!("EXPR_DEBUG_AST"); println!("EXPR_DEBUG_AST");
match result { match result {
Ok(ast) => ast.debug_dump(), 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" { if debug_var == "1" {
println!("EXPR_DEBUG_RPN"); println!("EXPR_DEBUG_RPN");
for token in rpn { for token in rpn {
println!("\t{:?}", token); println!("\t{token:?}");
} }
} }
} }
@ -238,7 +238,7 @@ fn ast_from_rpn(rpn: &mut TokenStack) -> Result<Box<AstNode>, String> {
} }
Some((token_idx, unexpected_token)) => { 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(()), None => return Ok(()),
Some((token_idx, Token::ParOpen)) => { Some((token_idx, Token::ParOpen)) => {
return Err(format!( return Err(format!(
"syntax error (Mismatched open-parenthesis at #{})", "syntax error (Mismatched open-parenthesis at #{token_idx})"
token_idx
)) ))
} }
Some((token_idx, Token::ParClose)) => { Some((token_idx, Token::ParClose)) => {
return Err(format!( return Err(format!(
"syntax error (Mismatched close-parenthesis at #{})", "syntax error (Mismatched close-parenthesis at #{token_idx})"
token_idx
)) ))
} }
Some(other) => out_stack.push(other), 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 let Ok(debug_var) = env::var("EXPR_DEBUG_SYA_STEP") {
if debug_var == "1" { if debug_var == "1" {
println!("EXPR_DEBUG_SYA_STEP"); println!("EXPR_DEBUG_SYA_STEP");
println!("\t{} => {:?}", token_idx, token); println!("\t{token_idx} => {token:?}");
println!("\t\tout: {:?}", out_stack); println!("\t\tout: {out_stack:?}");
println!("\t\top : {:?}", op_stack); println!("\t\top : {op_stack:?}");
println!("\t\tresult: {:?}", result); 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 (current_idx, ch_h) in haystack.chars().enumerate() {
for ch_n in needles.chars() { for ch_n in needles.chars() {
if ch_n == ch_h { if ch_n == ch_h {
return current_idx.to_string(); return (current_idx + 1).to_string();
} }
} }
} }

View file

@ -122,7 +122,7 @@ fn maybe_dump_tokens_acc(tokens_acc: &[(usize, Token)]) {
if debug_var == "1" { if debug_var == "1" {
println!("EXPR_DEBUG_TOKENS"); println!("EXPR_DEBUG_TOKENS");
for token in tokens_acc { for token in tokens_acc {
println!("\t{:?}", token); println!("\t{token:?}");
} }
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_factor" name = "uu_factor"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "factor ~ (uutils) display the prime factors of each NUMBER" 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" num-traits = "0.2.15" # Needs at least version 0.2.15 for "OverflowingAdd"
rand = { version = "0.8", features = ["small_rng"] } rand = { version = "0.8", features = ["small_rng"] }
smallvec = { version = "1.10", features = ["union"] } 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] [dev-dependencies]
paste = "1.0.6" paste = "1.0.6"

View file

@ -46,7 +46,7 @@ fn main() {
.and_then(|s| s.parse::<usize>().ok()) .and_then(|s| s.parse::<usize>().ok())
.unwrap_or(DEFAULT_SIZE); .unwrap_or(DEFAULT_SIZE);
write!(file, "{}", PREAMBLE).unwrap(); write!(file, "{PREAMBLE}").unwrap();
let mut cols = 3; let mut cols = 3;
// we want a total of n + 1 values // we want a total of n + 1 values
@ -60,10 +60,10 @@ fn main() {
// format the table // format the table
let output = format!("({}, {}, {}),", x, modular_inverse(x), std::u64::MAX / x); let output = format!("({}, {}, {}),", x, modular_inverse(x), std::u64::MAX / x);
if cols + output.len() > MAX_WIDTH { if cols + output.len() > MAX_WIDTH {
write!(file, "\n {}", output).unwrap(); write!(file, "\n {output}").unwrap();
cols = 4 + output.len(); cols = 4 + output.len();
} else { } else {
write!(file, " {}", output).unwrap(); write!(file, " {output}").unwrap();
cols += 1 + output.len(); cols += 1 + output.len();
} }
@ -72,8 +72,7 @@ fn main() {
write!( write!(
file, file,
"\n];\n\n#[allow(dead_code)]\npub const NEXT_PRIME: u64 = {};\n", "\n];\n\n#[allow(dead_code)]\npub const NEXT_PRIME: u64 = {x};\n"
x
) )
.unwrap(); .unwrap();
} }

View file

@ -99,7 +99,7 @@ impl fmt::Display for Factors {
for (p, exp) in v.iter() { for (p, exp) in v.iter() {
for _ in 0..*exp { for _ in 0..*exp {
write!(f, " {}", p)?; write!(f, " {p}")?;
} }
} }

View file

@ -153,8 +153,7 @@ mod tests {
for p in odd_primes() { for p in odd_primes() {
assert!( assert!(
test(Montgomery::<A>::new(p)).is_prime(), test(Montgomery::<A>::new(p)).is_prime(),
"{} reported composite", "{p} reported composite"
p
); );
} }
} }
@ -173,7 +172,7 @@ mod tests {
fn first_composites() { fn first_composites() {
for (p, q) in primes().zip(odd_primes()) { for (p, q) in primes().zip(odd_primes()) {
for i in p + 1..q { 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) { for q in odd_primes().take_while(|q| *q <= p) {
let n = p * q; let n = p * q;
let m = Montgomery::<A>::new(n); let m = Montgomery::<A>::new(n);
assert!(!test(m).is_prime(), "{} = {} × {} reported prime", n, p, q); assert!(!test(m).is_prime(), "{n} = {p} × {q} reported prime");
} }
} }
} }

View file

@ -32,8 +32,8 @@ pub fn gcd(mut u: u64, mut v: u64) -> u64 {
loop { loop {
// Loop invariant: u and v are odd // Loop invariant: u and v are odd
debug_assert!(u % 2 == 1, "u = {} is even", u); debug_assert!(u % 2 == 1, "u = {u} is even");
debug_assert!(v % 2 == 1, "v = {} is even", v); debug_assert!(v % 2 == 1, "v = {v} is even");
// gcd(u, v) = gcd(|u - v|, min(u, v)) // gcd(u, v) = gcd(|u - v|, min(u, v))
if u > v { if u > v {

View file

@ -13,7 +13,7 @@ use super::traits::Int;
pub(crate) fn modular_inverse<T: Int>(a: T) -> T { pub(crate) fn modular_inverse<T: Int>(a: T) -> T {
let zero = T::zero(); let zero = T::zero();
let one = T::one(); 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 t = zero;
let mut new_t = one; let mut new_t = one;

View file

@ -192,7 +192,7 @@ mod tests {
let m_x = m.to_mod(x); let m_x = m.to_mod(x);
for y in 0..=x { for y in 0..=x {
let m_y = m.to_mod(y); 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))); assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y)));
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_false" name = "uu_false"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "false ~ (uutils) do nothing and fail" description = "false ~ (uutils) do nothing and fail"
@ -16,7 +16,7 @@ path = "src/false.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "false" name = "false"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_fmt" name = "uu_fmt"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "fmt ~ (uutils) reformat each paragraph of input" description = "fmt ~ (uutils) reformat each paragraph of input"
@ -17,7 +17,7 @@ path = "src/fmt.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
unicode-width = "0.1.5" unicode-width = "0.1.5"
uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } uucore = { version=">=0.0.17", package="uucore", path="../../uucore" }
[[bin]] [[bin]]
name = "fmt" name = "fmt"

View file

@ -27,7 +27,7 @@ struct BreakArgs<'a> {
} }
impl<'a> 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 { if fresh {
0 0
} else { } else {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_fold" name = "uu_fold"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "fold ~ (uutils) wrap each line of input" description = "fold ~ (uutils) wrap each line of input"
@ -16,7 +16,7 @@ path = "src/fold.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "fold" name = "fold"

View file

@ -17,7 +17,6 @@ use uucore::format_usage;
const TAB_WIDTH: usize = 8; const TAB_WIDTH: usize = 8;
static NAME: &str = "fold";
static USAGE: &str = "{} [OPTION]... [FILE]..."; static USAGE: &str = "{} [OPTION]... [FILE]...";
static ABOUT: &str = "Writes each file (or standard input if no files are given) static ABOUT: &str = "Writes each file (or standard input if no files are given)
to standard output whilst breaking long lines"; to standard output whilst breaking long lines";
@ -63,7 +62,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.name(NAME)
.version(crate_version!()) .version(crate_version!())
.override_usage(format_usage(USAGE)) .override_usage(format_usage(USAGE))
.about(ABOUT) .about(ABOUT)
@ -190,9 +188,9 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
let at_eol = i >= len; let at_eol = i >= len;
if at_eol { if at_eol {
print!("{}", slice); print!("{slice}");
} else { } else {
println!("{}", slice); println!("{slice}");
} }
} }
@ -287,7 +285,7 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
} }
if !output.is_empty() { if !output.is_empty() {
print!("{}", output); print!("{output}");
output.truncate(0); output.truncate(0);
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_groups" name = "uu_groups"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "groups ~ (uutils) display group memberships for USERNAME" description = "groups ~ (uutils) display group memberships for USERNAME"
@ -16,7 +16,7 @@ path = "src/groups.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "groups" name = "groups"

View file

@ -49,7 +49,7 @@ impl Display for GroupsError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
Self::GetGroupsFailed => write!(f, "failed to fetch groups"), 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()), Self::UserNotFound(user) => write!(f, "{}: no such user", user.quote()),
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_hashsum" name = "uu_hashsum"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "hashsum ~ (uutils) display or check input digests" description = "hashsum ~ (uutils) display or check input digests"
@ -26,7 +26,7 @@ sha2 = "0.10.2"
sha3 = "0.10.6" sha3 = "0.10.6"
blake2b_simd = "1.0.0" blake2b_simd = "1.0.0"
blake3 = "1.3.2" blake3 = "1.3.2"
uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } uucore = { version=">=0.0.17", package="uucore", path="../../uucore" }
[[bin]] [[bin]]
name = "hashsum" name = "hashsum"

View file

@ -520,13 +520,12 @@ where
// where `n` is the number of bytes. // where `n` is the number of bytes.
let bytes = options.digest.output_bits() / 4; let bytes = options.digest.output_bits() / 4;
let modifier = if bytes > 0 { let modifier = if bytes > 0 {
format!("{{{}}}", bytes) format!("{{{bytes}}}")
} else { } else {
"+".to_string() "+".to_string()
}; };
let gnu_re = Regex::new(&format!( let gnu_re = Regex::new(&format!(
r"^(?P<digest>[a-fA-F0-9]{}) (?P<binary>[ \*])(?P<fileName>.*)", r"^(?P<digest>[a-fA-F0-9]{modifier}) (?P<binary>[ \*])(?P<fileName>.*)",
modifier,
)) ))
.map_err(|_| HashsumError::InvalidRegex)?; .map_err(|_| HashsumError::InvalidRegex)?;
let bsd_re = Regex::new(&format!( let bsd_re = Regex::new(&format!(
@ -579,7 +578,7 @@ where
uucore::util_name(), uucore::util_name(),
ck_filename ck_filename
); );
println!("{}: FAILED open or read", ck_filename); println!("{ck_filename}: FAILED open or read");
continue; continue;
} }
Ok(file) => file, Ok(file) => file,
@ -604,11 +603,11 @@ where
// easier (and more important) on Unix than on Windows. // easier (and more important) on Unix than on Windows.
if sum == real_sum { if sum == real_sum {
if !options.quiet { if !options.quiet {
println!("{}: OK", ck_filename); println!("{ck_filename}: OK");
} }
} else { } else {
if !options.status { if !options.status {
println!("{}: FAILED", ck_filename); println!("{ck_filename}: FAILED");
} }
failed_cksum += 1; failed_cksum += 1;
} }
@ -624,7 +623,7 @@ where
if options.tag { if options.tag {
println!("{} ({}) = {}", options.algoname, filename.display(), sum); println!("{} ({}) = {}", options.algoname, filename.display(), sum);
} else if options.nonames { } else if options.nonames {
println!("{}", sum); println!("{sum}");
} else { } else {
println!("{} {}{}", sum, binary_marker, filename.display()); println!("{} {}{}", sum, binary_marker, filename.display());
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_head" name = "uu_head"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "head ~ (uutils) display the first lines of input" description = "head ~ (uutils) display the first lines of input"
@ -17,7 +17,7 @@ path = "src/head.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
memchr = "2" 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]] [[bin]]
name = "head" name = "head"

View file

@ -134,7 +134,7 @@ impl Mode {
fn from(matches: &ArgMatches) -> Result<Self, String> { fn from(matches: &ArgMatches) -> Result<Self, String> {
if let Some(v) = matches.get_one::<String>(options::BYTES_NAME) { if let Some(v) = matches.get_one::<String>(options::BYTES_NAME) {
let (n, all_but_last) = 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 { if all_but_last {
Ok(Self::AllButLastBytes(n)) Ok(Self::AllButLastBytes(n))
} else { } else {
@ -142,14 +142,14 @@ impl Mode {
} }
} else if let Some(v) = matches.get_one::<String>(options::LINES_NAME) { } else if let Some(v) = matches.get_one::<String>(options::LINES_NAME) {
let (n, all_but_last) = 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 { if all_but_last {
Ok(Self::AllButLastLines(n)) Ok(Self::AllButLastLines(n))
} else { } else {
Ok(Self::FirstLines(n)) Ok(Self::FirstLines(n))
} }
} else { } else {
Ok(Default::default()) Ok(Self::default())
} }
} }
} }
@ -387,13 +387,13 @@ where
} }
// if it were just `n`, // if it were just `n`,
if lines == n + 1 { if lines == n + 1 {
input.seek(SeekFrom::Start(0))?; input.rewind()?;
return Ok(size - i); return Ok(size - i);
} }
i += 1; i += 1;
} }
if size - i == 0 { if size - i == 0 {
input.seek(SeekFrom::Start(0))?; input.rewind()?;
return Ok(0); return Ok(0);
} }
} }
@ -459,7 +459,7 @@ fn uu_head(options: &HeadOptions) -> UResult<()> {
if let Err(e) = usize::try_from(n) { if let Err(e) = usize::try_from(n) {
show!(USimpleError::new( show!(USimpleError::new(
1, 1,
format!("{}: number of bytes is too large", e) format!("{e}: number of bytes is too large")
)); ));
continue; continue;
}; };
@ -493,7 +493,7 @@ fn uu_head(options: &HeadOptions) -> UResult<()> {
if !first { if !first {
println!(); println!();
} }
println!("==> {} <==", name); println!("==> {name} <==");
} }
head_file(&mut file, options) head_file(&mut file, options)
} }
@ -506,7 +506,7 @@ fn uu_head(options: &HeadOptions) -> UResult<()> {
}; };
show!(USimpleError::new( show!(USimpleError::new(
1, 1,
format!("error reading {}: Input/output error", name) format!("error reading {name}: Input/output error")
)); ));
} }
first = false; first = false;

View file

@ -79,10 +79,10 @@ pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>
Some(n) => n, Some(n) => n,
None => return Some(Err(ParseError::Overflow)), None => return Some(Err(ParseError::Overflow)),
}; };
options.push(OsString::from(format!("{}", num))); options.push(OsString::from(format!("{num}")));
} else { } else {
options.push(OsString::from("-n")); options.push(OsString::from("-n"));
options.push(OsString::from(format!("{}", num))); options.push(OsString::from(format!("{num}")));
} }
Some(Ok(options.into_iter())) Some(Ok(options.into_iter()))
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_hostid" name = "uu_hostid"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "hostid ~ (uutils) display the numeric identifier of the current host" description = "hostid ~ (uutils) display the numeric identifier of the current host"
@ -17,7 +17,7 @@ path = "src/hostid.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
libc = "0.2.137" libc = "0.2.137"
uucore = { version=">=0.0.16", package="uucore", path="../../uucore" } uucore = { version=">=0.0.17", package="uucore", path="../../uucore" }
[[bin]] [[bin]]
name = "hostid" name = "hostid"

View file

@ -50,5 +50,5 @@ fn hostid() {
let mask = 0xffff_ffff; let mask = 0xffff_ffff;
result &= mask; result &= mask;
println!("{:0>8x}", result); println!("{result:0>8x}");
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_hostname" name = "uu_hostname"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "hostname ~ (uutils) display or set the host name of the current host" description = "hostname ~ (uutils) display or set the host name of the current host"
@ -17,7 +17,7 @@ path = "src/hostname.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
hostname = { version = "0.3", features = ["set"] } 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] [target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Networking_WinSock", "Win32_Foundation"] } windows-sys = { version = "0.42.0", default-features = false, features = ["Win32_Networking_WinSock", "Win32_Foundation"] }

View file

@ -164,7 +164,7 @@ fn display_hostname(matches: &ArgMatches) -> UResult<()> {
} }
} }
println!("{}", hostname); println!("{hostname}");
Ok(()) Ok(())
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_id" name = "uu_id"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "id ~ (uutils) display user and group information for USER" description = "id ~ (uutils) display user and group information for USER"
@ -16,7 +16,7 @@ path = "src/id.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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 } selinux = { version="0.3", optional = true }
[[bin]] [[bin]]

View file

@ -326,7 +326,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
if default_format { if default_format {
id_print(&mut state, &groups); id_print(&mut state, &groups);
} }
print!("{}", line_ending); print!("{line_ending}");
if i + 1 >= users.len() { if i + 1 >= users.len() {
break; break;
@ -468,11 +468,11 @@ fn pretty(possible_pw: Option<Passwd>) {
let rid = getuid(); let rid = getuid();
if let Ok(p) = Passwd::locate(rid) { if let Ok(p) = Passwd::locate(rid) {
if login == p.name { if login == p.name {
println!("login\t{}", login); println!("login\t{login}");
} }
println!("uid\t{}", p.name); println!("uid\t{}", p.name);
} else { } else {
println!("uid\t{}", rid); println!("uid\t{rid}");
} }
let eid = getegid(); let eid = getegid();
@ -480,7 +480,7 @@ fn pretty(possible_pw: Option<Passwd>) {
if let Ok(p) = Passwd::locate(eid) { if let Ok(p) = Passwd::locate(eid) {
println!("euid\t{}", p.name); println!("euid\t{}", p.name);
} else { } else {
println!("euid\t{}", eid); println!("euid\t{eid}");
} }
} }
@ -489,7 +489,7 @@ fn pretty(possible_pw: Option<Passwd>) {
if let Ok(g) = Group::locate(rid) { if let Ok(g) = Group::locate(rid) {
println!("euid\t{}", g.name); println!("euid\t{}", g.name);
} else { } else {
println!("euid\t{}", rid); println!("euid\t{rid}");
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_install" name = "uu_install"
version = "0.0.16" version = "0.0.17"
authors = [ authors = [
"Ben Eills <ben@beneills.com>", "Ben Eills <ben@beneills.com>",
"uutils developers", "uutils developers",
@ -22,7 +22,7 @@ clap = { version = "4.0", features = ["wrap_help", "cargo"] }
filetime = "0.2" filetime = "0.2"
file_diff = "1.0.0" file_diff = "1.0.0"
libc = ">= 0.2" 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] [dev-dependencies]
time = "0.3" time = "0.3"

View file

@ -87,7 +87,7 @@ impl Error for InstallError {}
impl Display for InstallError { impl Display for InstallError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Unimplemented(opt) => write!(f, "Unimplemented feature: {}", opt), Self::Unimplemented(opt) => write!(f, "Unimplemented feature: {opt}"),
Self::DirNeedsArg() => { Self::DirNeedsArg() => {
write!( write!(
f, f,
@ -115,7 +115,7 @@ impl Display for InstallError {
&uio_error!(e, "cannot install {} to {}", from.quote(), to.quote()), &uio_error!(e, "cannot install {} to {}", from.quote(), to.quote()),
f, 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::MetadataFailed(e) => Display::fmt(&uio_error!(e, ""), f),
Self::NoSuchUser(user) => write!(f, "no such user: {}", user.maybe_quote()), Self::NoSuchUser(user) => write!(f, "no such user: {}", user.maybe_quote()),
Self::NoSuchGroup(group) => write!(f, "no such group: {}", group.maybe_quote()), Self::NoSuchGroup(group) => write!(f, "no such group: {}", group.maybe_quote()),

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_join" name = "uu_join"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "join ~ (uutils) merge lines from inputs with matching join fields" description = "join ~ (uutils) merge lines from inputs with matching join fields"
@ -16,7 +16,7 @@ path = "src/join.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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" memchr = "2"
[[bin]] [[bin]]

View file

@ -24,8 +24,6 @@ use uucore::display::Quotable;
use uucore::error::{set_exit_code, UError, UResult, USimpleError}; use uucore::error::{set_exit_code, UError, UResult, USimpleError};
use uucore::{crash, crash_if_err}; use uucore::{crash, crash_if_err};
static NAME: &str = "join";
#[derive(Debug)] #[derive(Debug)]
enum JoinError { enum JoinError {
IOError(std::io::Error), IOError(std::io::Error),
@ -43,7 +41,7 @@ impl Error for JoinError {}
impl Display for JoinError { impl Display for JoinError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { 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), 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::<String>("1").map(|s| s.as_str()))?; let key1 = parse_field_number_option(matches.get_one::<String>("1").map(|s| s.as_str()))?;
let key2 = parse_field_number_option(matches.get_one::<String>("2").map(|s| s.as_str()))?; let key2 = parse_field_number_option(matches.get_one::<String>("2").map(|s| s.as_str()))?;
let mut settings: Settings = Default::default(); let mut settings = Settings::default();
let v_values = matches.get_many::<String>("v"); let v_values = matches.get_many::<String>("v");
if v_values.is_some() { if v_values.is_some() {
@ -694,12 +692,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
match exec(file1, file2, settings) { match exec(file1, file2, settings) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => Err(USimpleError::new(1, format!("{}", e))), Err(e) => Err(USimpleError::new(1, format!("{e}"))),
} }
} }
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
Command::new(NAME) Command::new(uucore::util_name())
.version(crate_version!()) .version(crate_version!())
.about( .about(
"For each pair of input lines with identical join fields, write a line to "For each pair of input lines with identical join fields, write a line to

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_kill" name = "uu_kill"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "kill ~ (uutils) send a signal to a process" description = "kill ~ (uutils) send a signal to a process"
@ -17,7 +17,7 @@ path = "src/kill.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
nix = { version = "0.25", features = ["signal"] } 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]] [[bin]]
name = "kill" name = "kill"

View file

@ -146,11 +146,11 @@ fn table() {
fn print_signal(signal_name_or_value: &str) -> UResult<()> { fn print_signal(signal_name_or_value: &str) -> UResult<()> {
for (value, &signal) in ALL_SIGNALS.iter().enumerate() { for (value, &signal) in ALL_SIGNALS.iter().enumerate() {
if signal == signal_name_or_value || (format!("SIG{}", signal)) == signal_name_or_value { if signal == signal_name_or_value || (format!("SIG{signal}")) == signal_name_or_value {
println!("{}", value); println!("{value}");
return Ok(()); return Ok(());
} else if signal_name_or_value == value.to_string() { } else if signal_name_or_value == value.to_string() {
println!("{}", signal); println!("{signal}");
return Ok(()); return Ok(());
} }
} }
@ -165,7 +165,7 @@ fn print_signals() {
if idx > 0 { if idx > 0 {
print!(" "); print!(" ");
} }
print!("{}", signal); print!("{signal}");
} }
println!(); println!();
} }
@ -205,7 +205,7 @@ fn kill(sig: Signal, pids: &[i32]) {
for &pid in pids { for &pid in pids {
if let Err(e) = signal::kill(Pid::from_raw(pid), sig) { if let Err(e) = signal::kill(Pid::from_raw(pid), sig) {
show!(Error::from_raw_os_error(e as i32) 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")));
} }
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_link" name = "uu_link"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "link ~ (uutils) create a hard (file system) link to FILE" description = "link ~ (uutils) create a hard (file system) link to FILE"
@ -16,7 +16,7 @@ path = "src/link.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "link" name = "link"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_ln" name = "uu_ln"
version = "0.0.16" version = "0.0.17"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "ln ~ (uutils) create a (file system) link to TARGET" description = "ln ~ (uutils) create a (file system) link to TARGET"
@ -16,7 +16,7 @@ path = "src/ln.rs"
[dependencies] [dependencies]
clap = { version = "4.0", features = ["wrap_help", "cargo"] } 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]] [[bin]]
name = "ln" name = "ln"

View file

@ -466,7 +466,7 @@ fn simple_backup_path(path: &Path, suffix: &str) -> PathBuf {
fn numbered_backup_path(path: &Path) -> PathBuf { fn numbered_backup_path(path: &Path) -> PathBuf {
let mut i: u64 = 1; let mut i: u64 = 1;
loop { loop {
let new_path = simple_backup_path(path, &format!(".~{}~", i)); let new_path = simple_backup_path(path, &format!(".~{i}~"));
if !new_path.exists() { if !new_path.exists() {
return new_path; return new_path;
} }

Some files were not shown because too many files have changed in this diff Show more