1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge branch 'main' of github.com:uutils/coreutils into fix-5327

This commit is contained in:
tommady 2023-10-11 08:39:52 +00:00
commit edb5b65b01
No known key found for this signature in database
GPG key ID: 175B664929DF2F2F
45 changed files with 680 additions and 807 deletions

View file

@ -82,206 +82,6 @@ jobs:
grep --ignore-case "all deps seem to have been used" udeps.log || { printf "%s\n" "::${fault_type} ::${fault_prefix}: \`cargo udeps\`: style violation (unused dependency found)" ; fault=true ; } grep --ignore-case "all deps seem to have been used" udeps.log || { printf "%s\n" "::${fault_type} ::${fault_prefix}: \`cargo udeps\`: style violation (unused dependency found)" ; fault=true ; }
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
style_format:
name: Style/format
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: rustfmt
- uses: Swatinem/rust-cache@v2
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
*) FAIL_ON_FAULT=true ; FAULT_TYPE=error ;;
esac;
outputs FAIL_ON_FAULT FAULT_TYPE
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
outputs CARGO_FEATURES_OPTION
- name: "`cargo fmt` testing"
shell: bash
run: |
## `cargo fmt` testing
unset fault
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
# * convert any errors/warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message>
S=$(cargo fmt -- --check) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s\n" "$S" | sed -E -n -e "s/^Diff[[:space:]]+in[[:space:]]+${PWD//\//\\/}\/(.*)[[:space:]]+at[[:space:]]+[^0-9]+([0-9]+).*$/::${fault_type} file=\1,line=\2::${fault_prefix}: \`cargo fmt\`: style violation (file:'\1', line:\2; use \`cargo fmt -- \"\1\"\`)/p" ; fault=true ; }
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
fuzz:
name: Run the fuzzers
runs-on: ubuntu-latest
env:
RUN_FOR: 60
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- name: Install `cargo-fuzz`
run: cargo install cargo-fuzz
- uses: Swatinem/rust-cache@v2
- name: Run fuzz_date for XX seconds
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_date -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_test for XX seconds
continue-on-error: true
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_test -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_expr for XX seconds
continue-on-error: true
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_expr -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_glob for XX seconds
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_parse_glob -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_size for XX seconds
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_parse_size -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_time for XX seconds
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_parse_time -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
style_lint:
name: Style/lint
runs-on: ${{ matrix.job.os }}
env:
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
- { os: macos-latest , features: feat_os_macos }
- { os: windows-latest , features: feat_os_windows }
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: clippy
- uses: Swatinem/rust-cache@v2
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.3
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
*) FAIL_ON_FAULT=true ; FAULT_TYPE=error ;;
esac;
outputs FAIL_ON_FAULT FAULT_TYPE
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='--all-features' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features ${{ matrix.job.features }}' ; fi
outputs CARGO_FEATURES_OPTION
# * determine sub-crate utility list
UTILITY_LIST="$(./util/show-utils.sh ${CARGO_FEATURES_OPTION})"
echo UTILITY_LIST=${UTILITY_LIST}
CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo -n "-puu_${u} "; done;)"
outputs CARGO_UTILITY_LIST_OPTIONS
- name: Install/setup prerequisites
shell: bash
run: |
## Install/setup prerequisites
case '${{ matrix.job.os }}' in
macos-latest) brew install coreutils ;; # needed for show-utils.sh
esac
- name: "`cargo clippy` lint testing"
shell: bash
run: |
## `cargo clippy` lint testing
unset fault
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
# * convert any warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message>
S=$(cargo clippy --all-targets ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} -- -W clippy::default_trait_access -W clippy::manual_string_new -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::${fault_type} file=\2,line=\3,col=\4::${fault_prefix}: \`cargo clippy\`: \1 (file:'\2', line:\3)/p;" -e '}' ; fault=true ; }
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
style_spellcheck:
name: Style/spelling
runs-on: ${{ matrix.job.os }}
strategy:
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
steps:
- uses: actions/checkout@v4
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
*) FAIL_ON_FAULT=true ; FAULT_TYPE=error ;;
esac;
outputs FAIL_ON_FAULT FAULT_TYPE
- name: Install/setup prerequisites
shell: bash
run: |
## Install/setup prerequisites
# * pin installed cspell to v4.2.8 (cspell v5+ is broken for NodeJS < v12)
## maint: [2021-11-10; rivy] `cspell` version may be advanced to v5 when used with NodeJS >= v12
sudo apt-get -y update ; sudo apt-get -y install npm ; sudo npm install cspell@4.2.8 -g ;
- name: Run `cspell`
shell: bash
run: |
## Run `cspell`
unset fault
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
# * find cspell configuration ; note: avoid quotes around ${cfg_file} b/c `cspell` (v4) doesn't correctly dequote the config argument (or perhaps a subshell expansion issue?)
cfg_files=($(shopt -s nullglob ; echo {.vscode,.}/{,.}c[sS]pell{.json,.config{.js,.cjs,.json,.yaml,.yml},.yaml,.yml} ;))
cfg_file=${cfg_files[0]}
unset CSPELL_CFG_OPTION ; if [ -n "$cfg_file" ]; then CSPELL_CFG_OPTION="--config $cfg_file" ; fi
# * `cspell`
## maint: [2021-11-10; rivy] the `--no-progress` option for `cspell` is a `cspell` v5+ option
# S=$(cspell ${CSPELL_CFG_OPTION} --no-summary --no-progress "**/*") && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n "s/${PWD//\//\\/}\/(.*):(.*):(.*) - (.*)/::${fault_type} file=\1,line=\2,col=\3::${fault_type^^}: \4 (file:'\1', line:\2)/p" ; fault=true ; true ; }
S=$(cspell ${CSPELL_CFG_OPTION} --no-summary "**/*") && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n "s/${PWD//\//\\/}\/(.*):(.*):(.*) - (.*)/::${fault_type} file=\1,line=\2,col=\3::${fault_type^^}: \4 (file:'\1', line:\2)/p" ; fault=true ; true ; }
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
doc_warnings: doc_warnings:
name: Documentation/warnings name: Documentation/warnings
runs-on: ${{ matrix.job.os }} runs-on: ${{ matrix.job.os }}
@ -610,6 +410,12 @@ jobs:
check() { check() {
# Warn if the size increases by more than 5% # Warn if the size increases by more than 5%
threshold='1.05' threshold='1.05'
if [[ "$2" -eq 0 || "$3" -eq 0 ]]; then
echo "::warning file=$4::Invalid size for $1. Sizes cannot be 0."
return
fi
ratio=$(jq -n "$2 / $3") ratio=$(jq -n "$2 / $3")
echo "$1: size=$2, previous_size=$3, ratio=$ratio, threshold=$threshold" echo "$1: size=$2, previous_size=$3, ratio=$ratio, threshold=$threshold"
if [[ "$(jq -n "$ratio > $threshold")" == 'true' ]]; then if [[ "$(jq -n "$ratio > $threshold")" == 'true' ]]; then
@ -1074,15 +880,6 @@ jobs:
name: toybox-result.json name: toybox-result.json
path: ${{ steps.vars.outputs.TEST_SUMMARY_FILE }} path: ${{ steps.vars.outputs.TEST_SUMMARY_FILE }}
toml_format:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Check
run: npx --yes @taplo/cli fmt --check
coverage: coverage:
name: Code Coverage name: Code Coverage
runs-on: ${{ matrix.job.os }} runs-on: ${{ matrix.job.os }}

176
.github/workflows/code-quality.yml vendored Normal file
View file

@ -0,0 +1,176 @@
name: Code Quality
# spell-checker:ignore TERMUX reactivecircus Swatinem noaudio pkill swiftshader dtolnay juliangruber
on: [push, pull_request]
permissions:
contents: read # to fetch code (actions/checkout)
# End the current execution if there is a new changeset in the PR.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
style_format:
name: Style/format
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: rustfmt
- uses: Swatinem/rust-cache@v2
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
*) FAIL_ON_FAULT=true ; FAULT_TYPE=error ;;
esac;
outputs FAIL_ON_FAULT FAULT_TYPE
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
outputs CARGO_FEATURES_OPTION
- name: "`cargo fmt` testing"
shell: bash
run: |
## `cargo fmt` testing
unset fault
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
# * convert any errors/warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message>
S=$(cargo fmt -- --check) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s\n" "$S" | sed -E -n -e "s/^Diff[[:space:]]+in[[:space:]]+${PWD//\//\\/}\/(.*)[[:space:]]+at[[:space:]]+[^0-9]+([0-9]+).*$/::${fault_type} file=\1,line=\2::${fault_prefix}: \`cargo fmt\`: style violation (file:'\1', line:\2; use \`cargo fmt -- \"\1\"\`)/p" ; fault=true ; }
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
style_lint:
name: Style/lint
runs-on: ${{ matrix.job.os }}
env:
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
- { os: macos-latest , features: feat_os_macos }
- { os: windows-latest , features: feat_os_windows }
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: clippy
- uses: Swatinem/rust-cache@v2
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.3
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
*) FAIL_ON_FAULT=true ; FAULT_TYPE=error ;;
esac;
outputs FAIL_ON_FAULT FAULT_TYPE
# target-specific options
# * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='--all-features' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features ${{ matrix.job.features }}' ; fi
outputs CARGO_FEATURES_OPTION
# * determine sub-crate utility list
UTILITY_LIST="$(./util/show-utils.sh ${CARGO_FEATURES_OPTION})"
echo UTILITY_LIST=${UTILITY_LIST}
CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo -n "-puu_${u} "; done;)"
outputs CARGO_UTILITY_LIST_OPTIONS
- name: Install/setup prerequisites
shell: bash
run: |
## Install/setup prerequisites
case '${{ matrix.job.os }}' in
macos-latest) brew install coreutils ;; # needed for show-utils.sh
esac
- name: "`cargo clippy` lint testing"
shell: bash
run: |
## `cargo clippy` lint testing
unset fault
CLIPPY_FLAGS="-W clippy::default_trait_access -W clippy::manual_string_new -W clippy::cognitive_complexity"
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
# * convert any warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message>
S=$(cargo clippy --all-targets ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} -- ${CLIPPY_FLAGS} -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::${fault_type} file=\2,line=\3,col=\4::${fault_prefix}: \`cargo clippy\`: \1 (file:'\2', line:\3)/p;" -e '}' ; fault=true ; }
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
style_spellcheck:
name: Style/spelling
runs-on: ${{ matrix.job.os }}
strategy:
matrix:
job:
- { os: ubuntu-latest , features: feat_os_unix }
steps:
- uses: actions/checkout@v4
- name: Initialize workflow variables
id: vars
shell: bash
run: |
## VARs setup
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
# failure mode
unset FAIL_ON_FAULT ; case '${{ env.STYLE_FAIL_ON_FAULT }}' in
''|0|f|false|n|no|off) FAULT_TYPE=warning ;;
*) FAIL_ON_FAULT=true ; FAULT_TYPE=error ;;
esac;
outputs FAIL_ON_FAULT FAULT_TYPE
- name: Install/setup prerequisites
shell: bash
run: |
## Install/setup prerequisites
# * pin installed cspell to v4.2.8 (cspell v5+ is broken for NodeJS < v12)
## maint: [2021-11-10; rivy] `cspell` version may be advanced to v5 when used with NodeJS >= v12
sudo apt-get -y update ; sudo apt-get -y install npm ; sudo npm install cspell@4.2.8 -g ;
- name: Run `cspell`
shell: bash
run: |
## Run `cspell`
unset fault
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
# * find cspell configuration ; note: avoid quotes around ${cfg_file} b/c `cspell` (v4) doesn't correctly dequote the config argument (or perhaps a subshell expansion issue?)
cfg_files=($(shopt -s nullglob ; echo {.vscode,.}/{,.}c[sS]pell{.json,.config{.js,.cjs,.json,.yaml,.yml},.yaml,.yml} ;))
cfg_file=${cfg_files[0]}
unset CSPELL_CFG_OPTION ; if [ -n "$cfg_file" ]; then CSPELL_CFG_OPTION="--config $cfg_file" ; fi
# * `cspell`
## maint: [2021-11-10; rivy] the `--no-progress` option for `cspell` is a `cspell` v5+ option
# S=$(cspell ${CSPELL_CFG_OPTION} --no-summary --no-progress "**/*") && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n "s/${PWD//\//\\/}\/(.*):(.*):(.*) - (.*)/::${fault_type} file=\1,line=\2,col=\3::${fault_type^^}: \4 (file:'\1', line:\2)/p" ; fault=true ; true ; }
S=$(cspell ${CSPELL_CFG_OPTION} --no-summary "**/*") && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n "s/${PWD//\//\\/}\/(.*):(.*):(.*) - (.*)/::${fault_type} file=\1,line=\2,col=\3::${fault_type^^}: \4 (file:'\1', line:\2)/p" ; fault=true ; true ; }
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
toml_format:
name: Style/toml
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Check
run: npx --yes @taplo/cli fmt --check

64
.github/workflows/fuzzing.yml vendored Normal file
View file

@ -0,0 +1,64 @@
name: Fuzzing
# spell-checker:ignore fuzzer
on: [push, pull_request]
permissions:
contents: read # to fetch code (actions/checkout)
# End the current execution if there is a new changeset in the PR.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
fuzz:
name: Run the fuzzers
runs-on: ubuntu-latest
env:
RUN_FOR: 60
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- name: Install `cargo-fuzz`
run: cargo install cargo-fuzz
- uses: Swatinem/rust-cache@v2
- name: Run fuzz_date for XX seconds
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_date -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_test for XX seconds
continue-on-error: true
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_test -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_expr for XX seconds
continue-on-error: true
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_expr -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_glob for XX seconds
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_parse_glob -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_size for XX seconds
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_parse_size -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_time for XX seconds
shell: bash
run: |
## Run it
cd fuzz
cargo +nightly fuzz run fuzz_parse_time -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0

52
Cargo.lock generated
View file

@ -188,9 +188,9 @@ dependencies = [
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "1.6.0" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019"
dependencies = [ dependencies = [
"memchr", "memchr",
"regex-automata", "regex-automata",
@ -211,9 +211,9 @@ checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "cc" name = "cc"
@ -470,7 +470,6 @@ dependencies = [
"uu_pwd", "uu_pwd",
"uu_readlink", "uu_readlink",
"uu_realpath", "uu_realpath",
"uu_relpath",
"uu_rm", "uu_rm",
"uu_rmdir", "uu_rmdir",
"uu_runcon", "uu_runcon",
@ -784,25 +783,14 @@ dependencies = [
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.1" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
dependencies = [ dependencies = [
"errno-dragonfly",
"libc", "libc",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]] [[package]]
name = "exacl" name = "exacl"
version = "0.11.0" version = "0.11.0"
@ -1201,9 +1189,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.148" version = "0.2.149"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -1405,9 +1393,9 @@ dependencies = [
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.16" version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
@ -1740,9 +1728,9 @@ checksum = "f1bfbf25d7eb88ddcbb1ec3d755d0634da8f7657b2cb8b74089121409ab8228f"
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.9.6" version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -1752,9 +1740,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.3.9" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" checksum = "465c6fc0621e4abc4187a2bda0937bfd4f722c2730b29562e19689ea796c9a4b"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -1763,9 +1751,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.7.5" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" checksum = "c3cbb081b9784b07cceb8824c8583f86db4814d172ab043f3c23f7dc600bf83d"
[[package]] [[package]]
name = "relative-path" name = "relative-path"
@ -2866,14 +2854,6 @@ dependencies = [
"uucore", "uucore",
] ]
[[package]]
name = "uu_relpath"
version = "0.0.21"
dependencies = [
"clap",
"uucore",
]
[[package]] [[package]]
name = "uu_rm" name = "uu_rm"
version = "0.0.21" version = "0.0.21"

View file

@ -100,7 +100,6 @@ feat_common_core = [
"pwd", "pwd",
"readlink", "readlink",
"realpath", "realpath",
"relpath",
"rm", "rm",
"rmdir", "rmdir",
"seq", "seq",
@ -260,9 +259,9 @@ test = ["uu_test"]
[workspace.dependencies] [workspace.dependencies]
bigdecimal = "0.4" bigdecimal = "0.4"
binary-heap-plus = "0.5.0" binary-heap-plus = "0.5.0"
bstr = "1.6" bstr = "1.7"
bytecount = "0.6.4" bytecount = "0.6.4"
byteorder = "1.4.3" byteorder = "1.5.0"
chrono = { version = "^0.4.31", default-features = false, features = [ chrono = { version = "^0.4.31", default-features = false, features = [
"std", "std",
"alloc", "alloc",
@ -287,7 +286,7 @@ glob = "0.3.1"
half = "2.3" half = "2.3"
indicatif = "0.17" indicatif = "0.17"
itertools = "0.11.0" itertools = "0.11.0"
libc = "0.2.148" libc = "0.2.149"
lscolors = { version = "0.15.0", default-features = false, features = [ lscolors = { version = "0.15.0", default-features = false, features = [
"nu-ansi-term", "nu-ansi-term",
] } ] }
@ -297,7 +296,7 @@ nix = { version = "0.27", default-features = false }
nom = "7.1.3" nom = "7.1.3"
notify = { version = "=6.0.1", features = ["macos_kqueue"] } notify = { version = "=6.0.1", features = ["macos_kqueue"] }
num-bigint = "0.4.4" num-bigint = "0.4.4"
num-traits = "0.2.16" num-traits = "0.2.17"
number_prefix = "0.4" number_prefix = "0.4"
once_cell = "1.18.0" once_cell = "1.18.0"
onig = { version = "~6.4", default-features = false } onig = { version = "~6.4", default-features = false }
@ -310,7 +309,7 @@ rand = { version = "0.8", features = ["small_rng"] }
rand_core = "0.6" rand_core = "0.6"
rayon = "1.8" rayon = "1.8"
redox_syscall = "0.4" redox_syscall = "0.4"
regex = "1.9.6" regex = "1.10.0"
rstest = "0.18.2" rstest = "0.18.2"
rust-ini = "0.19.0" rust-ini = "0.19.0"
same-file = "1.0.6" same-file = "1.0.6"
@ -430,7 +429,6 @@ ptx = { optional = true, version = "0.0.21", package = "uu_ptx", path = "src/uu/
pwd = { optional = true, version = "0.0.21", package = "uu_pwd", path = "src/uu/pwd" } pwd = { optional = true, version = "0.0.21", package = "uu_pwd", path = "src/uu/pwd" }
readlink = { optional = true, version = "0.0.21", package = "uu_readlink", path = "src/uu/readlink" } readlink = { optional = true, version = "0.0.21", package = "uu_readlink", path = "src/uu/readlink" }
realpath = { optional = true, version = "0.0.21", package = "uu_realpath", path = "src/uu/realpath" } realpath = { optional = true, version = "0.0.21", package = "uu_realpath", path = "src/uu/realpath" }
relpath = { optional = true, version = "0.0.21", package = "uu_relpath", path = "src/uu/relpath" }
rm = { optional = true, version = "0.0.21", package = "uu_rm", path = "src/uu/rm" } rm = { optional = true, version = "0.0.21", package = "uu_rm", path = "src/uu/rm" }
rmdir = { optional = true, version = "0.0.21", package = "uu_rmdir", path = "src/uu/rmdir" } rmdir = { optional = true, version = "0.0.21", package = "uu_rmdir", path = "src/uu/rmdir" }
runcon = { optional = true, version = "0.0.21", package = "uu_runcon", path = "src/uu/runcon" } runcon = { optional = true, version = "0.0.21", package = "uu_runcon", path = "src/uu/runcon" }

View file

@ -102,7 +102,6 @@ PROGS := \
pwd \ pwd \
readlink \ readlink \
realpath \ realpath \
relpath \
rm \ rm \
rmdir \ rmdir \
seq \ seq \

View file

@ -1,21 +1,21 @@
target,arch,base32,base64,basename,cat,chgrp,chmod,chown,chroot,cksum,comm,cp,csplit,cut,date,df,dircolors,dirname,du,echo,env,expand,expr,factor,false,fmt,fold,groups,hashsum,head,hostid,hostname,id,install,join,kill,link,ln,logname,ls,mkdir,mkfifo,mknod,mktemp,more,mv,nice,nl,nohup,nproc,numfmt,od,paste,pathchk,pinky,printenv,printf,ptx,pwd,readlink,realpath,relpath,rm,rmdir,seq,shred,shuf,sleep,sort,split,stat,stdbuf,sum,sync,tac,tail,tee,test,timeout,touch,tr,true,truncate,tsort,tty,uname,unexpand,uniq,unlink,uptime,users,wc,who,whoami,yes,chcon,pr,dir,vdir,dd,basenc,runcon target,arch,base32,base64,basename,cat,chgrp,chmod,chown,chroot,cksum,comm,cp,csplit,cut,date,df,dircolors,dirname,du,echo,env,expand,expr,factor,false,fmt,fold,groups,hashsum,head,hostid,hostname,id,install,join,kill,link,ln,logname,ls,mkdir,mkfifo,mknod,mktemp,more,mv,nice,nl,nohup,nproc,numfmt,od,paste,pathchk,pinky,printenv,printf,ptx,pwd,readlink,realpath,rm,rmdir,seq,shred,shuf,sleep,sort,split,stat,stdbuf,sum,sync,tac,tail,tee,test,timeout,touch,tr,true,truncate,tsort,tty,uname,unexpand,uniq,unlink,uptime,users,wc,who,whoami,yes,chcon,pr,dir,vdir,dd,basenc,runcon
aarch64-unknown-linux-gnu,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 aarch64-unknown-linux-gnu,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
i686-unknown-linux-gnu,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 i686-unknown-linux-gnu,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
powerpc64-unknown-linux-gnu,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 powerpc64-unknown-linux-gnu,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
riscv64gc-unknown-linux-gnu,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101 riscv64gc-unknown-linux-gnu,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101
x86_64-unknown-linux-gnu,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 x86_64-unknown-linux-gnu,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
aarch64-pc-windows-msvc,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,101,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,101,0,101,0,101,101,0,0,0,0,0,0,0,0 aarch64-pc-windows-msvc,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,101,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,101,0,101,0,101,101,0,0,0,0,0,0,0,0
i686-pc-windows-gnu,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,0,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,101,0,101,0,0,0,0,0,0,0,0,0 i686-pc-windows-gnu,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,0,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,101,0,101,0,0,0,0,0,0,0,0,0
i686-pc-windows-msvc,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,0,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,101,0,101,0,101,0,0,0,0,0,0,0,0,0 i686-pc-windows-msvc,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,0,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,101,0,101,0,101,0,0,0,0,0,0,0,0,0
x86_64-pc-windows-gnu,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,0,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,101,0,101,0,0,0,0,0,0,0,0,0 x86_64-pc-windows-gnu,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,0,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,101,0,101,0,0,0,0,0,0,0,0,0
x86_64-pc-windows-msvc,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,0,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,101,0,101,0,101,0,0,0,0,0,0,0,0,0 x86_64-pc-windows-msvc,0,0,0,0,0,101,101,101,101,0,0,0,0,0,0,0,0,0,101,0,0,0,101,0,0,0,0,101,0,0,0,0,101,101,0,101,0,0,0,0,0,101,101,0,0,0,101,0,101,0,0,0,0,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,101,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,101,0,101,0,101,0,0,0,0,0,0,0,0,0
x86_64-apple-darwin,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 x86_64-apple-darwin,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
x86_64-unknown-freebsd,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 x86_64-unknown-freebsd,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
x86_64-unknown-netbsd,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,101,101,0,101,0,0,0,0,0,0,0,0,0 x86_64-unknown-netbsd,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,101,101,0,101,0,0,0,0,0,0,0,0,0
aarch64-linux-android,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,101,101,0,101,0,0,0,0,0,0,0,0,0 aarch64-linux-android,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,101,101,0,101,0,0,0,0,0,0,0,0,0
x86_64-linux-android,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,101,101,0,101,0,0,0,0,0,0,0,0,0 x86_64-linux-android,0,0,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,0,0,0,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,0,101,0,0,0,0,101,0,0,0,0,0,0,101,0,0,0,101,101,0,101,0,0,0,0,0,0,0,0,0
x86_64-sun-solaris,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101 x86_64-sun-solaris,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101
wasm32-wasi,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101 wasm32-wasi,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101
x86_64-unknown-redox,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101 x86_64-unknown-redox,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101
aarch64-fuchsia,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101 aarch64-fuchsia,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101
x86_64-fuchsia,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101 x86_64-fuchsia,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101

1 target arch base32 base64 basename cat chgrp chmod chown chroot cksum comm cp csplit cut date df dircolors dirname du echo env expand expr factor false fmt fold groups hashsum head hostid hostname id install join kill link ln logname ls mkdir mkfifo mknod mktemp more mv nice nl nohup nproc numfmt od paste pathchk pinky printenv printf ptx pwd readlink realpath relpath rm rmdir seq shred shuf sleep sort split stat stdbuf sum sync tac tail tee test timeout touch tr true truncate tsort tty uname unexpand uniq unlink uptime users wc who whoami yes chcon pr dir vdir dd basenc runcon
2 aarch64-unknown-linux-gnu 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3 i686-unknown-linux-gnu 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 powerpc64-unknown-linux-gnu 0 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5 riscv64gc-unknown-linux-gnu 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
6 x86_64-unknown-linux-gnu 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
7 aarch64-pc-windows-msvc 0 0 0 0 0 101 101 101 101 0 0 0 0 0 0 0 0 0 101 0 0 0 101 0 0 0 0 101 0 0 0 0 101 101 0 101 0 0 0 101 0 101 101 0 0 0 101 0 101 0 0 0 0 101 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 101 0 0 0 0 0 0 101 0 0 0 0 0 101 0 0 0 101 0 101 0 101 101 0 0 0 0 0 0 0 0
8 i686-pc-windows-gnu 0 0 0 0 0 101 101 101 101 0 0 0 0 0 0 0 0 0 101 0 0 0 101 0 0 0 0 101 0 0 0 0 101 101 0 101 0 0 0 0 0 101 101 0 0 0 101 0 101 0 0 0 0 101 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 101 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 101 0 101 0 101 0 0 0 0 0 0 0 0 0
9 i686-pc-windows-msvc 0 0 0 0 0 101 101 101 101 0 0 0 0 0 0 0 0 0 101 0 0 0 101 0 0 0 0 101 0 0 0 0 101 101 0 101 0 0 0 0 0 101 101 0 0 0 101 0 101 0 0 0 0 101 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 101 0 0 0 0 0 0 101 0 0 0 0 0 101 0 0 0 101 0 101 0 101 0 0 0 0 0 0 0 0 0
10 x86_64-pc-windows-gnu 0 0 0 0 0 101 101 101 101 0 0 0 0 0 0 0 0 0 101 0 0 0 101 0 0 0 0 101 0 0 0 0 101 101 0 101 0 0 0 0 0 101 101 0 0 0 101 0 101 0 0 0 0 101 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 101 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 101 0 101 0 101 0 0 0 0 0 0 0 0 0
11 x86_64-pc-windows-msvc 0 0 0 0 0 101 101 101 101 0 0 0 0 0 0 0 0 0 101 0 0 0 101 0 0 0 0 101 0 0 0 0 101 101 0 101 0 0 0 0 0 101 101 0 0 0 101 0 101 0 0 0 0 101 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 101 0 0 0 0 0 0 101 0 0 0 0 0 101 0 0 0 101 0 101 0 101 0 0 0 0 0 0 0 0 0
12 x86_64-apple-darwin 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
13 x86_64-unknown-freebsd 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
14 x86_64-unknown-netbsd 0 0 0 0 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 101 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 101 101 0 101 0 0 0 0 0 0 0 0 0
15 aarch64-linux-android 0 0 0 0 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 101 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 101 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 101 101 0 101 0 0 0 0 0 0 0 0 0
16 x86_64-linux-android 0 0 0 0 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 101 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 0 0 0 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 0 0 101 0 0 0 0 101 0 0 0 0 0 0 101 0 0 0 101 101 0 101 0 0 0 0 0 0 0 0 0
17 x86_64-sun-solaris 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
18 wasm32-wasi 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
19 x86_64-unknown-redox 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
20 aarch64-fuchsia 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
21 x86_64-fuchsia 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101

View file

@ -195,6 +195,53 @@ pub fn uu_app() -> Command {
) )
} }
/// Parses the user string to extract the UID.
fn parse_uid(user: &str, spec: &str, sep: char) -> UResult<Option<u32>> {
if user.is_empty() {
return Ok(None);
}
match Passwd::locate(user) {
Ok(u) => Ok(Some(u.uid)), // We have been able to get the uid
Err(_) => {
// we have NOT been able to find the uid
// but we could be in the case where we have user.group
if spec.contains('.') && !spec.contains(':') && sep == ':' {
// but the input contains a '.' but not a ':'
// we might have something like username.groupname
// So, try to parse it this way
parse_spec(spec, '.').map(|(uid, _)| uid)
} else {
// It's possible that the `user` string contains a
// numeric user ID, in which case, we respect that.
match user.parse() {
Ok(uid) => Ok(Some(uid)),
Err(_) => Err(USimpleError::new(
1,
format!("invalid user: {}", spec.quote()),
)),
}
}
}
}
}
/// Parses the group string to extract the GID.
fn parse_gid(group: &str, spec: &str) -> UResult<Option<u32>> {
if group.is_empty() {
return Ok(None);
}
match Group::locate(group) {
Ok(g) => Ok(Some(g.gid)),
Err(_) => match group.parse() {
Ok(gid) => Ok(Some(gid)),
Err(_) => Err(USimpleError::new(
1,
format!("invalid group: {}", spec.quote()),
)),
},
}
}
/// Parse the owner/group specifier string into a user ID and a group ID. /// Parse the owner/group specifier string into a user ID and a group ID.
/// ///
/// The `spec` can be of the form: /// The `spec` can be of the form:
@ -213,52 +260,8 @@ fn parse_spec(spec: &str, sep: char) -> UResult<(Option<u32>, Option<u32>)> {
let user = args.next().unwrap_or(""); let user = args.next().unwrap_or("");
let group = args.next().unwrap_or(""); let group = args.next().unwrap_or("");
let uid = if user.is_empty() { let uid = parse_uid(user, spec, sep)?;
None let gid = parse_gid(group, spec)?;
} else {
Some(match Passwd::locate(user) {
Ok(u) => u.uid, // We have been able to get the uid
Err(_) =>
// we have NOT been able to find the uid
// but we could be in the case where we have user.group
{
if spec.contains('.') && !spec.contains(':') && sep == ':' {
// but the input contains a '.' but not a ':'
// we might have something like username.groupname
// So, try to parse it this way
return parse_spec(spec, '.');
} else {
// It's possible that the `user` string contains a
// numeric user ID, in which case, we respect that.
match user.parse() {
Ok(uid) => uid,
Err(_) => {
return Err(USimpleError::new(
1,
format!("invalid user: {}", spec.quote()),
))
}
}
}
}
})
};
let gid = if group.is_empty() {
None
} else {
Some(match Group::locate(group) {
Ok(g) => g.gid,
Err(_) => match group.parse() {
Ok(gid) => gid,
Err(_) => {
return Err(USimpleError::new(
1,
format!("invalid group: {}", spec.quote()),
));
}
},
})
};
if user.chars().next().map(char::is_numeric).unwrap_or(false) if user.chars().next().map(char::is_numeric).unwrap_or(false)
&& group.is_empty() && group.is_empty()

View file

@ -447,6 +447,7 @@ mod tests {
use super::ends_with_slash_dot; use super::ends_with_slash_dot;
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_ends_with_slash_dot() { fn test_ends_with_slash_dot() {
assert!(ends_with_slash_dot("/.")); assert!(ends_with_slash_dot("/."));
assert!(ends_with_slash_dot("./.")); assert!(ends_with_slash_dot("./."));

View file

@ -2,7 +2,7 @@
// //
// 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.
// spell-checker:ignore tmpfs Pcent Itotal Iused Iavail Ipcent // spell-checker:ignore tmpfs Pcent Itotal Iused Iavail Ipcent nosuid nodev
//! The filesystem usage data table. //! The filesystem usage data table.
//! //!
//! A table ([`Table`]) comprises a header row ([`Header`]) and a //! A table ([`Table`]) comprises a header row ([`Header`]) and a
@ -152,8 +152,10 @@ impl From<Filesystem> for Row {
ffree, ffree,
.. ..
} = fs.usage; } = fs.usage;
let bused = blocks - bfree;
let fused = files - ffree; // On Windows WSL, files can be less than ffree. Protect such cases via saturating_sub.
let bused = blocks.saturating_sub(bfree);
let fused = files.saturating_sub(ffree);
Self { Self {
file: fs.file, file: fs.file,
fs_device: dev_name, fs_device: dev_name,
@ -815,4 +817,35 @@ mod tests {
assert_eq!(get_formatted_values(1000, 1000, 0), vec!("1", "1", "0")); assert_eq!(get_formatted_values(1000, 1000, 0), vec!("1", "1", "0"));
assert_eq!(get_formatted_values(1001, 1000, 1), vec!("2", "1", "1")); assert_eq!(get_formatted_values(1001, 1000, 1), vec!("2", "1", "1"));
} }
#[test]
fn test_row_converter_with_invalid_numbers() {
// copy from wsl linux
let d = crate::Filesystem {
file: None,
mount_info: crate::MountInfo {
dev_id: "28".to_string(),
dev_name: "none".to_string(),
fs_type: "9p".to_string(),
mount_dir: "/usr/lib/wsl/drivers".to_string(),
mount_option: "ro,nosuid,nodev,noatime".to_string(),
mount_root: "/".to_string(),
remote: false,
dummy: false,
},
usage: crate::table::FsUsage {
blocksize: 4096,
blocks: 244029695,
bfree: 125085030,
bavail: 125085030,
bavail_top_bit_set: false,
files: 999,
ffree: 1000000,
},
};
let row = Row::from(d);
assert_eq!(row.inodes_used, 0);
}
} }

View file

@ -31,10 +31,12 @@ pub enum AstNode {
operands: OperandsList, operands: OperandsList,
}, },
} }
impl AstNode { impl AstNode {
fn debug_dump(&self) { fn debug_dump(&self) {
self.debug_dump_impl(1); self.debug_dump_impl(1);
} }
fn debug_dump_impl(&self, depth: usize) { fn debug_dump_impl(&self, depth: usize) {
for _ in 0..depth { for _ in 0..depth {
print!("\t",); print!("\t",);
@ -52,7 +54,7 @@ impl AstNode {
operands, operands,
} => { } => {
println!( println!(
"Node( {} ) at #{} (evaluate -> {:?})", "Node( {} ) at #{} ( evaluate -> {:?} )",
op_type, op_type,
token_idx, token_idx,
self.evaluate() self.evaluate()
@ -71,12 +73,14 @@ impl AstNode {
operands, operands,
}) })
} }
fn new_leaf(token_idx: usize, value: &str) -> Box<Self> { fn new_leaf(token_idx: usize, value: &str) -> Box<Self> {
Box::new(Self::Leaf { Box::new(Self::Leaf {
token_idx, token_idx,
value: value.into(), value: value.into(),
}) })
} }
pub fn evaluate(&self) -> Result<String, String> { pub fn evaluate(&self) -> Result<String, String> {
match self { match self {
Self::Leaf { value, .. } => Ok(value.clone()), Self::Leaf { value, .. } => Ok(value.clone()),
@ -154,9 +158,27 @@ impl AstNode {
}, },
} }
} }
pub fn operand_values(&self) -> Result<Vec<String>, String> { pub fn operand_values(&self) -> Result<Vec<String>, String> {
if let Self::Node { operands, .. } = self { if let Self::Node {
operands, op_type, ..
} = self
{
let mut out = Vec::with_capacity(operands.len()); let mut out = Vec::with_capacity(operands.len());
let mut operands = operands.iter();
// check the first value before `|`, stop evaluate and return directly if it is true.
// push dummy to pass the check of `len() == 2`
if op_type == "|" {
if let Some(value) = operands.next() {
let value = value.evaluate()?;
out.push(value.clone());
if value_as_bool(&value) {
out.push(String::from("dummy"));
return Ok(out);
}
}
}
for operand in operands { for operand in operands {
let value = operand.evaluate()?; let value = operand.evaluate()?;
out.push(value); out.push(value);
@ -240,6 +262,7 @@ fn ast_from_rpn(rpn: &mut TokenStack) -> Result<Box<AstNode>, String> {
} }
} }
} }
fn maybe_ast_node( fn maybe_ast_node(
token_idx: usize, token_idx: usize,
op_type: &str, op_type: &str,
@ -503,6 +526,7 @@ fn prefix_operator_substr(values: &[String]) -> String {
fn bool_as_int(b: bool) -> u8 { fn bool_as_int(b: bool) -> u8 {
u8::from(b) u8::from(b)
} }
fn bool_as_string(b: bool) -> String { fn bool_as_string(b: bool) -> String {
if b { if b {
"1".to_string() "1".to_string()
@ -510,6 +534,7 @@ fn bool_as_string(b: bool) -> String {
"0".to_string() "0".to_string()
} }
} }
fn value_as_bool(s: &str) -> bool { fn value_as_bool(s: &str) -> bool {
if s.is_empty() { if s.is_empty() {
return false; return false;

View file

@ -38,6 +38,7 @@ pub enum Token {
value: String, value: String,
}, },
} }
impl Token { impl Token {
fn new_infix_op(v: &str, left_assoc: bool, precedence: u8) -> Self { fn new_infix_op(v: &str, left_assoc: bool, precedence: u8) -> Self {
Self::InfixOp { Self::InfixOp {
@ -46,6 +47,7 @@ impl Token {
value: v.into(), value: v.into(),
} }
} }
fn new_value(v: &str) -> Self { fn new_value(v: &str) -> Self {
Self::Value { value: v.into() } Self::Value { value: v.into() }
} }
@ -56,12 +58,14 @@ impl Token {
_ => false, _ => false,
} }
} }
fn is_a_number(&self) -> bool { fn is_a_number(&self) -> bool {
match self { match self {
Self::Value { value, .. } => value.parse::<BigInt>().is_ok(), Self::Value { value, .. } => value.parse::<BigInt>().is_ok(),
_ => false, _ => false,
} }
} }
fn is_a_close_paren(&self) -> bool { fn is_a_close_paren(&self) -> bool {
matches!(*self, Self::ParClose) matches!(*self, Self::ParClose)
} }

View file

@ -3,7 +3,7 @@
// 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.
// spell-checker:ignore (vars) zlines BUFWRITER seekable // spell-checker:ignore (vars) BUFWRITER seekable
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
use std::ffi::OsString; use std::ffi::OsString;
@ -31,6 +31,7 @@ mod options {
pub const FILES_NAME: &str = "FILE"; pub const FILES_NAME: &str = "FILE";
pub const PRESUME_INPUT_PIPE: &str = "-PRESUME-INPUT-PIPE"; pub const PRESUME_INPUT_PIPE: &str = "-PRESUME-INPUT-PIPE";
} }
mod parse; mod parse;
mod take; mod take;
use take::take_all_but; use take::take_all_but;
@ -519,6 +520,7 @@ mod tests {
use std::io::Cursor; use std::io::Cursor;
use super::*; use super::*;
fn options(args: &str) -> Result<HeadOptions, String> { fn options(args: &str) -> Result<HeadOptions, String> {
let combined = "head ".to_owned() + args; let combined = "head ".to_owned() + args;
let args = combined.split_whitespace().map(OsString::from); let args = combined.split_whitespace().map(OsString::from);
@ -526,6 +528,7 @@ mod tests {
.get_matches_from(arg_iterate(args).map_err(|_| String::from("Arg iterate failed"))?); .get_matches_from(arg_iterate(args).map_err(|_| String::from("Arg iterate failed"))?);
HeadOptions::get_from(&matches) HeadOptions::get_from(&matches)
} }
#[test] #[test]
fn test_args_modes() { fn test_args_modes() {
let args = options("-n -10M -vz").unwrap(); let args = options("-n -10M -vz").unwrap();
@ -533,6 +536,7 @@ mod tests {
assert!(args.verbose); assert!(args.verbose);
assert_eq!(args.mode, Mode::AllButLastLines(10 * 1024 * 1024)); assert_eq!(args.mode, Mode::AllButLastLines(10 * 1024 * 1024));
} }
#[test] #[test]
fn test_gnu_compatibility() { fn test_gnu_compatibility() {
let args = options("-n 1 -c 1 -n 5 -c kiB -vqvqv").unwrap(); // spell-checker:disable-line let args = options("-n 1 -c 1 -n 5 -c kiB -vqvqv").unwrap(); // spell-checker:disable-line
@ -542,6 +546,7 @@ mod tests {
assert_eq!(options("-2b").unwrap().mode, Mode::FirstBytes(1024)); assert_eq!(options("-2b").unwrap().mode, Mode::FirstBytes(1024));
assert_eq!(options("-5 -c 1").unwrap().mode, Mode::FirstBytes(1)); assert_eq!(options("-5 -c 1").unwrap().mode, Mode::FirstBytes(1));
} }
#[test] #[test]
fn all_args_test() { fn all_args_test() {
assert!(options("--silent").unwrap().quiet); assert!(options("--silent").unwrap().quiet);
@ -559,11 +564,13 @@ mod tests {
assert_eq!(options("--bytes 15").unwrap().mode, Mode::FirstBytes(15)); assert_eq!(options("--bytes 15").unwrap().mode, Mode::FirstBytes(15));
assert_eq!(options("-c 15").unwrap().mode, Mode::FirstBytes(15)); assert_eq!(options("-c 15").unwrap().mode, Mode::FirstBytes(15));
} }
#[test] #[test]
fn test_options_errors() { fn test_options_errors() {
assert!(options("-n IsThisTheRealLife?").is_err()); assert!(options("-n IsThisTheRealLife?").is_err());
assert!(options("-c IsThisJustFantasy").is_err()); assert!(options("-c IsThisJustFantasy").is_err());
} }
#[test] #[test]
fn test_options_correct_defaults() { fn test_options_correct_defaults() {
let opts = HeadOptions::default(); let opts = HeadOptions::default();
@ -574,6 +581,7 @@ mod tests {
assert_eq!(opts.mode, Mode::FirstLines(10)); assert_eq!(opts.mode, Mode::FirstLines(10));
assert!(opts.files.is_empty()); assert!(opts.files.is_empty());
} }
fn arg_outputs(src: &str) -> Result<String, ()> { fn arg_outputs(src: &str) -> Result<String, ()> {
let split = src.split_whitespace().map(OsString::from); let split = src.split_whitespace().map(OsString::from);
match arg_iterate(split) { match arg_iterate(split) {
@ -586,6 +594,7 @@ mod tests {
Err(_) => Err(()), Err(_) => Err(()),
} }
} }
#[test] #[test]
fn test_arg_iterate() { fn test_arg_iterate() {
// test that normal args remain unchanged // test that normal args remain unchanged
@ -610,6 +619,7 @@ mod tests {
//test that empty args remain unchanged //test that empty args remain unchanged
assert_eq!(arg_outputs("head"), Ok("head".to_owned())); assert_eq!(arg_outputs("head"), Ok("head".to_owned()));
} }
#[test] #[test]
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn test_arg_iterate_bad_encoding() { fn test_arg_iterate_bad_encoding() {
@ -618,6 +628,7 @@ mod tests {
// this arises from a conversion from OsString to &str // this arises from a conversion from OsString to &str
assert!(arg_iterate(vec![OsString::from("head"), invalid].into_iter()).is_err()); assert!(arg_iterate(vec![OsString::from("head"), invalid].into_iter()).is_err());
} }
#[test] #[test]
fn read_early_exit() { fn read_early_exit() {
let mut empty = std::io::BufReader::new(std::io::Cursor::new(Vec::new())); let mut empty = std::io::BufReader::new(std::io::Cursor::new(Vec::new()));

View file

@ -11,9 +11,9 @@ pub enum ParseError {
Syntax, Syntax,
Overflow, Overflow,
} }
/// Parses obsolete syntax /// Parses obsolete syntax
/// head -NUM\[kmzv\] // spell-checker:disable-line /// head -NUM\[kmzv\] // spell-checker:disable-line
#[allow(clippy::cognitive_complexity)]
pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>, ParseError>> { pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>, ParseError>> {
let mut chars = src.char_indices(); let mut chars = src.char_indices();
if let Some((_, '-')) = chars.next() { if let Some((_, '-')) = chars.next() {
@ -30,65 +30,7 @@ pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>
} }
} }
if has_num { if has_num {
match src[1..=num_end].parse::<usize>() { process_num_block(&src[1..=num_end], last_char, &mut chars)
Ok(num) => {
let mut quiet = false;
let mut verbose = false;
let mut zero_terminated = false;
let mut multiplier = None;
let mut c = last_char;
loop {
// not that here, we only match lower case 'k', 'c', and 'm'
match c {
// we want to preserve order
// this also saves us 1 heap allocation
'q' => {
quiet = true;
verbose = false;
}
'v' => {
verbose = true;
quiet = false;
}
'z' => zero_terminated = true,
'c' => multiplier = Some(1),
'b' => multiplier = Some(512),
'k' => multiplier = Some(1024),
'm' => multiplier = Some(1024 * 1024),
'\0' => {}
_ => return Some(Err(ParseError::Syntax)),
}
if let Some((_, next)) = chars.next() {
c = next;
} else {
break;
}
}
let mut options = Vec::new();
if quiet {
options.push(OsString::from("-q"));
}
if verbose {
options.push(OsString::from("-v"));
}
if zero_terminated {
options.push(OsString::from("-z"));
}
if let Some(n) = multiplier {
options.push(OsString::from("-c"));
let num = match num.checked_mul(n) {
Some(n) => n,
None => return Some(Err(ParseError::Overflow)),
};
options.push(OsString::from(format!("{num}")));
} else {
options.push(OsString::from("-n"));
options.push(OsString::from(format!("{num}")));
}
Some(Ok(options.into_iter()))
}
Err(_) => Some(Err(ParseError::Overflow)),
}
} else { } else {
None None
} }
@ -96,6 +38,74 @@ pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>
None None
} }
} }
/// Processes the numeric block of the input string to generate the appropriate options.
fn process_num_block(
src: &str,
last_char: char,
chars: &mut std::str::CharIndices,
) -> Option<Result<impl Iterator<Item = OsString>, ParseError>> {
match src.parse::<usize>() {
Ok(num) => {
let mut quiet = false;
let mut verbose = false;
let mut zero_terminated = false;
let mut multiplier = None;
let mut c = last_char;
loop {
// note that here, we only match lower case 'k', 'c', and 'm'
match c {
// we want to preserve order
// this also saves us 1 heap allocation
'q' => {
quiet = true;
verbose = false;
}
'v' => {
verbose = true;
quiet = false;
}
'z' => zero_terminated = true,
'c' => multiplier = Some(1),
'b' => multiplier = Some(512),
'k' => multiplier = Some(1024),
'm' => multiplier = Some(1024 * 1024),
'\0' => {}
_ => return Some(Err(ParseError::Syntax)),
}
if let Some((_, next)) = chars.next() {
c = next;
} else {
break;
}
}
let mut options = Vec::new();
if quiet {
options.push(OsString::from("-q"));
}
if verbose {
options.push(OsString::from("-v"));
}
if zero_terminated {
options.push(OsString::from("-z"));
}
if let Some(n) = multiplier {
options.push(OsString::from("-c"));
let num = match num.checked_mul(n) {
Some(n) => n,
None => return Some(Err(ParseError::Overflow)),
};
options.push(OsString::from(format!("{num}")));
} else {
options.push(OsString::from("-n"));
options.push(OsString::from(format!("{num}")));
}
Some(Ok(options.into_iter()))
}
Err(_) => Some(Err(ParseError::Overflow)),
}
}
/// Parses an -c or -n argument, /// Parses an -c or -n argument,
/// the bool specifies whether to read from the end /// the bool specifies whether to read from the end
pub fn parse_num(src: &str) -> Result<(u64, bool), ParseSizeError> { pub fn parse_num(src: &str) -> Result<(u64, bool), ParseSizeError> {
@ -126,6 +136,7 @@ pub fn parse_num(src: &str) -> Result<(u64, bool), ParseSizeError> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
fn obsolete(src: &str) -> Option<Result<Vec<String>, ParseError>> { fn obsolete(src: &str) -> Option<Result<Vec<String>, ParseError>> {
let r = parse_obsolete(src); let r = parse_obsolete(src);
match r { match r {
@ -136,9 +147,11 @@ mod tests {
None => None, None => None,
} }
} }
fn obsolete_result(src: &[&str]) -> Option<Result<Vec<String>, ParseError>> { fn obsolete_result(src: &[&str]) -> Option<Result<Vec<String>, ParseError>> {
Some(Ok(src.iter().map(|s| s.to_string()).collect())) Some(Ok(src.iter().map(|s| s.to_string()).collect()))
} }
#[test] #[test]
fn test_parse_numbers_obsolete() { fn test_parse_numbers_obsolete() {
assert_eq!(obsolete("-5"), obsolete_result(&["-n", "5"])); assert_eq!(obsolete("-5"), obsolete_result(&["-n", "5"]));
@ -158,16 +171,19 @@ mod tests {
obsolete_result(&["-z", "-c", "110100480"]) obsolete_result(&["-z", "-c", "110100480"])
); );
} }
#[test] #[test]
fn test_parse_errors_obsolete() { fn test_parse_errors_obsolete() {
assert_eq!(obsolete("-5n"), Some(Err(ParseError::Syntax))); assert_eq!(obsolete("-5n"), Some(Err(ParseError::Syntax)));
assert_eq!(obsolete("-5c5"), Some(Err(ParseError::Syntax))); assert_eq!(obsolete("-5c5"), Some(Err(ParseError::Syntax)));
} }
#[test] #[test]
fn test_parse_obsolete_no_match() { fn test_parse_obsolete_no_match() {
assert_eq!(obsolete("-k"), None); assert_eq!(obsolete("-k"), None);
assert_eq!(obsolete("asd"), None); assert_eq!(obsolete("asd"), None);
} }
#[test] #[test]
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
fn test_parse_obsolete_overflow_x64() { fn test_parse_obsolete_overflow_x64() {
@ -180,6 +196,7 @@ mod tests {
Some(Err(ParseError::Overflow)) Some(Err(ParseError::Overflow))
); );
} }
#[test] #[test]
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
fn test_parse_obsolete_overflow_x32() { fn test_parse_obsolete_overflow_x32() {

View file

@ -109,6 +109,7 @@ struct State {
} }
#[uucore::main] #[uucore::main]
#[allow(clippy::cognitive_complexity)]
pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().after_help(AFTER_HELP).try_get_matches_from(args)?; let matches = uu_app().after_help(AFTER_HELP).try_get_matches_from(args)?;

View file

@ -526,6 +526,7 @@ fn is_potential_directory_path(path: &Path) -> bool {
/// ///
/// Returns a Result type with the Err variant containing the error message. /// Returns a Result type with the Err variant containing the error message.
/// ///
#[allow(clippy::cognitive_complexity)]
fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> { fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
// first check that paths contains at least one element // first check that paths contains at least one element
if paths.is_empty() { if paths.is_empty() {

View file

@ -1856,6 +1856,7 @@ impl PathData {
} }
} }
#[allow(clippy::cognitive_complexity)]
pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> { pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
let mut files = Vec::<PathData>::new(); let mut files = Vec::<PathData>::new();
let mut dirs = Vec::<PathData>::new(); let mut dirs = Vec::<PathData>::new();
@ -2888,7 +2889,11 @@ fn classify_file(path: &PathData, out: &mut BufWriter<Stdout>) -> Option<char> {
Some('=') Some('=')
} else if file_type.is_fifo() { } else if file_type.is_fifo() {
Some('|') Some('|')
} else if file_type.is_file() && file_is_executable(path.md(out).as_ref().unwrap()) { } else if file_type.is_file()
// Safe unwrapping if the file was removed between listing and display
// See https://github.com/uutils/coreutils/issues/5371
&& path.md(out).map(file_is_executable).unwrap_or_default()
{
Some('*') Some('*')
} else { } else {
None None

View file

@ -137,21 +137,34 @@ pub fn uu_app() -> Command {
*/ */
fn exec(dirs: ValuesRef<OsString>, recursive: bool, mode: u32, verbose: bool) -> UResult<()> { fn exec(dirs: ValuesRef<OsString>, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
for dir in dirs { for dir in dirs {
// Special case to match GNU's behavior: let path_buf = PathBuf::from(dir);
// mkdir -p foo/. should work and just create foo/ let path = path_buf.as_path();
// std::fs::create_dir("foo/."); fails in pure Rust
let path = if recursive { show_if_err!(mkdir(path, recursive, mode, verbose));
dir_strip_dot_for_creation(&PathBuf::from(dir))
} else {
// Normal case
PathBuf::from(dir)
};
show_if_err!(mkdir(path.as_path(), recursive, mode, verbose));
} }
Ok(()) Ok(())
} }
fn mkdir(path: &Path, recursive: bool, mode: u32, verbose: bool) -> UResult<()> { /// Create directory at a given `path`.
///
/// ## Options
///
/// * `recursive` --- create parent directories for the `path`, if they do not
/// exist.
/// * `mode` --- file mode for the directories (not implemented on windows).
/// * `verbose` --- print a message for each printed directory.
///
/// ## Trailing dot
///
/// To match the GNU behavior, a path with the last directory being a single dot
/// (like `some/path/to/.`) is created (with the dot stripped).
pub fn mkdir(path: &Path, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
// Special case to match GNU's behavior:
// mkdir -p foo/. should work and just create foo/
// std::fs::create_dir("foo/."); fails in pure Rust
let path_buf = dir_strip_dot_for_creation(path);
let path = path_buf.as_path();
create_dir(path, recursive, verbose, false)?; create_dir(path, recursive, verbose, false)?;
chmod(path, mode) chmod(path, mode)
} }

View file

@ -3,7 +3,7 @@
// 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.
// spell-checker:ignore (ToDO) sourcepath targetpath // spell-checker:ignore (ToDO) sourcepath targetpath nushell
mod error; mod error;
@ -19,7 +19,8 @@ use std::os::unix;
#[cfg(windows)] #[cfg(windows)]
use std::os::windows; use std::os::windows;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uucore::backup_control::{self, source_is_target_backup, BackupMode}; pub use uucore::backup_control::BackupMode;
use uucore::backup_control::{self, source_is_target_backup};
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{set_exit_code, FromIo, UError, UResult, USimpleError, UUsageError}; use uucore::error::{set_exit_code, FromIo, UError, UResult, USimpleError, UUsageError};
use uucore::fs::{are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file}; use uucore::fs::{are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file};
@ -33,22 +34,56 @@ use fs_extra::dir::{
use crate::error::MvError; use crate::error::MvError;
pub struct Behavior { /// Options contains all the possible behaviors and flags for mv.
overwrite: OverwriteMode, ///
backup: BackupMode, /// All options are public so that the options can be programmatically
suffix: String, /// constructed by other crates, such as nushell. That means that this struct is
update: UpdateMode, /// part of our public API. It should therefore not be changed without good reason.
target_dir: Option<OsString>, ///
no_target_dir: bool, /// The fields are documented with the arguments that determine their value.
verbose: bool, #[derive(Debug, Clone, Eq, PartialEq)]
strip_slashes: bool, pub struct Options {
progress_bar: bool, /// specifies overwrite behavior
/// '-n' '--no-clobber'
/// '-i' '--interactive'
/// '-f' '--force'
pub overwrite: OverwriteMode,
/// `--backup[=CONTROL]`, `-b`
pub backup: BackupMode,
/// '-S' --suffix' backup suffix
pub suffix: String,
/// Available update mode "--update-mode=all|none|older"
pub update: UpdateMode,
/// Specifies target directory
/// '-t, --target-directory=DIRECTORY'
pub target_dir: Option<OsString>,
/// Treat destination as a normal file
/// '-T, --no-target-directory
pub no_target_dir: bool,
/// '-v, --verbose'
pub verbose: bool,
/// '--strip-trailing-slashes'
pub strip_slashes: bool,
/// '-g, --progress'
pub progress_bar: bool,
} }
#[derive(Clone, Eq, PartialEq)] /// specifies behavior of the overwrite flag
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum OverwriteMode { pub enum OverwriteMode {
/// '-n' '--no-clobber' do not overwrite
NoClobber, NoClobber,
/// '-i' '--interactive' prompt before overwrite
Interactive, Interactive,
///'-f' '--force' overwrite without prompt
Force, Force,
} }
@ -116,7 +151,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} }
} }
let behavior = Behavior { let opts = Options {
overwrite: overwrite_mode, overwrite: overwrite_mode,
backup: backup_mode, backup: backup_mode,
suffix: backup_suffix, suffix: backup_suffix,
@ -128,7 +163,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
progress_bar: matches.get_flag(OPT_PROGRESS), progress_bar: matches.get_flag(OPT_PROGRESS),
}; };
exec(&files[..], &behavior) mv(&files[..], &opts)
} }
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
@ -235,10 +270,10 @@ fn determine_overwrite_mode(matches: &ArgMatches) -> OverwriteMode {
} }
} }
fn parse_paths(files: &[OsString], b: &Behavior) -> Vec<PathBuf> { fn parse_paths(files: &[OsString], opts: &Options) -> Vec<PathBuf> {
let paths = files.iter().map(Path::new); let paths = files.iter().map(Path::new);
if b.strip_slashes { if opts.strip_slashes {
paths paths
.map(|p| p.components().as_path().to_owned()) .map(|p| p.components().as_path().to_owned())
.collect::<Vec<PathBuf>>() .collect::<Vec<PathBuf>>()
@ -247,8 +282,10 @@ fn parse_paths(files: &[OsString], b: &Behavior) -> Vec<PathBuf> {
} }
} }
fn handle_two_paths(source: &Path, target: &Path, b: &Behavior) -> UResult<()> { fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()> {
if b.backup == BackupMode::SimpleBackup && source_is_target_backup(source, target, &b.suffix) { if opts.backup == BackupMode::SimpleBackup
&& source_is_target_backup(source, target, &opts.suffix)
{
return Err(io::Error::new( return Err(io::Error::new(
io::ErrorKind::NotFound, io::ErrorKind::NotFound,
format!( format!(
@ -266,7 +303,7 @@ fn handle_two_paths(source: &Path, target: &Path, b: &Behavior) -> UResult<()> {
if (source.eq(target) if (source.eq(target)
|| are_hardlinks_to_same_file(source, target) || are_hardlinks_to_same_file(source, target)
|| are_hardlinks_or_one_way_symlink_to_same_file(source, target)) || are_hardlinks_or_one_way_symlink_to_same_file(source, target))
&& b.backup == BackupMode::NoBackup && opts.backup == BackupMode::NoBackup
{ {
if source.eq(Path::new(".")) || source.ends_with("/.") || source.is_file() { if source.eq(Path::new(".")) || source.ends_with("/.") || source.is_file() {
return Err( return Err(
@ -278,19 +315,19 @@ fn handle_two_paths(source: &Path, target: &Path, b: &Behavior) -> UResult<()> {
} }
if target.is_dir() { if target.is_dir() {
if b.no_target_dir { if opts.no_target_dir {
if source.is_dir() { if source.is_dir() {
rename(source, target, b, None).map_err_context(|| { rename(source, target, opts, None).map_err_context(|| {
format!("cannot move {} to {}", source.quote(), target.quote()) format!("cannot move {} to {}", source.quote(), target.quote())
}) })
} else { } else {
Err(MvError::DirectoryToNonDirectory(target.quote().to_string()).into()) Err(MvError::DirectoryToNonDirectory(target.quote().to_string()).into())
} }
} else { } else {
move_files_into_dir(&[source.to_path_buf()], target, b) move_files_into_dir(&[source.to_path_buf()], target, opts)
} }
} else if target.exists() && source.is_dir() { } else if target.exists() && source.is_dir() {
match b.overwrite { match opts.overwrite {
OverwriteMode::NoClobber => return Ok(()), OverwriteMode::NoClobber => return Ok(()),
OverwriteMode::Interactive => { OverwriteMode::Interactive => {
if !prompt_yes!("overwrite {}? ", target.quote()) { if !prompt_yes!("overwrite {}? ", target.quote()) {
@ -305,12 +342,12 @@ fn handle_two_paths(source: &Path, target: &Path, b: &Behavior) -> UResult<()> {
) )
.into()) .into())
} else { } else {
rename(source, target, b, None).map_err(|e| USimpleError::new(1, format!("{e}"))) rename(source, target, opts, None).map_err(|e| USimpleError::new(1, format!("{e}")))
} }
} }
fn handle_multiple_paths(paths: &[PathBuf], b: &Behavior) -> UResult<()> { fn handle_multiple_paths(paths: &[PathBuf], opts: &Options) -> UResult<()> {
if b.no_target_dir { if opts.no_target_dir {
return Err(UUsageError::new( return Err(UUsageError::new(
1, 1,
format!("mv: extra operand {}", paths[2].quote()), format!("mv: extra operand {}", paths[2].quote()),
@ -319,24 +356,27 @@ fn handle_multiple_paths(paths: &[PathBuf], b: &Behavior) -> UResult<()> {
let target_dir = paths.last().unwrap(); let target_dir = paths.last().unwrap();
let sources = &paths[..paths.len() - 1]; let sources = &paths[..paths.len() - 1];
move_files_into_dir(sources, target_dir, b) move_files_into_dir(sources, target_dir, opts)
} }
fn exec(files: &[OsString], b: &Behavior) -> UResult<()> { /// Execute the mv command. This moves 'source' to 'target', where
let paths = parse_paths(files, b); /// 'target' is a directory. If 'target' does not exist, and source is a single
/// file or directory, then 'source' will be renamed to 'target'.
pub fn mv(files: &[OsString], opts: &Options) -> UResult<()> {
let paths = parse_paths(files, opts);
if let Some(ref name) = b.target_dir { if let Some(ref name) = opts.target_dir {
return move_files_into_dir(&paths, &PathBuf::from(name), b); return move_files_into_dir(&paths, &PathBuf::from(name), opts);
} }
match paths.len() { match paths.len() {
2 => handle_two_paths(&paths[0], &paths[1], b), 2 => handle_two_paths(&paths[0], &paths[1], opts),
_ => handle_multiple_paths(&paths, b), _ => handle_multiple_paths(&paths, opts),
} }
} }
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UResult<()> { fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, opts: &Options) -> UResult<()> {
if !target_dir.is_dir() { if !target_dir.is_dir() {
return Err(MvError::NotADirectory(target_dir.quote().to_string()).into()); return Err(MvError::NotADirectory(target_dir.quote().to_string()).into());
} }
@ -345,7 +385,7 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
.canonicalize() .canonicalize()
.unwrap_or_else(|_| target_dir.to_path_buf()); .unwrap_or_else(|_| target_dir.to_path_buf());
let multi_progress = b.progress_bar.then(MultiProgress::new); let multi_progress = opts.progress_bar.then(MultiProgress::new);
let count_progress = if let Some(ref multi_progress) = multi_progress { let count_progress = if let Some(ref multi_progress) = multi_progress {
if files.len() > 1 { if files.len() > 1 {
@ -396,7 +436,7 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
} }
} }
match rename(sourcepath, &targetpath, b, multi_progress.as_ref()) { match rename(sourcepath, &targetpath, opts, multi_progress.as_ref()) {
Err(e) if e.to_string().is_empty() => set_exit_code(1), Err(e) if e.to_string().is_empty() => set_exit_code(1),
Err(e) => { Err(e) => {
let e = e.map_err_context(|| { let e = e.map_err_context(|| {
@ -413,7 +453,6 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
} }
Ok(()) => (), Ok(()) => (),
} }
if let Some(ref pb) = count_progress { if let Some(ref pb) = count_progress {
pb.inc(1); pb.inc(1);
} }
@ -424,29 +463,30 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
fn rename( fn rename(
from: &Path, from: &Path,
to: &Path, to: &Path,
b: &Behavior, opts: &Options,
multi_progress: Option<&MultiProgress>, multi_progress: Option<&MultiProgress>,
) -> io::Result<()> { ) -> io::Result<()> {
let mut backup_path = None; let mut backup_path = None;
if to.exists() { if to.exists() {
if b.update == UpdateMode::ReplaceIfOlder && b.overwrite == OverwriteMode::Interactive { if opts.update == UpdateMode::ReplaceIfOlder && opts.overwrite == OverwriteMode::Interactive
{
// `mv -i --update old new` when `new` exists doesn't move anything // `mv -i --update old new` when `new` exists doesn't move anything
// and exit with 0 // and exit with 0
return Ok(()); return Ok(());
} }
if b.update == UpdateMode::ReplaceNone { if opts.update == UpdateMode::ReplaceNone {
return Ok(()); return Ok(());
} }
if (b.update == UpdateMode::ReplaceIfOlder) if (opts.update == UpdateMode::ReplaceIfOlder)
&& fs::metadata(from)?.modified()? <= fs::metadata(to)?.modified()? && fs::metadata(from)?.modified()? <= fs::metadata(to)?.modified()?
{ {
return Ok(()); return Ok(());
} }
match b.overwrite { match opts.overwrite {
OverwriteMode::NoClobber => { OverwriteMode::NoClobber => {
let err_msg = format!("not replacing {}", to.quote()); let err_msg = format!("not replacing {}", to.quote());
return Err(io::Error::new(io::ErrorKind::Other, err_msg)); return Err(io::Error::new(io::ErrorKind::Other, err_msg));
@ -459,7 +499,7 @@ fn rename(
OverwriteMode::Force => {} OverwriteMode::Force => {}
}; };
backup_path = backup_control::get_backup_path(b.backup, to, &b.suffix); backup_path = backup_control::get_backup_path(opts.backup, to, &opts.suffix);
if let Some(ref backup_path) = backup_path { if let Some(ref backup_path) = backup_path {
rename_with_fallback(to, backup_path, multi_progress)?; rename_with_fallback(to, backup_path, multi_progress)?;
} }
@ -479,7 +519,7 @@ fn rename(
rename_with_fallback(from, to, multi_progress)?; rename_with_fallback(from, to, multi_progress)?;
if b.verbose { if opts.verbose {
let message = match backup_path { let message = match backup_path {
Some(path) => format!( Some(path) => format!(
"renamed {} -> {} (backup: {})", "renamed {} -> {} (backup: {})",

View file

@ -166,6 +166,7 @@ mod tests {
#[test] #[test]
#[allow(clippy::float_cmp)] #[allow(clippy::float_cmp)]
#[allow(clippy::cognitive_complexity)]
fn smoke_test() { fn smoke_test() {
let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xff, 0xff]; let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xff, 0xff];
let mut input = PeekReader::new(Cursor::new(&data)); let mut input = PeekReader::new(Cursor::new(&data));

View file

@ -208,6 +208,7 @@ impl TypeSizeInfo for TypeInfo {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_calculate_alignment() { fn test_calculate_alignment() {
// For this example `byte_size_block` is 8 and 'print_width_block' is 23: // For this example `byte_size_block` is 8 and 'print_width_block' is 23:
// 1777777777777777777777 1777777777777777777777 // 1777777777777777777777 1777777777777777777777

View file

@ -213,6 +213,7 @@ mod tests {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_parse_inputs_with_offset() { fn test_parse_inputs_with_offset() {
// offset is found without filename, so stdin will be used. // offset is found without filename, so stdin will be used.
assert_eq!( assert_eq!(
@ -355,6 +356,7 @@ mod tests {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_parse_offset_operand() { fn test_parse_offset_operand() {
assert_eq!(8, parse_offset_operand_str("10").unwrap()); // default octal assert_eq!(8, parse_offset_operand_str("10").unwrap()); // default octal
assert_eq!(0, parse_offset_operand_str("0").unwrap()); assert_eq!(0, parse_offset_operand_str("0").unwrap());

View file

@ -79,6 +79,7 @@ pub fn parse_number_of_bytes(s: &str) -> Result<u64, ParseSizeError> {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_parse_number_of_bytes() { fn test_parse_number_of_bytes() {
// octal input // octal input
assert_eq!(8, parse_number_of_bytes("010").unwrap()); assert_eq!(8, parse_number_of_bytes("010").unwrap());

View file

@ -186,6 +186,7 @@ mod tests {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_peek_read_with_smaller_buffer() { fn test_peek_read_with_smaller_buffer() {
let mut sut = PeekReader::new(Cursor::new(&b"abcdefghij"[..])); let mut sut = PeekReader::new(Cursor::new(&b"abcdefghij"[..]));

View file

@ -99,6 +99,7 @@ pub fn format_ascii_dump(bytes: &[u8]) -> String {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_format_item_a() { fn test_format_item_a() {
assert_eq!(" nul", format_item_a(0x00)); assert_eq!(" nul", format_item_a(0x00));
assert_eq!(" soh", format_item_a(0x01)); assert_eq!(" soh", format_item_a(0x01));
@ -114,6 +115,7 @@ fn test_format_item_a() {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_format_item_c() { fn test_format_item_c() {
assert_eq!(" \\0", format_item_c(&[0x00])); assert_eq!(" \\0", format_item_c(&[0x00]));
assert_eq!(" 001", format_item_c(&[0x01])); assert_eq!(" 001", format_item_c(&[0x01]));

View file

@ -91,6 +91,7 @@ fn format_float(f: f64, width: usize, precision: usize) -> String {
#[test] #[test]
#[allow(clippy::excessive_precision)] #[allow(clippy::excessive_precision)]
#[allow(clippy::cognitive_complexity)]
fn test_format_flo32() { fn test_format_flo32() {
assert_eq!(format_flo32(1.0), " 1.0000000"); assert_eq!(format_flo32(1.0), " 1.0000000");
assert_eq!(format_flo32(9.9999990), " 9.9999990"); assert_eq!(format_flo32(9.9999990), " 9.9999990");
@ -167,6 +168,7 @@ fn test_format_flo32() {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_format_flo64() { fn test_format_flo64() {
assert_eq!(format_flo64(1.0), " 1.0000000000000000"); assert_eq!(format_flo64(1.0), " 1.0000000000000000");
assert_eq!(format_flo64(10.0), " 10.000000000000000"); assert_eq!(format_flo64(10.0), " 10.000000000000000");

View file

@ -89,6 +89,7 @@ int_writer_signed!(FORMAT_ITEM_DEC32S, 4, 12, format_item_dec_s32, DEC!()); // m
int_writer_signed!(FORMAT_ITEM_DEC64S, 8, 21, format_item_dec_s64, DEC!()); // max: -9223372036854775808 int_writer_signed!(FORMAT_ITEM_DEC64S, 8, 21, format_item_dec_s64, DEC!()); // max: -9223372036854775808
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_sign_extend() { fn test_sign_extend() {
assert_eq!( assert_eq!(
0xffff_ffff_ffff_ff80u64 as i64, 0xffff_ffff_ffff_ff80u64 as i64,
@ -179,6 +180,7 @@ fn test_format_item_dec_u() {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_format_item_dec_s() { fn test_format_item_dec_s() {
assert_eq!(" 0", format_item_dec_s8(0)); assert_eq!(" 0", format_item_dec_s8(0));
assert_eq!(" 127", format_item_dec_s8(0x7f)); assert_eq!(" 127", format_item_dec_s8(0x7f));

View file

@ -1,23 +0,0 @@
[package]
name = "uu_relpath"
version = "0.0.21"
authors = ["uutils developers"]
license = "MIT"
description = "relpath ~ (uutils) display relative path of PATHNAME_TO from PATHNAME_FROM"
homepage = "https://github.com/uutils/coreutils"
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/relpath"
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
categories = ["command-line-utilities"]
edition = "2021"
[lib]
path = "src/relpath.rs"
[dependencies]
clap = { workspace = true }
uucore = { workspace = true, features = ["fs"] }
[[bin]]
name = "relpath"
path = "src/main.rs"

View file

@ -1 +0,0 @@
../../../LICENSE

View file

@ -1,8 +0,0 @@
# relpath
```
relpath [-d DIR] TO [FROM]
```
Convert TO destination to the relative path from the FROM dir.
If FROM path is omitted, current working dir will be used.

View file

@ -1 +0,0 @@
uucore::bin!(uu_relpath);

View file

@ -1,91 +0,0 @@
// 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.
// spell-checker:ignore (ToDO) subpath absto absfrom absbase
use clap::{crate_version, Arg, Command};
use std::env;
use std::path::{Path, PathBuf};
use uucore::display::println_verbatim;
use uucore::error::{FromIo, UResult};
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
use uucore::{format_usage, help_about, help_usage};
const USAGE: &str = help_usage!("relpath.md");
const ABOUT: &str = help_about!("relpath.md");
mod options {
pub const DIR: &str = "DIR";
pub const TO: &str = "TO";
pub const FROM: &str = "FROM";
}
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let args = args.collect_lossy();
let matches = uu_app().get_matches_from(args);
let to = Path::new(matches.get_one::<String>(options::TO).unwrap()).to_path_buf(); // required
let from = match matches.get_one::<String>(options::FROM) {
Some(p) => Path::new(p).to_path_buf(),
None => env::current_dir().unwrap(),
};
let absto = canonicalize(to, MissingHandling::Normal, ResolveMode::Logical)
.map_err_context(String::new)?;
let absfrom = canonicalize(from, MissingHandling::Normal, ResolveMode::Logical)
.map_err_context(String::new)?;
if matches.contains_id(options::DIR) {
let base = Path::new(&matches.get_one::<String>(options::DIR).unwrap()).to_path_buf();
let absbase = canonicalize(base, MissingHandling::Normal, ResolveMode::Logical)
.map_err_context(String::new)?;
if !absto.as_path().starts_with(absbase.as_path())
|| !absfrom.as_path().starts_with(absbase.as_path())
{
return println_verbatim(absto).map_err_context(String::new);
}
}
let mut suffix_pos = 0;
for (f, t) in absfrom.components().zip(absto.components()) {
if f == t {
suffix_pos += 1;
} else {
break;
}
}
let mut result = PathBuf::new();
absfrom
.components()
.skip(suffix_pos)
.map(|_| result.push(".."))
.last();
absto
.components()
.skip(suffix_pos)
.map(|x| result.push(x.as_os_str()))
.last();
println_verbatim(result).map_err_context(String::new)
}
pub fn uu_app() -> Command {
Command::new(uucore::util_name())
.version(crate_version!())
.about(ABOUT)
.override_usage(format_usage(USAGE))
.infer_long_args(true)
.arg(Arg::new(options::DIR).short('d').help(
"If any of FROM and TO is not subpath of DIR, output absolute path instead of relative",
))
.arg(
Arg::new(options::TO)
.value_hint(clap::ValueHint::AnyPath)
.required(true),
)
.arg(Arg::new(options::FROM).value_hint(clap::ValueHint::AnyPath))
}

View file

@ -1714,6 +1714,7 @@ where
Ok(()) Ok(())
} }
#[allow(clippy::cognitive_complexity)]
fn split(settings: &Settings) -> UResult<()> { fn split(settings: &Settings) -> UResult<()> {
let mut reader = BufReader::new(if settings.input == "-" { let mut reader = BufReader::new(if settings.input == "-" {
Box::new(stdin()) as Box<dyn Read> Box::new(stdin()) as Box<dyn Read>

View file

@ -404,6 +404,7 @@ fn print_unsigned_hex(
} }
impl Stater { impl Stater {
#[allow(clippy::cognitive_complexity)]
fn generate_tokens(format_str: &str, use_printf: bool) -> UResult<Vec<Token>> { fn generate_tokens(format_str: &str, use_printf: bool) -> UResult<Vec<Token>> {
let mut tokens = Vec::new(); let mut tokens = Vec::new();
let bound = format_str.len(); let bound = format_str.len();
@ -609,6 +610,7 @@ impl Stater {
ret ret
} }
#[allow(clippy::cognitive_complexity)]
fn do_stat(&self, file: &OsStr, stdin_is_fifo: bool) -> i32 { fn do_stat(&self, file: &OsStr, stdin_is_fifo: bool) -> i32 {
let display_name = file.to_string_lossy(); let display_name = file.to_string_lossy();
let file = if cfg!(unix) && display_name == "-" { let file = if cfg!(unix) && display_name == "-" {

View file

@ -489,7 +489,7 @@ fn pathbuf_from_stdout() -> UResult<PathBuf> {
format!("GetFinalPathNameByHandleW failed with code {ret}"), format!("GetFinalPathNameByHandleW failed with code {ret}"),
)) ))
} }
e if e == 0 => { 0 => {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
format!( format!(

View file

@ -17,23 +17,6 @@ pub enum FieldType {
Charf, Charf,
} }
// #[allow(non_camel_case_types)]
// pub enum FChar {
// d,
// e,
// E,
// i,
// f,
// F,
// g,
// G,
// u,
// x,
// X,
// o
// }
//
// a Sub Tokens' fields are stored // a Sub Tokens' fields are stored
// as a single object so they can be more simply // as a single object so they can be more simply
// passed by ref to num_format in a Sub method // passed by ref to num_format in a Sub method

View file

@ -18,7 +18,6 @@ use std::iter::Peekable;
use std::process::exit; use std::process::exit;
use std::slice::Iter; use std::slice::Iter;
use std::str::Chars; use std::str::Chars;
// use std::collections::HashSet;
use super::num_format::format_field::{FieldType, FormatField}; use super::num_format::format_field::{FieldType, FormatField};
use super::num_format::num_format; use super::num_format::num_format;

View file

@ -1545,7 +1545,6 @@ fn test_cp_preserve_links_case_7() {
.arg("dest") .arg("dest")
.fails() .fails()
.stderr_contains("not replacing"); .stderr_contains("not replacing");
();
assert!(at.dir_exists("dest")); assert!(at.dir_exists("dest"));
assert!(at.plus("dest").join("f").exists()); assert!(at.plus("dest").join("f").exists());

View file

@ -123,6 +123,21 @@ fn test_or() {
.args(&["-14", "|", "1"]) .args(&["-14", "|", "1"])
.succeeds() .succeeds()
.stdout_only("-14\n"); .stdout_only("-14\n");
new_ucmd!()
.args(&["1", "|", "a", "/", "5"])
.succeeds()
.stdout_only("1\n");
new_ucmd!()
.args(&["foo", "|", "a", "/", "5"])
.succeeds()
.stdout_only("foo\n");
new_ucmd!()
.args(&["0", "|", "10", "/", "5"])
.succeeds()
.stdout_only("2\n");
} }
#[test] #[test]

View file

@ -1,189 +0,0 @@
// 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 crate::common::util::TestScenario;
use std::borrow::Cow;
use std::path::Path;
struct TestCase<'a> {
from: &'a str,
to: &'a str,
expected: &'a str,
}
const TESTS: [TestCase; 10] = [
TestCase {
from: "A/B/C",
to: "A",
expected: "../..",
},
TestCase {
from: "A/B/C",
to: "A/B",
expected: "..",
},
TestCase {
from: "A/B/C",
to: "A/B/C",
expected: "",
},
TestCase {
from: "A/B/C",
to: "A/B/C/D",
expected: "D",
},
TestCase {
from: "A/B/C",
to: "A/B/C/D/E",
expected: "D/E",
},
TestCase {
from: "A/B/C",
to: "A/B/D",
expected: "../D",
},
TestCase {
from: "A/B/C",
to: "A/B/D/E",
expected: "../D/E",
},
TestCase {
from: "A/B/C",
to: "A/D",
expected: "../../D",
},
TestCase {
from: "A/B/C",
to: "D/E/F",
expected: "../../../D/E/F",
},
TestCase {
from: "A/B/C",
to: "A/D/E",
expected: "../../D/E",
},
];
#[allow(clippy::needless_lifetimes)]
fn convert_path<'a>(path: &'a str) -> Cow<'a, str> {
#[cfg(windows)]
return path.replace('/', "\\").into();
#[cfg(not(windows))]
return path.into();
}
#[test]
fn test_relpath_with_from_no_d() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
for test in &TESTS {
let from: &str = &convert_path(test.from);
let to: &str = &convert_path(test.to);
let expected: &str = &convert_path(test.expected);
at.mkdir_all(to);
at.mkdir_all(from);
scene
.ucmd()
.arg(to)
.arg(from)
.succeeds()
.stdout_only(&format!("{expected}\n"));
}
}
#[test]
fn test_relpath_with_from_with_d() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
for test in &TESTS {
let from: &str = &convert_path(test.from);
let to: &str = &convert_path(test.to);
let pwd = at.as_string();
at.mkdir_all(to);
at.mkdir_all(from);
// d is part of subpath -> expect relative path
let mut _result_stdout = scene
.ucmd()
.arg(to)
.arg(from)
.arg(&format!("-d{pwd}"))
.succeeds()
.stdout_move_str();
// relax rules for windows test environment
#[cfg(not(windows))]
assert!(Path::new(&_result_stdout).is_relative());
// d is not part of subpath -> expect absolute path
_result_stdout = scene
.ucmd()
.arg(to)
.arg(from)
.arg("-dnon_existing") // spell-checker:disable-line
.succeeds()
.stdout_move_str();
assert!(Path::new(&_result_stdout).is_absolute());
}
}
#[test]
fn test_relpath_no_from_no_d() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
for test in &TESTS {
let to: &str = &convert_path(test.to);
at.mkdir_all(to);
let _result_stdout = scene.ucmd().arg(to).succeeds().stdout_move_str();
#[cfg(not(windows))]
assert_eq!(_result_stdout, format!("{to}\n"));
// relax rules for windows test environment
#[cfg(windows)]
assert!(_result_stdout.ends_with(&format!("{to}\n")));
}
}
#[test]
fn test_relpath_no_from_with_d() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
for test in &TESTS {
let to: &str = &convert_path(test.to);
let pwd = at.as_string();
at.mkdir_all(to);
// d is part of subpath -> expect relative path
let _result_stdout = scene
.ucmd()
.arg(to)
.arg(&format!("-d{pwd}"))
.succeeds()
.stdout_move_str();
// relax rules for windows test environment
#[cfg(not(windows))]
assert!(Path::new(&_result_stdout).is_relative());
// d is not part of subpath -> expect absolute path
let result_stdout = scene
.ucmd()
.arg(to)
.arg("-dnon_existing") // spell-checker:disable-line
.succeeds()
.stdout_move_str();
assert!(Path::new(&result_stdout).is_absolute());
}
}
#[test]
fn test_relpath_no_to() {
new_ucmd!()
.fails()
.stderr_contains("required arguments were not provided");
}

View file

@ -438,7 +438,7 @@ fn test_split_obs_lines_within_combined_shorts() {
let scene = TestScenario::new(util_name!()); let scene = TestScenario::new(util_name!());
let at = &scene.fixtures; let at = &scene.fixtures;
let name = "obs-lines-within-shorts"; let name = "obs-lines-within-shorts";
RandomFile::new(&at, name).add_lines(400); RandomFile::new(at, name).add_lines(400);
scene scene
.ucmd() .ucmd()
@ -446,9 +446,9 @@ fn test_split_obs_lines_within_combined_shorts() {
.succeeds() .succeeds()
.no_stderr() .no_stderr()
.no_stdout(); .no_stdout();
let glob = Glob::new(&at, ".", r"x\d\d$"); let glob = Glob::new(at, ".", r"x\d\d$");
assert_eq!(glob.count(), 2); assert_eq!(glob.count(), 2);
assert_eq!(glob.collate(), at.read_bytes(name)) assert_eq!(glob.collate(), at.read_bytes(name));
} }
/// Test for obsolete lines option as part of combined short options with tailing suffix length with value /// Test for obsolete lines option as part of combined short options with tailing suffix length with value
@ -470,7 +470,7 @@ fn test_split_obs_lines_starts_combined_shorts() {
let scene = TestScenario::new(util_name!()); let scene = TestScenario::new(util_name!());
let at = &scene.fixtures; let at = &scene.fixtures;
let name = "obs-lines-starts-shorts"; let name = "obs-lines-starts-shorts";
RandomFile::new(&at, name).add_lines(400); RandomFile::new(at, name).add_lines(400);
scene scene
.ucmd() .ucmd()
@ -478,9 +478,9 @@ fn test_split_obs_lines_starts_combined_shorts() {
.succeeds() .succeeds()
.no_stderr() .no_stderr()
.no_stdout(); .no_stdout();
let glob = Glob::new(&at, ".", r"x\d\d$"); let glob = Glob::new(at, ".", r"x\d\d$");
assert_eq!(glob.count(), 2); assert_eq!(glob.count(), 2);
assert_eq!(glob.collate(), at.read_bytes(name)) assert_eq!(glob.collate(), at.read_bytes(name));
} }
/// Test for using both obsolete lines (standalone) option and short/long lines option simultaneously /// Test for using both obsolete lines (standalone) option and short/long lines option simultaneously
@ -585,7 +585,7 @@ fn test_split_multiple_obs_lines_standalone() {
let scene = TestScenario::new(util_name!()); let scene = TestScenario::new(util_name!());
let at = &scene.fixtures; let at = &scene.fixtures;
let name = "multiple-obs-lines"; let name = "multiple-obs-lines";
RandomFile::new(&at, name).add_lines(400); RandomFile::new(at, name).add_lines(400);
scene scene
.ucmd() .ucmd()
@ -593,9 +593,9 @@ fn test_split_multiple_obs_lines_standalone() {
.succeeds() .succeeds()
.no_stderr() .no_stderr()
.no_stdout(); .no_stdout();
let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$"); let glob = Glob::new(at, ".", r"x[[:alpha:]][[:alpha:]]$");
assert_eq!(glob.count(), 2); assert_eq!(glob.count(), 2);
assert_eq!(glob.collate(), at.read_bytes(name)) assert_eq!(glob.collate(), at.read_bytes(name));
} }
/// Test for using more than one obsolete lines option within combined shorts /// Test for using more than one obsolete lines option within combined shorts
@ -605,7 +605,7 @@ fn test_split_multiple_obs_lines_within_combined() {
let scene = TestScenario::new(util_name!()); let scene = TestScenario::new(util_name!());
let at = &scene.fixtures; let at = &scene.fixtures;
let name = "multiple-obs-lines"; let name = "multiple-obs-lines";
RandomFile::new(&at, name).add_lines(400); RandomFile::new(at, name).add_lines(400);
scene scene
.ucmd() .ucmd()
@ -613,9 +613,9 @@ fn test_split_multiple_obs_lines_within_combined() {
.succeeds() .succeeds()
.no_stderr() .no_stderr()
.no_stdout(); .no_stdout();
let glob = Glob::new(&at, ".", r"x\d\d$"); let glob = Glob::new(at, ".", r"x\d\d$");
assert_eq!(glob.count(), 2); assert_eq!(glob.count(), 2);
assert_eq!(glob.collate(), at.read_bytes(name)) assert_eq!(glob.collate(), at.read_bytes(name));
} }
/// Test for using both obsolete lines option within combined shorts with conflicting -n option simultaneously /// Test for using both obsolete lines option within combined shorts with conflicting -n option simultaneously
@ -1543,8 +1543,8 @@ fn test_split_separator_nul_lines() {
ucmd.args(&["--lines=2", "-t", "\\0", "separator_nul.txt"]) ucmd.args(&["--lines=2", "-t", "\\0", "separator_nul.txt"])
.succeeds(); .succeeds();
assert_eq!(file_read(&at, "xaa"), "1\02\0"); assert_eq!(file_read(&at, "xaa"), "1\x002\0");
assert_eq!(file_read(&at, "xab"), "3\04\0"); assert_eq!(file_read(&at, "xab"), "3\x004\0");
assert_eq!(file_read(&at, "xac"), "5\0"); assert_eq!(file_read(&at, "xac"), "5\0");
assert!(!at.plus("xad").exists()); assert!(!at.plus("xad").exists());
} }
@ -1555,8 +1555,8 @@ fn test_split_separator_nul_line_bytes() {
ucmd.args(&["--line-bytes=4", "-t", "\\0", "separator_nul.txt"]) ucmd.args(&["--line-bytes=4", "-t", "\\0", "separator_nul.txt"])
.succeeds(); .succeeds();
assert_eq!(file_read(&at, "xaa"), "1\02\0"); assert_eq!(file_read(&at, "xaa"), "1\x002\0");
assert_eq!(file_read(&at, "xab"), "3\04\0"); assert_eq!(file_read(&at, "xab"), "3\x004\0");
assert_eq!(file_read(&at, "xac"), "5\0"); assert_eq!(file_read(&at, "xac"), "5\0");
assert!(!at.plus("xad").exists()); assert!(!at.plus("xad").exists());
} }
@ -1567,8 +1567,8 @@ fn test_split_separator_nul_number_l() {
ucmd.args(&["--number=l/3", "--separator=\\0", "separator_nul.txt"]) ucmd.args(&["--number=l/3", "--separator=\\0", "separator_nul.txt"])
.succeeds(); .succeeds();
assert_eq!(file_read(&at, "xaa"), "1\02\0"); assert_eq!(file_read(&at, "xaa"), "1\x002\0");
assert_eq!(file_read(&at, "xab"), "3\04\0"); assert_eq!(file_read(&at, "xab"), "3\x004\0");
assert_eq!(file_read(&at, "xac"), "5\0"); assert_eq!(file_read(&at, "xac"), "5\0");
assert!(!at.plus("xad").exists()); assert!(!at.plus("xad").exists());
} }
@ -1579,8 +1579,8 @@ fn test_split_separator_nul_number_r() {
ucmd.args(&["--number=r/3", "--separator=\\0", "separator_nul.txt"]) ucmd.args(&["--number=r/3", "--separator=\\0", "separator_nul.txt"])
.succeeds(); .succeeds();
assert_eq!(file_read(&at, "xaa"), "1\04\0"); assert_eq!(file_read(&at, "xaa"), "1\x004\0");
assert_eq!(file_read(&at, "xab"), "2\05\0"); assert_eq!(file_read(&at, "xab"), "2\x005\0");
assert_eq!(file_read(&at, "xac"), "3\0"); assert_eq!(file_read(&at, "xac"), "3\0");
assert!(!at.plus("xad").exists()); assert!(!at.plus("xad").exists());
} }

View file

@ -3,6 +3,7 @@
// 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 crate::common::util::TestScenario; use crate::common::util::TestScenario;
use std::fmt::Write;
// tests for basic tee functionality. // tests for basic tee functionality.
// inspired by: // inspired by:
@ -74,7 +75,10 @@ fn test_tee_append() {
fn test_tee_no_more_writeable_1() { fn test_tee_no_more_writeable_1() {
// equals to 'tee /dev/full out2 <multi_read' call // equals to 'tee /dev/full out2 <multi_read' call
let (at, mut ucmd) = at_and_ucmd!(); let (at, mut ucmd) = at_and_ucmd!();
let content = (1..=10).map(|x| format!("{x}\n")).collect::<String>(); let content = (1..=10).fold(String::new(), |mut output, x| {
let _ = writeln!(output, "{x}");
output
});
let file_out = "tee_file_out"; let file_out = "tee_file_out";
ucmd.arg("/dev/full") ucmd.arg("/dev/full")
@ -94,7 +98,10 @@ fn test_tee_no_more_writeable_2() {
// but currently there is no way to redirect stdout to /dev/full // but currently there is no way to redirect stdout to /dev/full
// so this test is disabled // so this test is disabled
let (_at, mut ucmd) = at_and_ucmd!(); let (_at, mut ucmd) = at_and_ucmd!();
let _content = (1..=10).map(|x| format!("{x}\n")).collect::<String>(); let _content = (1..=10).fold(String::new(), |mut output, x| {
let _ = writeln!(output, "{x}");
output
});
let file_out_a = "tee_file_out_a"; let file_out_a = "tee_file_out_a";
let file_out_b = "tee_file_out_b"; let file_out_b = "tee_file_out_b";
@ -114,6 +121,7 @@ fn test_tee_no_more_writeable_2() {
mod linux_only { mod linux_only {
use crate::common::util::{AtPath, TestScenario, UCommand}; use crate::common::util::{AtPath, TestScenario, UCommand};
use std::fmt::Write;
use std::fs::File; use std::fs::File;
use std::process::{Output, Stdio}; use std::process::{Output, Stdio};
@ -135,7 +143,10 @@ mod linux_only {
} }
fn run_tee(proc: &mut UCommand) -> (String, Output) { fn run_tee(proc: &mut UCommand) -> (String, Output) {
let content = (1..=100_000).map(|x| format!("{x}\n")).collect::<String>(); let content = (1..=100_000).fold(String::new(), |mut output, x| {
let _ = writeln!(output, "{x}");
output
});
#[allow(deprecated)] #[allow(deprecated)]
let output = proc let output = proc

View file

@ -269,10 +269,6 @@ mod test_readlink;
#[path = "by-util/test_realpath.rs"] #[path = "by-util/test_realpath.rs"]
mod test_realpath; mod test_realpath;
#[cfg(feature = "relpath")]
#[path = "by-util/test_relpath.rs"]
mod test_relpath;
#[cfg(feature = "rm")] #[cfg(feature = "rm")]
#[path = "by-util/test_rm.rs"] #[path = "by-util/test_rm.rs"]
mod test_rm; mod test_rm;

View file

@ -2,7 +2,7 @@
@echo off @echo off
@rem ::# spell-checker:ignore (CMD) ERRORLEVEL @rem ::# spell-checker:ignore (CMD) ERRORLEVEL
@rem ::# spell-checker:ignore (utils) cksum coreutils dircolors hashsum mkdir mktemp printenv printf readlink realpath relpath rmdir shuf tsort unexpand @rem ::# spell-checker:ignore (utils) cksum coreutils dircolors hashsum mkdir mktemp printenv printf readlink realpath rmdir shuf tsort unexpand
@rem ::# spell-checker:ignore (jq) deps startswith @rem ::# spell-checker:ignore (jq) deps startswith
set "ME=%~0" set "ME=%~0"
@ -12,7 +12,7 @@ set "ME_parent_dir=%~dp0.\.."
@rem refs: <https://forge.rust-lang.org/release/platform-support.html> , <https://docs.rs/platforms/0.2.1/platforms/platform/tier1/index.html> @rem refs: <https://forge.rust-lang.org/release/platform-support.html> , <https://docs.rs/platforms/0.2.1/platforms/platform/tier1/index.html>
@rem :: default ("Tier 1" cross-platform) utility list @rem :: default ("Tier 1" cross-platform) utility list
set "default_utils=base32 base64 basename cat cksum comm cp cut date dircolors dirname echo env expand expr factor false fmt fold hashsum head join link ln ls mkdir mktemp more mv nl od paste printenv printf ptx pwd readlink realpath relpath rm rmdir seq shred shuf sleep sort split sum tac tail tee test tr true truncate tsort unexpand uniq wc yes" set "default_utils=base32 base64 basename cat cksum comm cp cut date dircolors dirname echo env expand expr factor false fmt fold hashsum head join link ln ls mkdir mktemp more mv nl od paste printenv printf ptx pwd readlink realpath rm rmdir seq shred shuf sleep sort split sum tac tail tee test tr true truncate tsort unexpand uniq wc yes"
set "project_dir=%ME_parent_dir%" set "project_dir=%ME_parent_dir%"
cd "%project_dir%" cd "%project_dir%"

View file

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# spell-checker:ignore (utils) cksum coreutils dircolors hashsum mkdir mktemp printenv printf readlink realpath relpath rmdir shuf tsort unexpand # spell-checker:ignore (utils) cksum coreutils dircolors hashsum mkdir mktemp printenv printf readlink realpath rmdir shuf tsort unexpand
# spell-checker:ignore (jq) deps startswith # spell-checker:ignore (jq) deps startswith
ME="${0}" ME="${0}"
@ -12,7 +12,7 @@ ME_parent_dir_abs="$(realpath -mP -- "${ME_parent_dir}" || realpath -- "${ME_par
# refs: <https://forge.rust-lang.org/release/platform-support.html> , <https://docs.rs/platforms/0.2.1/platforms/platform/tier1/index.html> # refs: <https://forge.rust-lang.org/release/platform-support.html> , <https://docs.rs/platforms/0.2.1/platforms/platform/tier1/index.html>
# default ("Tier 1" cross-platform) utility list # default ("Tier 1" cross-platform) utility list
default_utils="base32 base64 basename cat cksum comm cp cut date dircolors dirname echo env expand expr factor false fmt fold hashsum head join link ln ls mkdir mktemp more mv nl od paste printenv printf ptx pwd readlink realpath relpath rm rmdir seq shred shuf sleep sort split sum tac tail tee test tr true truncate tsort unexpand uniq wc yes" default_utils="base32 base64 basename cat cksum comm cp cut date dircolors dirname echo env expand expr factor false fmt fold hashsum head join link ln ls mkdir mktemp more mv nl od paste printenv printf ptx pwd readlink realpath rm rmdir seq shred shuf sleep sort split sum tac tail tee test tr true truncate tsort unexpand uniq wc yes"
project_main_dir="${ME_parent_dir_abs}" project_main_dir="${ME_parent_dir_abs}"
# printf 'project_main_dir="%s"\n' "${project_main_dir}" # printf 'project_main_dir="%s"\n' "${project_main_dir}"