1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 20:17:45 +00:00

Merge branch 'master' into refactoring_parse_size

This commit is contained in:
Jan Scheer 2021-06-09 13:44:40 +02:00
commit be8650278b
76 changed files with 419 additions and 330 deletions

View file

@ -5,7 +5,7 @@ name: CICD
# spell-checker:ignore (jargon) SHAs deps softprops toolchain # spell-checker:ignore (jargon) SHAs deps softprops toolchain
# spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy # spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy
# spell-checker:ignore (shell/tools) choco clippy dmake dpkg esac fakeroot gmake grcov halium lcov libssl mkdir popd printf pushd rustc rustfmt rustup shopt xargs # spell-checker:ignore (shell/tools) choco clippy dmake dpkg esac fakeroot gmake grcov halium lcov libssl mkdir popd printf pushd rustc rustfmt rustup shopt xargs
# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend tempfile testsuite uutils # spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend runtest tempfile testsuite uutils
env: env:
PROJECT_NAME: coreutils PROJECT_NAME: coreutils
@ -32,12 +32,12 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## VARs setup
outputs() { for var in "$@" ; do echo steps.vars.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; }
# target-specific options # target-specific options
# * CARGO_FEATURES_OPTION # * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ; CARGO_FEATURES_OPTION='' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
echo set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION} outputs CARGO_FEATURES_OPTION
echo ::set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
- name: Install `rust` toolchain - name: Install `rust` toolchain
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -93,12 +93,12 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## VARs setup
outputs() { for var in "$@" ; do echo steps.vars.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; }
# target-specific options # target-specific options
# * CARGO_FEATURES_OPTION # * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ; CARGO_FEATURES_OPTION='' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
echo set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION} outputs CARGO_FEATURES_OPTION
echo ::set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
- name: Install `rust` toolchain - name: Install `rust` toolchain
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -197,7 +197,11 @@ jobs:
run: | run: |
bindir=$(pwd)/target/debug bindir=$(pwd)/target/debug
cd tmp/busybox-*/testsuite cd tmp/busybox-*/testsuite
S=$(bindir=$bindir ./runtest) && printf "%s\n" "$S" || { printf "%s\n" "$S" | grep "FAIL:" | sed -e "s/FAIL: /::warning ::Test failure:/g" ; } ## S=$(bindir=$bindir ./runtest) && printf "%s\n" "$S" || { printf "%s\n" "$S" | grep "FAIL:" | sed -e "s/FAIL: /::warning ::Test failure:/g" ; }
output=$(bindir=$bindir ./runtest 2>&1 || true)
printf "%s\n" "${output}"
n_fails=$(echo "$output" | grep "^FAIL:\s" | wc --lines)
if [ $n_fails -gt 0 ] ; then echo "::warning ::${n_fails}+ test failures" ; fi
makefile_build: makefile_build:
name: Test the build target of the Makefile name: Test the build target of the Makefile
@ -261,22 +265,20 @@ jobs:
shell: bash shell: bash
run: | run: |
## VARs setup ## VARs setup
outputs() { for var in "$@" ; do echo steps.vars.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; }
# toolchain # toolchain
TOOLCHAIN="stable" ## default to "stable" toolchain TOOLCHAIN="stable" ## default to "stable" toolchain
# * specify alternate/non-default TOOLCHAIN for *-pc-windows-gnu targets; gnu targets on Windows are broken for the standard *-pc-windows-msvc toolchain (refs: GH:rust-lang/rust#47048, GH:rust-lang/rust#53454, GH:rust-lang/cargo#6754) # * specify alternate/non-default TOOLCHAIN for *-pc-windows-gnu targets; gnu targets on Windows are broken for the standard *-pc-windows-msvc toolchain (refs: GH:rust-lang/rust#47048, GH:rust-lang/rust#53454, GH:rust-lang/cargo#6754)
case ${{ matrix.job.target }} in *-pc-windows-gnu) TOOLCHAIN="stable-${{ matrix.job.target }}" ;; esac; case ${{ matrix.job.target }} in *-pc-windows-gnu) TOOLCHAIN="stable-${{ matrix.job.target }}" ;; esac;
# * use requested TOOLCHAIN if specified # * use requested TOOLCHAIN if specified
if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi
echo set-output name=TOOLCHAIN::${TOOLCHAIN:-<empty>/false} outputs TOOLCHAIN
echo ::set-output name=TOOLCHAIN::${TOOLCHAIN}
# staging directory # staging directory
STAGING='_staging' STAGING='_staging'
echo set-output name=STAGING::${STAGING} outputs STAGING
echo ::set-output name=STAGING::${STAGING}
# determine EXE suffix # determine EXE suffix
EXE_suffix="" ; case '${{ matrix.job.target }}' in *-pc-windows-*) EXE_suffix=".exe" ;; esac; EXE_suffix="" ; case '${{ matrix.job.target }}' in *-pc-windows-*) EXE_suffix=".exe" ;; esac;
echo set-output name=EXE_suffix::${EXE_suffix} outputs EXE_suffix
echo ::set-output name=EXE_suffix::${EXE_suffix}
# parse commit reference info # parse commit reference info
echo GITHUB_REF=${GITHUB_REF} echo GITHUB_REF=${GITHUB_REF}
echo GITHUB_SHA=${GITHUB_SHA} echo GITHUB_SHA=${GITHUB_SHA}
@ -284,14 +286,7 @@ jobs:
unset REF_BRANCH ; case "${GITHUB_REF}" in refs/heads/*) REF_BRANCH=${GITHUB_REF#refs/heads/} ;; esac; unset REF_BRANCH ; case "${GITHUB_REF}" in refs/heads/*) REF_BRANCH=${GITHUB_REF#refs/heads/} ;; esac;
unset REF_TAG ; case "${GITHUB_REF}" in refs/tags/*) REF_TAG=${GITHUB_REF#refs/tags/} ;; esac; unset REF_TAG ; case "${GITHUB_REF}" in refs/tags/*) REF_TAG=${GITHUB_REF#refs/tags/} ;; esac;
REF_SHAS=${GITHUB_SHA:0:8} REF_SHAS=${GITHUB_SHA:0:8}
echo set-output name=REF_NAME::${REF_NAME} outputs REF_NAME REF_BRANCH REF_TAG REF_SHAS
echo set-output name=REF_BRANCH::${REF_BRANCH}
echo set-output name=REF_TAG::${REF_TAG}
echo set-output name=REF_SHAS::${REF_SHAS}
echo ::set-output name=REF_NAME::${REF_NAME}
echo ::set-output name=REF_BRANCH::${REF_BRANCH}
echo ::set-output name=REF_TAG::${REF_TAG}
echo ::set-output name=REF_SHAS::${REF_SHAS}
# parse target # parse target
unset TARGET_ARCH unset TARGET_ARCH
case '${{ matrix.job.target }}' in case '${{ matrix.job.target }}' in
@ -301,68 +296,50 @@ jobs:
i686-*) TARGET_ARCH=i686 ;; i686-*) TARGET_ARCH=i686 ;;
x86_64-*) TARGET_ARCH=x86_64 ;; x86_64-*) TARGET_ARCH=x86_64 ;;
esac; esac;
echo set-output name=TARGET_ARCH::${TARGET_ARCH}
echo ::set-output name=TARGET_ARCH::${TARGET_ARCH}
unset TARGET_OS ; case '${{ matrix.job.target }}' in *-linux-*) TARGET_OS=linux ;; *-apple-*) TARGET_OS=macos ;; *-windows-*) TARGET_OS=windows ;; esac; unset TARGET_OS ; case '${{ matrix.job.target }}' in *-linux-*) TARGET_OS=linux ;; *-apple-*) TARGET_OS=macos ;; *-windows-*) TARGET_OS=windows ;; esac;
echo set-output name=TARGET_OS::${TARGET_OS} outputs TARGET_ARCH TARGET_OS
echo ::set-output name=TARGET_OS::${TARGET_OS}
# package name # package name
PKG_suffix=".tar.gz" ; case '${{ matrix.job.target }}' in *-pc-windows-*) PKG_suffix=".zip" ;; esac; PKG_suffix=".tar.gz" ; case '${{ matrix.job.target }}' in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
PKG_BASENAME=${PROJECT_NAME}-${REF_TAG:-$REF_SHAS}-${{ matrix.job.target }} PKG_BASENAME=${PROJECT_NAME}-${REF_TAG:-$REF_SHAS}-${{ matrix.job.target }}
PKG_NAME=${PKG_BASENAME}${PKG_suffix} PKG_NAME=${PKG_BASENAME}${PKG_suffix}
echo set-output name=PKG_suffix::${PKG_suffix} outputs PKG_suffix PKG_BASENAME PKG_NAME
echo set-output name=PKG_BASENAME::${PKG_BASENAME}
echo set-output name=PKG_NAME::${PKG_NAME}
echo ::set-output name=PKG_suffix::${PKG_suffix}
echo ::set-output name=PKG_BASENAME::${PKG_BASENAME}
echo ::set-output name=PKG_NAME::${PKG_NAME}
# deployable tag? (ie, leading "vM" or "M"; M == version number) # deployable tag? (ie, leading "vM" or "M"; M == version number)
unset DEPLOY ; if [[ $REF_TAG =~ ^[vV]?[0-9].* ]]; then DEPLOY='true' ; fi unset DEPLOY ; if [[ $REF_TAG =~ ^[vV]?[0-9].* ]]; then DEPLOY='true' ; fi
echo set-output name=DEPLOY::${DEPLOY:-<empty>/false} outputs DEPLOY
echo ::set-output name=DEPLOY::${DEPLOY}
# DPKG architecture? # DPKG architecture?
unset DPKG_ARCH unset DPKG_ARCH
case ${{ matrix.job.target }} in case ${{ matrix.job.target }} in
x86_64-*-linux-*) DPKG_ARCH=amd64 ;; x86_64-*-linux-*) DPKG_ARCH=amd64 ;;
*-linux-*) DPKG_ARCH=${TARGET_ARCH} ;; *-linux-*) DPKG_ARCH=${TARGET_ARCH} ;;
esac esac
echo set-output name=DPKG_ARCH::${DPKG_ARCH} outputs DPKG_ARCH
echo ::set-output name=DPKG_ARCH::${DPKG_ARCH}
# DPKG version? # DPKG version?
unset DPKG_VERSION ; if [[ $REF_TAG =~ ^[vV]?[0-9].* ]]; then DPKG_VERSION=${REF_TAG/#[vV]/} ; fi unset DPKG_VERSION ; if [[ $REF_TAG =~ ^[vV]?[0-9].* ]]; then DPKG_VERSION=${REF_TAG/#[vV]/} ; fi
echo set-output name=DPKG_VERSION::${DPKG_VERSION} outputs DPKG_VERSION
echo ::set-output name=DPKG_VERSION::${DPKG_VERSION}
# DPKG base name/conflicts? # DPKG base name/conflicts?
DPKG_BASENAME=${PROJECT_NAME} DPKG_BASENAME=${PROJECT_NAME}
DPKG_CONFLICTS=${PROJECT_NAME}-musl DPKG_CONFLICTS=${PROJECT_NAME}-musl
case ${{ matrix.job.target }} in *-musl) DPKG_BASENAME=${PROJECT_NAME}-musl ; DPKG_CONFLICTS=${PROJECT_NAME} ;; esac; case ${{ matrix.job.target }} in *-musl) DPKG_BASENAME=${PROJECT_NAME}-musl ; DPKG_CONFLICTS=${PROJECT_NAME} ;; esac;
echo set-output name=DPKG_BASENAME::${DPKG_BASENAME} outputs DPKG_BASENAME DPKG_CONFLICTS
echo set-output name=DPKG_CONFLICTS::${DPKG_CONFLICTS}
echo ::set-output name=DPKG_BASENAME::${DPKG_BASENAME}
echo ::set-output name=DPKG_CONFLICTS::${DPKG_CONFLICTS}
# DPKG name # DPKG name
unset DPKG_NAME; unset DPKG_NAME;
if [[ -n $DPKG_ARCH && -n $DPKG_VERSION ]]; then DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb" ; fi if [[ -n $DPKG_ARCH && -n $DPKG_VERSION ]]; then DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb" ; fi
echo set-output name=DPKG_NAME::${DPKG_NAME} outputs DPKG_NAME
echo ::set-output name=DPKG_NAME::${DPKG_NAME}
# target-specific options # target-specific options
# * CARGO_FEATURES_OPTION # * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='' ; CARGO_FEATURES_OPTION='' ;
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
echo set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION} outputs CARGO_FEATURES_OPTION
echo ::set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
# * CARGO_USE_CROSS (truthy) # * CARGO_USE_CROSS (truthy)
CARGO_USE_CROSS='true' ; case '${{ matrix.job.use-cross }}' in ''|0|f|false|n|no) unset CARGO_USE_CROSS ;; esac; CARGO_USE_CROSS='true' ; case '${{ matrix.job.use-cross }}' in ''|0|f|false|n|no) unset CARGO_USE_CROSS ;; esac;
echo set-output name=CARGO_USE_CROSS::${CARGO_USE_CROSS:-<empty>/false} outputs CARGO_USE_CROSS
echo ::set-output name=CARGO_USE_CROSS::${CARGO_USE_CROSS}
# ** pass needed environment into `cross` container (iff `cross` not already configured via "Cross.toml") # ** pass needed environment into `cross` container (iff `cross` not already configured via "Cross.toml")
if [ -n "${CARGO_USE_CROSS}" ] && [ ! -e "Cross.toml" ] ; then if [ -n "${CARGO_USE_CROSS}" ] && [ ! -e "Cross.toml" ] ; then
printf "[build.env]\npassthrough = [\"CI\"]\n" > Cross.toml printf "[build.env]\npassthrough = [\"CI\"]\n" > Cross.toml
fi fi
# * test only library and/or binaries for arm-type targets # * test only library and/or binaries for arm-type targets
unset CARGO_TEST_OPTIONS ; case '${{ matrix.job.target }}' in aarch64-* | arm-*) CARGO_TEST_OPTIONS="--bins" ;; esac; unset CARGO_TEST_OPTIONS ; case '${{ matrix.job.target }}' in aarch64-* | arm-*) CARGO_TEST_OPTIONS="--bins" ;; esac;
echo set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS} outputs CARGO_TEST_OPTIONS
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
# * executable for `strip`? # * executable for `strip`?
STRIP="strip" STRIP="strip"
case ${{ matrix.job.target }} in case ${{ matrix.job.target }} in
@ -370,8 +347,7 @@ jobs:
arm-*-linux-gnueabihf) STRIP="arm-linux-gnueabihf-strip" ;; arm-*-linux-gnueabihf) STRIP="arm-linux-gnueabihf-strip" ;;
*-pc-windows-msvc) STRIP="" ;; *-pc-windows-msvc) STRIP="" ;;
esac; esac;
echo set-output name=STRIP::${STRIP:-<empty>/false} outputs STRIP
echo ::set-output name=STRIP::${STRIP}
- name: Create all needed build/work directories - name: Create all needed build/work directories
shell: bash shell: bash
run: | run: |
@ -395,11 +371,12 @@ jobs:
shell: bash shell: bash
run: | run: |
## Dependent VARs setup ## Dependent VARs setup
outputs() { for var in "$@" ; do echo steps.vars.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; }
# * determine sub-crate utility list # * determine sub-crate utility list
UTILITY_LIST="$(./util/show-utils.sh ${CARGO_FEATURES_OPTION})" 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 "-puu_${u}"; done;)" CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo "-puu_${u}"; done;)"
echo set-output name=UTILITY_LIST::${UTILITY_LIST} outputs CARGO_UTILITY_LIST_OPTIONS
echo ::set-output name=CARGO_UTILITY_LIST_OPTIONS::${CARGO_UTILITY_LIST_OPTIONS}
- name: Install `cargo-tree` # for dependency information - name: Install `cargo-tree` # for dependency information
uses: actions-rs/install@v0.1 uses: actions-rs/install@v0.1
with: with:
@ -524,34 +501,31 @@ jobs:
id: vars id: vars
shell: bash shell: bash
run: | run: |
## VARs setup
outputs() { for var in "$@" ; do echo steps.vars.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; }
# toolchain # toolchain
TOOLCHAIN="nightly-${{ env.RUST_COV_SRV }}" ## default to "nightly" toolchain (required for certain required unstable compiler flags) ## !maint: refactor when stable channel has needed support TOOLCHAIN="nightly-${{ env.RUST_COV_SRV }}" ## default to "nightly" toolchain (required for certain required unstable compiler flags) ## !maint: refactor when stable channel has needed support
# * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files # * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files
case ${{ matrix.job.os }} in windows-*) TOOLCHAIN="$TOOLCHAIN-x86_64-pc-windows-gnu" ;; esac; case ${{ matrix.job.os }} in windows-*) TOOLCHAIN="$TOOLCHAIN-x86_64-pc-windows-gnu" ;; esac;
# * use requested TOOLCHAIN if specified # * use requested TOOLCHAIN if specified
if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi
echo set-output name=TOOLCHAIN::${TOOLCHAIN} outputs TOOLCHAIN
echo ::set-output name=TOOLCHAIN::${TOOLCHAIN}
# staging directory # staging directory
STAGING='_staging' STAGING='_staging'
echo set-output name=STAGING::${STAGING} outputs STAGING
echo ::set-output name=STAGING::${STAGING}
## # check for CODECOV_TOKEN availability (work-around for inaccessible 'secrets' object for 'if'; see <https://github.community/t5/GitHub-Actions/jobs-lt-job-id-gt-if-does-not-work-with-env-secrets/m-p/38549>) ## # check for CODECOV_TOKEN availability (work-around for inaccessible 'secrets' object for 'if'; see <https://github.community/t5/GitHub-Actions/jobs-lt-job-id-gt-if-does-not-work-with-env-secrets/m-p/38549>)
## # note: CODECOV_TOKEN / HAS_CODECOV_TOKEN is not needed for public repositories when using AppVeyor, Azure Pipelines, CircleCI, GitHub Actions, Travis (see <https://docs.codecov.io/docs/about-the-codecov-bash-uploader#section-upload-token>) ## # note: CODECOV_TOKEN / HAS_CODECOV_TOKEN is not needed for public repositories when using AppVeyor, Azure Pipelines, CircleCI, GitHub Actions, Travis (see <https://docs.codecov.io/docs/about-the-codecov-bash-uploader#section-upload-token>)
## unset HAS_CODECOV_TOKEN ## unset HAS_CODECOV_TOKEN
## if [ -n $CODECOV_TOKEN ]; then HAS_CODECOV_TOKEN='true' ; fi ## if [ -n $CODECOV_TOKEN ]; then HAS_CODECOV_TOKEN='true' ; fi
## echo set-output name=HAS_CODECOV_TOKEN::${HAS_CODECOV_TOKEN} ## outputs HAS_CODECOV_TOKEN
## echo ::set-output name=HAS_CODECOV_TOKEN::${HAS_CODECOV_TOKEN}
# target-specific options # target-specific options
# * CARGO_FEATURES_OPTION # * CARGO_FEATURES_OPTION
CARGO_FEATURES_OPTION='--all-features' ; ## default to '--all-features' for code coverage CARGO_FEATURES_OPTION='--all-features' ; ## default to '--all-features' for code coverage
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
echo set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION} outputs CARGO_FEATURES_OPTION
echo ::set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
# * CODECOV_FLAGS # * CODECOV_FLAGS
CODECOV_FLAGS=$( echo "${{ matrix.job.os }}" | sed 's/[^[:alnum:]]/_/g' ) CODECOV_FLAGS=$( echo "${{ matrix.job.os }}" | sed 's/[^[:alnum:]]/_/g' )
echo set-output name=CODECOV_FLAGS::${CODECOV_FLAGS} outputs CODECOV_FLAGS
echo ::set-output name=CODECOV_FLAGS::${CODECOV_FLAGS}
- name: rust toolchain ~ install - name: rust toolchain ~ install
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -563,11 +537,11 @@ jobs:
shell: bash shell: bash
run: | run: |
## Dependent VARs setup ## Dependent VARs setup
outputs() { for var in "$@" ; do echo steps.vars.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; }
# * determine sub-crate utility list # * determine sub-crate utility list
UTILITY_LIST="$(./util/show-utils.sh ${CARGO_FEATURES_OPTION})" UTILITY_LIST="$(./util/show-utils.sh ${CARGO_FEATURES_OPTION})"
CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo "-puu_${u}"; done;)" CARGO_UTILITY_LIST_OPTIONS="$(for u in ${UTILITY_LIST}; do echo "-puu_${u}"; done;)"
echo set-output name=UTILITY_LIST::${UTILITY_LIST} outputs CARGO_UTILITY_LIST_OPTIONS
echo ::set-output name=CARGO_UTILITY_LIST_OPTIONS::${CARGO_UTILITY_LIST_OPTIONS}
- name: Test uucore - name: Test uucore
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@ -606,7 +580,7 @@ jobs:
with: with:
crate: grcov crate: grcov
version: latest version: latest
use-tool-cache: true use-tool-cache: false
- name: Generate coverage data (via `grcov`) - name: Generate coverage data (via `grcov`)
id: coverage id: coverage
shell: bash shell: bash

View file

@ -97,6 +97,9 @@ Michael Debertol
Michael Gehring Michael Gehring
Michael Michael
Gehring Gehring
Mitchell Mebane
Mitchell
Mebane
Morten Olsen Lysgaard Morten Olsen Lysgaard
Morten Morten
Olsen Olsen

View file

@ -7,6 +7,7 @@ advapi
advapi32-sys advapi32-sys
aho-corasick aho-corasick
backtrace backtrace
blake2b_simd
bstr bstr
byteorder byteorder
chacha chacha
@ -47,6 +48,7 @@ xattr
# * rust/rustc # * rust/rustc
RUSTDOCFLAGS RUSTDOCFLAGS
RUSTFLAGS RUSTFLAGS
bitor # BitOr trait function
bitxor # BitXor trait function bitxor # BitXor trait function
clippy clippy
concat concat

1
Cargo.lock generated
View file

@ -2420,6 +2420,7 @@ dependencies = [
"uucore", "uucore",
"uucore_procs", "uucore_procs",
"walkdir", "walkdir",
"winapi 0.3.9",
] ]
[[package]] [[package]]

View file

@ -349,7 +349,7 @@ sha1 = { version="0.6", features=["std"] }
tempfile = "3.2.0" tempfile = "3.2.0"
time = "0.1" time = "0.1"
unindent = "0.1" unindent = "0.1"
uucore = { version=">=0.0.8", package="uucore", path="src/uucore", features=["entries"] } uucore = { version=">=0.0.8", package="uucore", path="src/uucore", features=["entries", "process"] }
walkdir = "2.2" walkdir = "2.2"
atty = "0.2.14" atty = "0.2.14"

View file

@ -268,11 +268,11 @@ test:
${CARGO} test ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST) ${CARGO} test ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST)
busybox-src: busybox-src:
if [ ! -e $(BUSYBOX_SRC) ]; then \ if [ ! -e "$(BUSYBOX_SRC)" ] ; then \
mkdir -p $(BUSYBOX_ROOT); \ mkdir -p "$(BUSYBOX_ROOT)" ; \
wget https://busybox.net/downloads/busybox-$(BUSYBOX_VER).tar.bz2 -P $(BUSYBOX_ROOT); \ wget "https://busybox.net/downloads/busybox-$(BUSYBOX_VER).tar.bz2" -P "$(BUSYBOX_ROOT)" ; \
tar -C $(BUSYBOX_ROOT) -xf $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER).tar.bz2; \ tar -C "$(BUSYBOX_ROOT)" -xf "$(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER).tar.bz2" ; \
fi; \ fi ;
# This is a busybox-specific config file their test suite wants to parse. # This is a busybox-specific config file their test suite wants to parse.
$(BUILDDIR)/.config: $(BASEDIR)/.busybox-config $(BUILDDIR)/.config: $(BASEDIR)/.busybox-config
@ -280,10 +280,12 @@ $(BUILDDIR)/.config: $(BASEDIR)/.busybox-config
# Test under the busybox test suite # Test under the busybox test suite
$(BUILDDIR)/busybox: busybox-src build-coreutils $(BUILDDIR)/.config $(BUILDDIR)/busybox: busybox-src build-coreutils $(BUILDDIR)/.config
cp $(BUILDDIR)/coreutils $(BUILDDIR)/busybox; \ cp "$(BUILDDIR)/coreutils" "$(BUILDDIR)/busybox"
chmod +x $@; chmod +x $@
prepare-busytest: $(BUILDDIR)/busybox prepare-busytest: $(BUILDDIR)/busybox
# disable inapplicable tests
-( cd "$(BUSYBOX_SRC)/testsuite" ; if [ -e "busybox.tests" ] ; then mv busybox.tests busybox.tests- ; fi ; )
ifeq ($(EXES),) ifeq ($(EXES),)
busytest: busytest:

View file

@ -110,7 +110,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let line_ending = if opt_zero { "\0" } else { "\n" }; let line_ending = if opt_zero { "\0" } else { "\n" };
for path in paths { for path in paths {
print!("{}{}", basename(&path, &suffix), line_ending); print!("{}{}", basename(path, suffix), line_ending);
} }
0 0

View file

@ -295,7 +295,7 @@ fn cat_handle<R: Read>(
if options.can_write_fast() { if options.can_write_fast() {
write_fast(handle) write_fast(handle)
} else { } else {
write_lines(handle, &options, state) write_lines(handle, options, state)
} }
} }
@ -308,7 +308,7 @@ fn cat_path(path: &str, options: &OutputOptions, state: &mut OutputState) -> Cat
reader: stdin, reader: stdin,
is_interactive: is_stdin_interactive(), is_interactive: is_stdin_interactive(),
}; };
return cat_handle(&mut handle, &options, state); return cat_handle(&mut handle, options, state);
} }
match get_input_type(path)? { match get_input_type(path)? {
InputType::Directory => Err(CatError::IsDirectory), InputType::Directory => Err(CatError::IsDirectory),
@ -322,7 +322,7 @@ fn cat_path(path: &str, options: &OutputOptions, state: &mut OutputState) -> Cat
reader: socket, reader: socket,
is_interactive: false, is_interactive: false,
}; };
cat_handle(&mut handle, &options, state) cat_handle(&mut handle, options, state)
} }
_ => { _ => {
let file = File::open(path)?; let file = File::open(path)?;
@ -332,7 +332,7 @@ fn cat_path(path: &str, options: &OutputOptions, state: &mut OutputState) -> Cat
reader: file, reader: file,
is_interactive: false, is_interactive: false,
}; };
cat_handle(&mut handle, &options, state) cat_handle(&mut handle, options, state)
} }
} }
} }
@ -345,7 +345,7 @@ fn cat_files(files: Vec<String>, options: &OutputOptions) -> Result<(), u32> {
}; };
for path in &files { for path in &files {
if let Err(err) = cat_path(path, &options, &mut state) { if let Err(err) = cat_path(path, options, &mut state) {
show_error!("{}: {}", path, err); show_error!("{}: {}", path, err);
error_count += 1; error_count += 1;
} }

View file

@ -127,13 +127,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let verbose = matches.is_present(options::VERBOSE); let verbose = matches.is_present(options::VERBOSE);
let preserve_root = matches.is_present(options::PRESERVE_ROOT); let preserve_root = matches.is_present(options::PRESERVE_ROOT);
let recursive = matches.is_present(options::RECURSIVE); let recursive = matches.is_present(options::RECURSIVE);
let fmode = let fmode = matches
matches .value_of(options::REFERENCE)
.value_of(options::REFERENCE) .and_then(|fref| match fs::metadata(fref) {
.and_then(|ref fref| match fs::metadata(fref) { Ok(meta) => Some(meta.mode()),
Ok(meta) => Some(meta.mode()), Err(err) => crash!(1, "cannot stat attributes of '{}': {}", fref, err),
Err(err) => crash!(1, "cannot stat attributes of '{}': {}", fref, err), });
});
let modes = matches.value_of(options::MODE).unwrap(); // should always be Some because required let modes = matches.value_of(options::MODE).unwrap(); // should always be Some because required
let mut cmode = if mode_had_minus_prefix { let mut cmode = if mode_had_minus_prefix {
// clap parsing is finished, now put prefix back // clap parsing is finished, now put prefix back
@ -230,11 +229,11 @@ impl Chmoder {
return Err(1); return Err(1);
} }
if !self.recursive { if !self.recursive {
r = self.chmod_file(&file).and(r); r = self.chmod_file(file).and(r);
} else { } else {
for entry in WalkDir::new(&filename).into_iter().filter_map(|e| e.ok()) { for entry in WalkDir::new(&filename).into_iter().filter_map(|e| e.ok()) {
let file = entry.path(); let file = entry.path();
r = self.chmod_file(&file).and(r); r = self.chmod_file(file).and(r);
} }
} }
} }

View file

@ -220,7 +220,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
}; };
let filter = if let Some(spec) = matches.value_of(options::FROM) { let filter = if let Some(spec) = matches.value_of(options::FROM) {
match parse_spec(&spec) { match parse_spec(spec) {
Ok((Some(uid), None)) => IfFrom::User(uid), Ok((Some(uid), None)) => IfFrom::User(uid),
Ok((None, Some(gid))) => IfFrom::Group(gid), Ok((None, Some(gid))) => IfFrom::Group(gid),
Ok((Some(uid), Some(gid))) => IfFrom::UserGroup(uid, gid), Ok((Some(uid), Some(gid))) => IfFrom::UserGroup(uid, gid),
@ -248,7 +248,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
} }
} }
} else { } else {
match parse_spec(&owner) { match parse_spec(owner) {
Ok((u, g)) => { Ok((u, g)) => {
dest_uid = u; dest_uid = u;
dest_gid = g; dest_gid = g;

View file

@ -106,13 +106,13 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let mut vector: Vec<&str> = Vec::new(); let mut vector: Vec<&str> = Vec::new();
for (&k, v) in matches.args.iter() { for (&k, v) in matches.args.iter() {
vector.push(k); vector.push(k);
vector.push(&v.vals[0].to_str().unwrap()); vector.push(v.vals[0].to_str().unwrap());
} }
vector vector
} }
}; };
set_context(&newroot, &matches); set_context(newroot, &matches);
let pstatus = Command::new(command[0]) let pstatus = Command::new(command[0])
.args(&command[1..]) .args(&command[1..])
@ -132,7 +132,7 @@ fn set_context(root: &Path, options: &clap::ArgMatches) {
let group_str = options.value_of(options::GROUP).unwrap_or_default(); let group_str = options.value_of(options::GROUP).unwrap_or_default();
let groups_str = options.value_of(options::GROUPS).unwrap_or_default(); let groups_str = options.value_of(options::GROUPS).unwrap_or_default();
let userspec = match userspec_str { let userspec = match userspec_str {
Some(ref u) => { Some(u) => {
let s: Vec<&str> = u.split(':').collect(); let s: Vec<&str> = u.split(':').collect();
if s.len() != 2 || s.iter().any(|&spec| spec.is_empty()) { if s.len() != 2 || s.iter().any(|&spec| spec.is_empty()) {
crash!(1, "invalid userspec: `{}`", u) crash!(1, "invalid userspec: `{}`", u)

View file

@ -1088,7 +1088,7 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu
} }
#[cfg(not(windows))] #[cfg(not(windows))]
#[allow(clippy::unnecessary_unwrap)] // needed for windows version #[allow(clippy::unnecessary_wraps)] // needed for windows version
fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> { fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> {
match std::os::unix::fs::symlink(source, dest).context(context) { match std::os::unix::fs::symlink(source, dest).context(context) {
Ok(_) => Ok(()), Ok(_) => Ok(()),

View file

@ -92,7 +92,7 @@ where
T: BufRead, T: BufRead,
{ {
let mut input_iter = InputSplitter::new(input.lines().enumerate()); let mut input_iter = InputSplitter::new(input.lines().enumerate());
let mut split_writer = SplitWriter::new(&options); let mut split_writer = SplitWriter::new(options);
let ret = do_csplit(&mut split_writer, patterns, &mut input_iter); let ret = do_csplit(&mut split_writer, patterns, &mut input_iter);
// consume the rest // consume the rest

View file

@ -393,7 +393,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
although the apparent size is usually smaller, it may be larger due to holes \ although the apparent size is usually smaller, it may be larger due to holes \
in ('sparse') files, internal fragmentation, indirect blocks, and the like" in ('sparse') files, internal fragmentation, indirect blocks, and the like"
) )
.alias("app") // The GNU testsuite uses this alias .alias("app") // The GNU test suite uses this alias
) )
.arg( .arg(
Arg::with_name(options::BLOCK_SIZE) Arg::with_name(options::BLOCK_SIZE)
@ -545,12 +545,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let max_depth_str = matches.value_of(options::MAX_DEPTH); let max_depth_str = matches.value_of(options::MAX_DEPTH);
let max_depth = max_depth_str.as_ref().and_then(|s| s.parse::<usize>().ok()); let max_depth = max_depth_str.as_ref().and_then(|s| s.parse::<usize>().ok());
match (max_depth_str, max_depth) { match (max_depth_str, max_depth) {
(Some(ref s), _) if summarize => { (Some(s), _) if summarize => {
show_error!("summarizing conflicts with --max-depth={}", *s); show_error!("summarizing conflicts with --max-depth={}", s);
return 1; return 1;
} }
(Some(ref s), None) => { (Some(s), None) => {
show_error!("invalid maximum depth '{}'", *s); show_error!("invalid maximum depth '{}'", s);
return 1; return 1;
} }
(Some(_), Some(_)) | (None, _) => { /* valid */ } (Some(_), Some(_)) | (None, _) => { /* valid */ }

View file

@ -181,7 +181,7 @@ fn execute(no_newline: bool, escaped: bool, free: Vec<String>) -> io::Result<()>
write!(output, " ")?; write!(output, " ")?;
} }
if escaped { if escaped {
let should_stop = print_escaped(&input, &mut output)?; let should_stop = print_escaped(input, &mut output)?;
if should_stop { if should_stop {
break; break;
} }

View file

@ -245,7 +245,7 @@ fn run_env(args: impl uucore::Args) -> Result<(), i32> {
} }
// set specified env vars // set specified env vars
for &(ref name, ref val) in &opts.sets { for &(name, val) in &opts.sets {
// FIXME: set_var() panics if name is an empty string // FIXME: set_var() panics if name is an empty string
env::set_var(name, val); env::set_var(name, val);
} }

View file

@ -15,7 +15,6 @@ extern crate uucore;
use clap::{crate_version, App, Arg, ArgMatches}; use clap::{crate_version, App, Arg, ArgMatches};
use std::fs::File; use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write}; use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::iter::repeat;
use std::str::from_utf8; use std::str::from_utf8;
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
@ -90,7 +89,7 @@ impl Options {
}) })
.max() .max()
.unwrap(); // length of tabstops is guaranteed >= 1 .unwrap(); // length of tabstops is guaranteed >= 1
let tspaces = repeat(' ').take(nspaces).collect(); let tspaces = " ".repeat(nspaces);
let files: Vec<String> = match matches.values_of(options::FILES) { let files: Vec<String> = match matches.values_of(options::FILES) {
Some(s) => s.map(|v| v.to_string()).collect(), Some(s) => s.map(|v| v.to_string()).collect(),
@ -236,7 +235,7 @@ fn expand(options: Options) {
// now dump out either spaces if we're expanding, or a literal tab if we're not // now dump out either spaces if we're expanding, or a literal tab if we're not
if init || !options.iflag { if init || !options.iflag {
safe_unwrap!(output.write_all(&options.tspaces[..nts].as_bytes())); safe_unwrap!(output.write_all(options.tspaces[..nts].as_bytes()));
} else { } else {
safe_unwrap!(output.write_all(&buf[byte..byte + nbytes])); safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
} }

View file

@ -37,7 +37,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
} }
fn process_expr(token_strings: &[String]) -> Result<String, String> { fn process_expr(token_strings: &[String]) -> Result<String, String> {
let maybe_tokens = tokens::strings_to_tokens(&token_strings); let maybe_tokens = tokens::strings_to_tokens(token_strings);
let maybe_ast = syntax_tree::tokens_to_ast(maybe_tokens); let maybe_ast = syntax_tree::tokens_to_ast(maybe_tokens);
evaluate_ast(maybe_ast) evaluate_ast(maybe_ast)
} }

View file

@ -78,27 +78,27 @@ pub fn strings_to_tokens(strings: &[String]) -> Result<Vec<(usize, Token)>, Stri
"(" => Token::ParOpen, "(" => Token::ParOpen,
")" => Token::ParClose, ")" => Token::ParClose,
"^" => Token::new_infix_op(&s, false, 7), "^" => Token::new_infix_op(s, false, 7),
":" => Token::new_infix_op(&s, true, 6), ":" => Token::new_infix_op(s, true, 6),
"*" => Token::new_infix_op(&s, true, 5), "*" => Token::new_infix_op(s, true, 5),
"/" => Token::new_infix_op(&s, true, 5), "/" => Token::new_infix_op(s, true, 5),
"%" => Token::new_infix_op(&s, true, 5), "%" => Token::new_infix_op(s, true, 5),
"+" => Token::new_infix_op(&s, true, 4), "+" => Token::new_infix_op(s, true, 4),
"-" => Token::new_infix_op(&s, true, 4), "-" => Token::new_infix_op(s, true, 4),
"=" => Token::new_infix_op(&s, true, 3), "=" => Token::new_infix_op(s, true, 3),
"!=" => Token::new_infix_op(&s, true, 3), "!=" => Token::new_infix_op(s, true, 3),
"<" => Token::new_infix_op(&s, true, 3), "<" => Token::new_infix_op(s, true, 3),
">" => Token::new_infix_op(&s, true, 3), ">" => Token::new_infix_op(s, true, 3),
"<=" => Token::new_infix_op(&s, true, 3), "<=" => Token::new_infix_op(s, true, 3),
">=" => Token::new_infix_op(&s, true, 3), ">=" => Token::new_infix_op(s, true, 3),
"&" => Token::new_infix_op(&s, true, 2), "&" => Token::new_infix_op(s, true, 2),
"|" => Token::new_infix_op(&s, true, 1), "|" => Token::new_infix_op(s, true, 1),
"match" => Token::PrefixOp { "match" => Token::PrefixOp {
arity: 2, arity: 2,
@ -117,9 +117,9 @@ pub fn strings_to_tokens(strings: &[String]) -> Result<Vec<(usize, Token)>, Stri
value: s.clone(), value: s.clone(),
}, },
_ => Token::new_value(&s), _ => Token::new_value(s),
}; };
push_token_if_not_escaped(&mut tokens_acc, tok_idx, token_if_not_escaped, &s); push_token_if_not_escaped(&mut tokens_acc, tok_idx, token_if_not_escaped, s);
tok_idx += 1; tok_idx += 1;
} }
maybe_dump_tokens_acc(&tokens_acc); maybe_dump_tokens_acc(&tokens_acc);

View file

@ -109,7 +109,7 @@ fn handle_obsolete(args: &[String]) -> (Vec<String>, Option<String>) {
fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: usize) { fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: usize) {
for filename in &filenames { for filename in &filenames {
let filename: &str = &filename; let filename: &str = filename;
let mut stdin_buf; let mut stdin_buf;
let mut file_buf; let mut file_buf;
let buffer = BufReader::new(if filename == "-" { let buffer = BufReader::new(if filename == "-" {

View file

@ -10,7 +10,7 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::entries::{get_groups, gid2grp, Locate, Passwd}; use uucore::entries::{get_groups_gnu, gid2grp, Locate, Passwd};
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
@ -35,7 +35,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
None => { None => {
println!( println!(
"{}", "{}",
get_groups() get_groups_gnu(None)
.unwrap() .unwrap()
.iter() .iter()
.map(|&g| gid2grp(g).unwrap()) .map(|&g| gid2grp(g).unwrap())

View file

@ -59,7 +59,7 @@ impl Digest for blake2b_simd::State {
fn result(&mut self, out: &mut [u8]) { fn result(&mut self, out: &mut [u8]) {
let hash_result = &self.finalize(); let hash_result = &self.finalize();
out.copy_from_slice(&hash_result.as_bytes()); out.copy_from_slice(hash_result.as_bytes());
} }
fn reset(&mut self) { fn reset(&mut self) {

View file

@ -90,7 +90,7 @@ fn detect_algo<'a>(
512, 512,
), ),
"sha3sum" => match matches.value_of("bits") { "sha3sum" => match matches.value_of("bits") {
Some(bits_str) => match (&bits_str).parse::<usize>() { Some(bits_str) => match (bits_str).parse::<usize>() {
Ok(224) => ( Ok(224) => (
"SHA3-224", "SHA3-224",
Box::new(Sha3_224::new()) as Box<dyn Digest>, Box::new(Sha3_224::new()) as Box<dyn Digest>,
@ -140,7 +140,7 @@ fn detect_algo<'a>(
512, 512,
), ),
"shake128sum" => match matches.value_of("bits") { "shake128sum" => match matches.value_of("bits") {
Some(bits_str) => match (&bits_str).parse::<usize>() { Some(bits_str) => match (bits_str).parse::<usize>() {
Ok(bits) => ( Ok(bits) => (
"SHAKE128", "SHAKE128",
Box::new(Shake128::new()) as Box<dyn Digest>, Box::new(Shake128::new()) as Box<dyn Digest>,
@ -151,7 +151,7 @@ fn detect_algo<'a>(
None => crash!(1, "--bits required for SHAKE-128"), None => crash!(1, "--bits required for SHAKE-128"),
}, },
"shake256sum" => match matches.value_of("bits") { "shake256sum" => match matches.value_of("bits") {
Some(bits_str) => match (&bits_str).parse::<usize>() { Some(bits_str) => match (bits_str).parse::<usize>() {
Ok(bits) => ( Ok(bits) => (
"SHAKE256", "SHAKE256",
Box::new(Shake256::new()) as Box<dyn Digest>, Box::new(Shake256::new()) as Box<dyn Digest>,
@ -194,7 +194,7 @@ fn detect_algo<'a>(
} }
if matches.is_present("sha3") { if matches.is_present("sha3") {
match matches.value_of("bits") { match matches.value_of("bits") {
Some(bits_str) => match (&bits_str).parse::<usize>() { Some(bits_str) => match (bits_str).parse::<usize>() {
Ok(224) => set_or_crash( Ok(224) => set_or_crash(
"SHA3-224", "SHA3-224",
Box::new(Sha3_224::new()) as Box<dyn Digest>, Box::new(Sha3_224::new()) as Box<dyn Digest>,
@ -238,7 +238,7 @@ fn detect_algo<'a>(
} }
if matches.is_present("shake128") { if matches.is_present("shake128") {
match matches.value_of("bits") { match matches.value_of("bits") {
Some(bits_str) => match (&bits_str).parse::<usize>() { Some(bits_str) => match (bits_str).parse::<usize>() {
Ok(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), bits), Ok(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), bits),
Err(err) => crash!(1, "{}", err), Err(err) => crash!(1, "{}", err),
}, },
@ -247,7 +247,7 @@ fn detect_algo<'a>(
} }
if matches.is_present("shake256") { if matches.is_present("shake256") {
match matches.value_of("bits") { match matches.value_of("bits") {
Some(bits_str) => match (&bits_str).parse::<usize>() { Some(bits_str) => match (bits_str).parse::<usize>() {
Ok(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), bits), Ok(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), bits),
Err(err) => crash!(1, "{}", err), Err(err) => crash!(1, "{}", err),
}, },

View file

@ -10,7 +10,7 @@
// http://ftp-archive.freebsd.org/mirror/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/id.c // http://ftp-archive.freebsd.org/mirror/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/id.c
// http://www.opensource.apple.com/source/shell_cmds/shell_cmds-118/id/id.c // http://www.opensource.apple.com/source/shell_cmds/shell_cmds-118/id/id.c
// spell-checker:ignore (ToDO) asid auditid auditinfo auid cstr egid emod euid getaudit getlogin gflag nflag pline rflag termid uflag // spell-checker:ignore (ToDO) asid auditid auditinfo auid cstr egid emod euid getaudit getlogin gflag nflag pline rflag termid uflag gsflag
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(dead_code)] #![allow(dead_code)]
@ -79,7 +79,7 @@ static OPT_GROUPS: &str = "groups";
static OPT_HUMAN_READABLE: &str = "human-readable"; static OPT_HUMAN_READABLE: &str = "human-readable";
static OPT_NAME: &str = "name"; static OPT_NAME: &str = "name";
static OPT_PASSWORD: &str = "password"; static OPT_PASSWORD: &str = "password";
static OPT_REAL_ID: &str = "real-id"; static OPT_REAL_ID: &str = "real";
static ARG_USERS: &str = "users"; static ARG_USERS: &str = "users";
@ -135,7 +135,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.arg( .arg(
Arg::with_name(OPT_REAL_ID) Arg::with_name(OPT_REAL_ID)
.short("r") .short("r")
.help("Display the real ID for the -g and -u options"), .long(OPT_REAL_ID)
.help(
"Display the real ID for the -G, -g and -u options instead of the effective ID.",
),
) )
.arg(Arg::with_name(ARG_USERS).multiple(true).takes_value(true)) .arg(Arg::with_name(ARG_USERS).multiple(true).takes_value(true))
.get_matches_from(args); .get_matches_from(args);
@ -162,6 +165,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let nflag = matches.is_present(OPT_NAME); let nflag = matches.is_present(OPT_NAME);
let uflag = matches.is_present(OPT_EFFECTIVE_USER); let uflag = matches.is_present(OPT_EFFECTIVE_USER);
let gflag = matches.is_present(OPT_GROUP); let gflag = matches.is_present(OPT_GROUP);
let gsflag = matches.is_present(OPT_GROUPS);
let rflag = matches.is_present(OPT_REAL_ID); let rflag = matches.is_present(OPT_REAL_ID);
if gflag { if gflag {
@ -194,26 +198,23 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
return 0; return 0;
} }
if matches.is_present(OPT_GROUPS) { if gsflag {
let id = possible_pw
.map(|p| p.gid())
.unwrap_or(if rflag { getgid() } else { getegid() });
println!( println!(
"{}", "{}",
if nflag { possible_pw
possible_pw .map(|p| p.belongs_to())
.map(|p| p.belongs_to()) .unwrap_or_else(|| entries::get_groups_gnu(Some(id)).unwrap())
.unwrap_or_else(|| entries::get_groups().unwrap()) .iter()
.iter() .map(|&id| if nflag {
.map(|&id| entries::gid2grp(id).unwrap()) entries::gid2grp(id).unwrap_or_else(|_| id.to_string())
.collect::<Vec<_>>() } else {
.join(" ") id.to_string()
} else { })
possible_pw .collect::<Vec<_>>()
.map(|p| p.belongs_to()) .join(" ")
.unwrap_or_else(|| entries::get_groups().unwrap())
.iter()
.map(|&id| id.to_string())
.collect::<Vec<_>>()
.join(" ")
}
); );
return 0; return 0;
} }
@ -280,7 +281,7 @@ fn pretty(possible_pw: Option<Passwd>) {
println!( println!(
"groups\t{}", "groups\t{}",
entries::get_groups() entries::get_groups_gnu(None)
.unwrap() .unwrap()
.iter() .iter()
.map(|&gr| entries::gid2grp(gr).unwrap()) .map(|&gr| entries::gid2grp(gr).unwrap())

View file

@ -379,7 +379,7 @@ fn directory(paths: Vec<String>, b: Behavior) -> i32 {
} }
} }
if mode::chmod(&path, b.mode()).is_err() { if mode::chmod(path, b.mode()).is_err() {
all_successful = false; all_successful = false;
continue; continue;
} }
@ -422,7 +422,7 @@ fn standard(paths: Vec<String>, b: Behavior) -> i32 {
return 1; return 1;
} }
if mode::chmod(&parent, b.mode()).is_err() { if mode::chmod(parent, b.mode()).is_err() {
show_error!("failed to chmod {}", parent.display()); show_error!("failed to chmod {}", parent.display());
return 1; return 1;
} }
@ -501,7 +501,7 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i3
/// _target_ must be a non-directory /// _target_ must be a non-directory
/// ///
fn copy_file_to_file(file: &Path, target: &Path, b: &Behavior) -> i32 { fn copy_file_to_file(file: &Path, target: &Path, b: &Behavior) -> i32 {
if copy(file, &target, b).is_err() { if copy(file, target, b).is_err() {
1 1
} else { } else {
0 0
@ -563,7 +563,7 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> Result<(), ()> {
} }
} }
if mode::chmod(&to, b.mode()).is_err() { if mode::chmod(to, b.mode()).is_err() {
return Err(()); return Err(());
} }

View file

@ -328,8 +328,8 @@ impl<'a> State<'a> {
}); });
} else { } else {
repr.print_field(key); repr.print_field(key);
repr.print_fields(&line1, self.key, self.max_fields); repr.print_fields(line1, self.key, self.max_fields);
repr.print_fields(&line2, other.key, other.max_fields); repr.print_fields(line2, other.key, other.max_fields);
} }
println!(); println!();
@ -611,7 +611,7 @@ fn exec(file1: &str, file2: &str, settings: &Settings) -> i32 {
let mut state1 = State::new( let mut state1 = State::new(
FileNum::File1, FileNum::File1,
&file1, file1,
&stdin, &stdin,
settings.key1, settings.key1,
settings.print_unpaired, settings.print_unpaired,
@ -619,7 +619,7 @@ fn exec(file1: &str, file2: &str, settings: &Settings) -> i32 {
let mut state2 = State::new( let mut state2 = State::new(
FileNum::File2, FileNum::File2,
&file2, file2,
&stdin, &stdin,
settings.key2, settings.key2,
settings.print_unpaired, settings.print_unpaired,

View file

@ -260,17 +260,17 @@ fn exec(files: &[PathBuf], settings: &Settings) -> i32 {
// Handle cases where we create links in a directory first. // Handle cases where we create links in a directory first.
if let Some(ref name) = settings.target_dir { if let Some(ref name) = settings.target_dir {
// 4th form: a directory is specified by -t. // 4th form: a directory is specified by -t.
return link_files_in_dir(files, &PathBuf::from(name), &settings); return link_files_in_dir(files, &PathBuf::from(name), settings);
} }
if !settings.no_target_dir { if !settings.no_target_dir {
if files.len() == 1 { if files.len() == 1 {
// 2nd form: the target directory is the current directory. // 2nd form: the target directory is the current directory.
return link_files_in_dir(files, &PathBuf::from("."), &settings); return link_files_in_dir(files, &PathBuf::from("."), settings);
} }
let last_file = &PathBuf::from(files.last().unwrap()); let last_file = &PathBuf::from(files.last().unwrap());
if files.len() > 2 || last_file.is_dir() { if files.len() > 2 || last_file.is_dir() {
// 3rd form: create links in the last argument. // 3rd form: create links in the last argument.
return link_files_in_dir(&files[0..files.len() - 1], last_file, &settings); return link_files_in_dir(&files[0..files.len() - 1], last_file, settings);
} }
} }
@ -392,7 +392,7 @@ fn relative_path<'a>(src: &Path, dst: &Path) -> Result<Cow<'a, Path>> {
fn link(src: &Path, dst: &Path, settings: &Settings) -> Result<()> { fn link(src: &Path, dst: &Path, settings: &Settings) -> Result<()> {
let mut backup_path = None; let mut backup_path = None;
let source: Cow<'_, Path> = if settings.relative { let source: Cow<'_, Path> = if settings.relative {
relative_path(&src, dst)? relative_path(src, dst)?
} else { } else {
src.into() src.into()
}; };

View file

@ -1243,7 +1243,7 @@ fn sort_entries(entries: &mut Vec<PathData>, config: &Config) {
Sort::Time => entries.sort_by_key(|k| { Sort::Time => entries.sort_by_key(|k| {
Reverse( Reverse(
k.md() k.md()
.and_then(|md| get_system_time(&md, config)) .and_then(|md| get_system_time(md, config))
.unwrap_or(UNIX_EPOCH), .unwrap_or(UNIX_EPOCH),
) )
}), }),
@ -1323,7 +1323,7 @@ fn enter_directory(dir: &PathData, config: &Config, out: &mut BufWriter<Stdout>)
.filter(|p| p.file_type().map(|ft| ft.is_dir()).unwrap_or(false)) .filter(|p| p.file_type().map(|ft| ft.is_dir()).unwrap_or(false))
{ {
let _ = writeln!(out, "\n{}:", e.p_buf.display()); let _ = writeln!(out, "\n{}:", e.p_buf.display());
enter_directory(&e, config, out); enter_directory(e, config, out);
} }
} }
} }
@ -1339,8 +1339,8 @@ fn get_metadata(entry: &Path, dereference: bool) -> std::io::Result<Metadata> {
fn display_dir_entry_size(entry: &PathData, config: &Config) -> (usize, usize) { fn display_dir_entry_size(entry: &PathData, config: &Config) -> (usize, usize) {
if let Some(md) = entry.md() { if let Some(md) = entry.md() {
( (
display_symlink_count(&md).len(), display_symlink_count(md).len(),
display_size_or_rdev(&md, config).len(), display_size_or_rdev(md, config).len(),
) )
} else { } else {
(0, 0) (0, 0)
@ -1371,7 +1371,7 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout
display_item_long(item, max_links, max_width, config, out); display_item_long(item, max_links, max_width, config, out);
} }
} else { } else {
let names = items.iter().filter_map(|i| display_file_name(&i, config)); let names = items.iter().filter_map(|i| display_file_name(i, config));
match (&config.format, config.width) { match (&config.format, config.width) {
(Format::Columns, Some(width)) => { (Format::Columns, Some(width)) => {
@ -1482,40 +1482,40 @@ fn display_item_long(
#[cfg(unix)] #[cfg(unix)]
{ {
if config.inode { if config.inode {
let _ = write!(out, "{} ", get_inode(&md)); let _ = write!(out, "{} ", get_inode(md));
} }
} }
let _ = write!( let _ = write!(
out, out,
"{} {}", "{} {}",
display_permissions(&md, true), display_permissions(md, true),
pad_left(display_symlink_count(&md), max_links), pad_left(display_symlink_count(md), max_links),
); );
if config.long.owner { if config.long.owner {
let _ = write!(out, " {}", display_uname(&md, config)); let _ = write!(out, " {}", display_uname(md, config));
} }
if config.long.group { if config.long.group {
let _ = write!(out, " {}", display_group(&md, config)); let _ = write!(out, " {}", display_group(md, config));
} }
// Author is only different from owner on GNU/Hurd, so we reuse // Author is only different from owner on GNU/Hurd, so we reuse
// the owner, since GNU/Hurd is not currently supported by Rust. // the owner, since GNU/Hurd is not currently supported by Rust.
if config.long.author { if config.long.author {
let _ = write!(out, " {}", display_uname(&md, config)); let _ = write!(out, " {}", display_uname(md, config));
} }
let _ = writeln!( let _ = writeln!(
out, out,
" {} {} {}", " {} {} {}",
pad_left(display_size_or_rdev(md, config), max_size), pad_left(display_size_or_rdev(md, config), max_size),
display_date(&md, config), display_date(md, config),
// unwrap is fine because it fails when metadata is not available // unwrap is fine because it fails when metadata is not available
// but we already know that it is because it's checked at the // but we already know that it is because it's checked at the
// start of the function. // start of the function.
display_file_name(&item, config).unwrap().contents, display_file_name(item, config).unwrap().contents,
); );
} }
@ -1741,7 +1741,7 @@ fn display_file_name(path: &PathData, config: &Config) -> Option<Cell> {
let mut width = name.width(); let mut width = name.width();
if let Some(ls_colors) = &config.color { if let Some(ls_colors) = &config.color {
name = color_name(&ls_colors, &path.p_buf, name, path.md()?); name = color_name(ls_colors, &path.p_buf, name, path.md()?);
} }
if config.indicator_style != IndicatorStyle::None { if config.indicator_style != IndicatorStyle::None {
@ -1786,7 +1786,7 @@ fn display_file_name(path: &PathData, config: &Config) -> Option<Cell> {
} }
fn color_name(ls_colors: &LsColors, path: &Path, name: String, md: &Metadata) -> String { fn color_name(ls_colors: &LsColors, path: &Path, name: String, md: &Metadata) -> String {
match ls_colors.style_for_path_with_metadata(path, Some(&md)) { match ls_colors.style_for_path_with_metadata(path, Some(md)) {
Some(style) => style.to_ansi_term_style().paint(name).to_string(), Some(style) => style.to_ansi_term_style().paint(name).to_string(),
None => name, None => name,
} }

View file

@ -77,7 +77,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let mode_match = matches.value_of(OPT_MODE); let mode_match = matches.value_of(OPT_MODE);
let mode: u16 = match mode_match { let mode: u16 = match mode_match {
Some(m) => { Some(m) => {
let res: Option<u16> = u16::from_str_radix(&m, 8).ok(); let res: Option<u16> = u16::from_str_radix(m, 8).ok();
match res { match res {
Some(r) => r, Some(r) => r,
_ => crash!(1, "no mode given"), _ => crash!(1, "no mode given"),

View file

@ -59,7 +59,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
} }
let mode = match matches.value_of(options::MODE) { let mode = match matches.value_of(options::MODE) {
Some(m) => match usize::from_str_radix(&m, 8) { Some(m) => match usize::from_str_radix(m, 8) {
Ok(m) => m, Ok(m) => m,
Err(e) => { Err(e) => {
show_error!("invalid mode: {}", e); show_error!("invalid mode: {}", e);

View file

@ -165,9 +165,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
}; };
if dry_run { if dry_run {
dry_exec(tmpdir, prefix, rand, &suffix) dry_exec(tmpdir, prefix, rand, suffix)
} else { } else {
exec(tmpdir, prefix, rand, &suffix, make_dir, suppress_file_err) exec(tmpdir, prefix, rand, suffix, make_dir, suppress_file_err)
} }
} }

View file

@ -389,7 +389,7 @@ fn rename_with_fallback(from: &Path, to: &Path) -> io::Result<()> {
let file_type = metadata.file_type(); let file_type = metadata.file_type();
if file_type.is_symlink() { if file_type.is_symlink() {
rename_symlink_fallback(&from, &to)?; rename_symlink_fallback(from, to)?;
} else if file_type.is_dir() { } else if file_type.is_dir() {
// We remove the destination directory if it exists to match the // We remove the destination directory if it exists to match the
// behavior of `fs::rename`. As far as I can tell, `fs_extra`'s // behavior of `fs::rename`. As far as I can tell, `fs_extra`'s

View file

@ -238,7 +238,7 @@ fn format_and_print_delimited(s: &str, options: &NumfmtOptions) -> Result<()> {
} }
if field_selected { if field_selected {
print!("{}", format_string(&field.trim_start(), options, None)?); print!("{}", format_string(field.trim_start(), options, None)?);
} else { } else {
// print unselected field without conversion // print unselected field without conversion
print!("{}", field); print!("{}", field);
@ -271,7 +271,7 @@ fn format_and_print_whitespace(s: &str, options: &NumfmtOptions) -> Result<()> {
None None
}; };
print!("{}", format_string(&field, options, implicit_padding)?); print!("{}", format_string(field, options, implicit_padding)?);
} else { } else {
// print unselected field without conversion // print unselected field without conversion
print!("{}{}", prefix, field); print!("{}{}", prefix, field);

View file

@ -2,6 +2,7 @@
use std::fmt; use std::fmt;
#[allow(clippy::enum_variant_names)]
#[derive(Copy)] #[derive(Copy)]
pub enum FormatWriter { pub enum FormatWriter {
IntWriter(fn(u64) -> String), IntWriter(fn(u64) -> String),

View file

@ -115,7 +115,7 @@ impl<'a> MemoryDecoder<'a> {
/// Creates a clone of the internal buffer. The clone only contain the valid data. /// Creates a clone of the internal buffer. The clone only contain the valid data.
pub fn clone_buffer(&self, other: &mut Vec<u8>) { pub fn clone_buffer(&self, other: &mut Vec<u8>) {
other.clone_from(&self.data); other.clone_from(self.data);
other.resize(self.used_normal_length, 0); other.resize(self.used_normal_length, 0);
} }

View file

@ -129,10 +129,6 @@ impl OdOptions {
} }
}; };
if matches.occurrences_of(options::STRINGS) > 0 {
crash!(1, "Option '{}' not yet implemented.", options::STRINGS);
}
let mut skip_bytes = matches.value_of(options::SKIP_BYTES).map_or(0, |s| { let mut skip_bytes = matches.value_of(options::SKIP_BYTES).map_or(0, |s| {
parse_number_of_bytes(s).unwrap_or_else(|e| { parse_number_of_bytes(s).unwrap_or_else(|e| {
crash!(1, "{}", format_error_message(e, s, options::SKIP_BYTES)) crash!(1, "{}", format_error_message(e, s, options::SKIP_BYTES))
@ -536,7 +532,7 @@ where
print_bytes( print_bytes(
&input_offset.format_byte_offset(), &input_offset.format_byte_offset(),
&memory_decoder, &memory_decoder,
&output_info, output_info,
); );
} }

View file

@ -68,7 +68,7 @@ impl OutputInfo {
let print_width_line = print_width_block * (line_bytes / byte_size_block); let print_width_line = print_width_block * (line_bytes / byte_size_block);
let spaced_formatters = let spaced_formatters =
OutputInfo::create_spaced_formatter_info(&formats, byte_size_block, print_width_block); OutputInfo::create_spaced_formatter_info(formats, byte_size_block, print_width_block);
OutputInfo { OutputInfo {
byte_size_line: line_bytes, byte_size_line: line_bytes,

View file

@ -55,7 +55,7 @@ pub fn parse_inputs(matches: &dyn CommandLineOpts) -> Result<CommandLineInputs,
// if any of the options -A, -j, -N, -t, -v or -w are present there is no offset // if any of the options -A, -j, -N, -t, -v or -w are present there is no offset
if !matches.opts_present(&["A", "j", "N", "t", "v", "w"]) { if !matches.opts_present(&["A", "j", "N", "t", "v", "w"]) {
// test if the last input can be parsed as an offset. // test if the last input can be parsed as an offset.
let offset = parse_offset_operand(&input_strings[input_strings.len() - 1]); let offset = parse_offset_operand(input_strings[input_strings.len() - 1]);
if let Ok(n) = offset { if let Ok(n) = offset {
// if there is just 1 input (stdin), an offset must start with '+' // if there is just 1 input (stdin), an offset must start with '+'
if input_strings.len() == 1 && input_strings[0].starts_with('+') { if input_strings.len() == 1 && input_strings[0].starts_with('+') {
@ -88,7 +88,7 @@ pub fn parse_inputs_traditional(input_strings: Vec<&str>) -> Result<CommandLineI
match input_strings.len() { match input_strings.len() {
0 => Ok(CommandLineInputs::FileNames(vec!["-".to_string()])), 0 => Ok(CommandLineInputs::FileNames(vec!["-".to_string()])),
1 => { 1 => {
let offset0 = parse_offset_operand(&input_strings[0]); let offset0 = parse_offset_operand(input_strings[0]);
Ok(match offset0 { Ok(match offset0 {
Ok(n) => CommandLineInputs::FileAndOffset(("-".to_string(), n, None)), Ok(n) => CommandLineInputs::FileAndOffset(("-".to_string(), n, None)),
_ => CommandLineInputs::FileNames( _ => CommandLineInputs::FileNames(
@ -97,8 +97,8 @@ pub fn parse_inputs_traditional(input_strings: Vec<&str>) -> Result<CommandLineI
}) })
} }
2 => { 2 => {
let offset0 = parse_offset_operand(&input_strings[0]); let offset0 = parse_offset_operand(input_strings[0]);
let offset1 = parse_offset_operand(&input_strings[1]); let offset1 = parse_offset_operand(input_strings[1]);
match (offset0, offset1) { match (offset0, offset1) {
(Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset(( (Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset((
"-".to_string(), "-".to_string(),
@ -114,8 +114,8 @@ pub fn parse_inputs_traditional(input_strings: Vec<&str>) -> Result<CommandLineI
} }
} }
3 => { 3 => {
let offset = parse_offset_operand(&input_strings[1]); let offset = parse_offset_operand(input_strings[1]);
let label = parse_offset_operand(&input_strings[2]); let label = parse_offset_operand(input_strings[2]);
match (offset, label) { match (offset, label) {
(Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset(( (Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset((
input_strings[0].to_string(), input_strings[0].to_string(),

View file

@ -118,10 +118,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
// check a path, given as a slice of it's components and an operating mode // check a path, given as a slice of it's components and an operating mode
fn check_path(mode: &Mode, path: &[String]) -> bool { fn check_path(mode: &Mode, path: &[String]) -> bool {
match *mode { match *mode {
Mode::Basic => check_basic(&path), Mode::Basic => check_basic(path),
Mode::Extra => check_default(&path) && check_extra(&path), Mode::Extra => check_default(path) && check_extra(path),
Mode::Both => check_basic(&path) && check_extra(&path), Mode::Both => check_basic(path) && check_extra(path),
_ => check_default(&path), _ => check_default(path),
} }
} }
@ -156,7 +156,7 @@ fn check_basic(path: &[String]) -> bool {
); );
return false; return false;
} }
if !check_portable_chars(&p) { if !check_portable_chars(p) {
return false; return false;
} }
} }
@ -168,7 +168,7 @@ fn check_basic(path: &[String]) -> bool {
fn check_extra(path: &[String]) -> bool { fn check_extra(path: &[String]) -> bool {
// components: leading hyphens // components: leading hyphens
for p in path { for p in path {
if !no_leading_hyphen(&p) { if !no_leading_hyphen(p) {
writeln!( writeln!(
&mut std::io::stderr(), &mut std::io::stderr(),
"leading hyphen in file name component '{}'", "leading hyphen in file name component '{}'",

View file

@ -283,7 +283,7 @@ impl Pinky {
} }
} }
print!(" {}", time_string(&ut)); print!(" {}", time_string(ut));
let mut s = ut.host(); let mut s = ut.host();
if self.include_where && !s.is_empty() { if self.include_where && !s.is_empty() {

View file

@ -410,7 +410,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let options = &result_options.unwrap(); let options = &result_options.unwrap();
let cmd_result = if file_group.len() == 1 { let cmd_result = if file_group.len() == 1 {
pr(&file_group.get(0).unwrap(), options) pr(file_group.get(0).unwrap(), options)
} else { } else {
mpr(&file_group, options) mpr(&file_group, options)
}; };
@ -1114,7 +1114,7 @@ fn write_columns(
for (i, cell) in row.iter().enumerate() { for (i, cell) in row.iter().enumerate() {
if cell.is_none() && options.merge_files_print.is_some() { if cell.is_none() && options.merge_files_print.is_some() {
out.write_all( out.write_all(
get_line_for_printing(&options, &blank_line, columns, i, &line_width, indexes) get_line_for_printing(options, &blank_line, columns, i, &line_width, indexes)
.as_bytes(), .as_bytes(),
)?; )?;
} else if cell.is_none() { } else if cell.is_none() {
@ -1124,7 +1124,7 @@ fn write_columns(
let file_line = cell.unwrap(); let file_line = cell.unwrap();
out.write_all( out.write_all(
get_line_for_printing(&options, file_line, columns, i, &line_width, indexes) get_line_for_printing(options, file_line, columns, i, &line_width, indexes)
.as_bytes(), .as_bytes(),
)?; )?;
lines_printed += 1; lines_printed += 1;
@ -1149,7 +1149,7 @@ fn get_line_for_printing(
indexes: usize, indexes: usize,
) -> String { ) -> String {
let blank_line = String::new(); let blank_line = String::new();
let formatted_line_number = get_formatted_line_number(&options, file_line.line_number, index); let formatted_line_number = get_formatted_line_number(options, file_line.line_number, index);
let mut complete_line = format!( let mut complete_line = format!(
"{}{}", "{}{}",

View file

@ -26,7 +26,7 @@ impl Formatter for CninetyNineHexFloatf {
) -> Option<FormatPrimitive> { ) -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1; let second_field = field.second_field.unwrap_or(6) + 1;
let analysis = FloatAnalysis::analyze( let analysis = FloatAnalysis::analyze(
&str_in, str_in,
initial_prefix, initial_prefix,
Some(second_field as usize), Some(second_field as usize),
None, None,

View file

@ -298,11 +298,11 @@ pub fn get_primitive_dec(
pub fn primitive_to_str_common(prim: &FormatPrimitive, field: &FormatField) -> String { pub fn primitive_to_str_common(prim: &FormatPrimitive, field: &FormatField) -> String {
let mut final_str = String::new(); let mut final_str = String::new();
if let Some(ref prefix) = prim.prefix { if let Some(ref prefix) = prim.prefix {
final_str.push_str(&prefix); final_str.push_str(prefix);
} }
match prim.pre_decimal { match prim.pre_decimal {
Some(ref pre_decimal) => { Some(ref pre_decimal) => {
final_str.push_str(&pre_decimal); final_str.push_str(pre_decimal);
} }
None => { None => {
panic!( panic!(

View file

@ -21,7 +21,7 @@ impl Formatter for Floatf {
) -> Option<FormatPrimitive> { ) -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1; let second_field = field.second_field.unwrap_or(6) + 1;
let analysis = FloatAnalysis::analyze( let analysis = FloatAnalysis::analyze(
&str_in, str_in,
initial_prefix, initial_prefix,
None, None,
Some(second_field as usize), Some(second_field as usize),

View file

@ -252,7 +252,7 @@ impl Formatter for Intf {
fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String { fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
let mut final_str: String = String::new(); let mut final_str: String = String::new();
if let Some(ref prefix) = prim.prefix { if let Some(ref prefix) = prim.prefix {
final_str.push_str(&prefix); final_str.push_str(prefix);
} }
// integral second fields is zero-padded minimum-width // integral second fields is zero-padded minimum-width
// which gets handled before general minimum-width // which gets handled before general minimum-width
@ -266,7 +266,7 @@ impl Formatter for Intf {
i -= 1; i -= 1;
} }
} }
final_str.push_str(&pre_decimal); final_str.push_str(pre_decimal);
} }
None => { None => {
panic!( panic!(

View file

@ -235,7 +235,7 @@ pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<St
let as_str = format!("{}", provided_num); let as_str = format!("{}", provided_num);
let initial_prefix = get_initial_prefix( let initial_prefix = get_initial_prefix(
&as_str, &as_str,
&field.field_type field.field_type
); );
tmp=formatter.get_primitive(field, &initial_prefix, &as_str) tmp=formatter.get_primitive(field, &initial_prefix, &as_str)
.expect("err during default provided num"); .expect("err during default provided num");
@ -258,7 +258,7 @@ pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<St
// any formatter (int or float) // any formatter (int or float)
let initial_prefix = get_initial_prefix( let initial_prefix = get_initial_prefix(
in_str, in_str,
&field.field_type field.field_type
); );
// then get the FormatPrimitive from the Formatter // then get the FormatPrimitive from the Formatter
formatter.get_primitive(field, &initial_prefix, in_str) formatter.get_primitive(field, &initial_prefix, in_str)

View file

@ -275,7 +275,7 @@ impl SubParser {
} }
None => { None => {
text_so_far.push('%'); text_so_far.push('%');
err_conv(&text_so_far); err_conv(text_so_far);
false false
} }
} }

View file

@ -213,7 +213,7 @@ fn read_input(input_files: &[String], config: &Config) -> FileMap {
files.push("-"); files.push("-");
} else if config.gnu_ext { } else if config.gnu_ext {
for file in input_files { for file in input_files {
files.push(&file); files.push(file);
} }
} else { } else {
files.push(&input_files[0]); files.push(&input_files[0]);
@ -503,7 +503,7 @@ fn format_tex_line(
let keyword = &line[word_ref.position..word_ref.position_end]; let keyword = &line[word_ref.position..word_ref.position_end];
let after_chars_trim_idx = (word_ref.position_end, chars_line.len()); let after_chars_trim_idx = (word_ref.position_end, chars_line.len());
let all_after = &chars_line[after_chars_trim_idx.0..after_chars_trim_idx.1]; let all_after = &chars_line[after_chars_trim_idx.0..after_chars_trim_idx.1];
let (tail, before, after, head) = get_output_chunks(&all_before, &keyword, &all_after, &config); let (tail, before, after, head) = get_output_chunks(all_before, keyword, all_after, config);
output.push_str(&format!( output.push_str(&format!(
"{5}{0}{6}{5}{1}{6}{5}{2}{6}{5}{3}{6}{5}{4}{6}", "{5}{0}{6}{5}{1}{6}{5}{2}{6}{5}{3}{6}{5}{4}{6}",
format_tex_field(&tail), format_tex_field(&tail),
@ -515,7 +515,7 @@ fn format_tex_line(
"}" "}"
)); ));
if config.auto_ref || config.input_ref { if config.auto_ref || config.input_ref {
output.push_str(&format!("{}{}{}", "{", format_tex_field(&reference), "}")); output.push_str(&format!("{}{}{}", "{", format_tex_field(reference), "}"));
} }
output output
} }
@ -546,7 +546,7 @@ fn format_roff_line(
let keyword = &line[word_ref.position..word_ref.position_end]; let keyword = &line[word_ref.position..word_ref.position_end];
let after_chars_trim_idx = (word_ref.position_end, chars_line.len()); let after_chars_trim_idx = (word_ref.position_end, chars_line.len());
let all_after = &chars_line[after_chars_trim_idx.0..after_chars_trim_idx.1]; let all_after = &chars_line[after_chars_trim_idx.0..after_chars_trim_idx.1];
let (tail, before, after, head) = get_output_chunks(&all_before, &keyword, &all_after, &config); let (tail, before, after, head) = get_output_chunks(all_before, keyword, all_after, config);
output.push_str(&format!( output.push_str(&format!(
" \"{}\" \"{}\" \"{}{}\" \"{}\"", " \"{}\" \"{}\" \"{}{}\" \"{}\"",
format_roff_field(&tail), format_roff_field(&tail),
@ -556,7 +556,7 @@ fn format_roff_line(
format_roff_field(&head) format_roff_field(&head)
)); ));
if config.auto_ref || config.input_ref { if config.auto_ref || config.input_ref {
output.push_str(&format!(" \"{}\"", format_roff_field(&reference))); output.push_str(&format!(" \"{}\"", format_roff_field(reference)));
} }
output output
} }

View file

@ -18,10 +18,12 @@ path = "src/rm.rs"
clap = "2.33" clap = "2.33"
walkdir = "2.2" walkdir = "2.2"
remove_dir_all = "0.5.1" remove_dir_all = "0.5.1"
winapi = { version="0.3", features=[] }
uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["fs"] } uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]] [[bin]]
name = "rm" name = "rm"
path = "src/main.rs" path = "src/main.rs"

View file

@ -5,7 +5,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) bitor ulong // spell-checker:ignore (path) eacces
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
@ -430,9 +430,7 @@ use std::os::windows::prelude::MetadataExt;
#[cfg(windows)] #[cfg(windows)]
fn is_symlink_dir(metadata: &fs::Metadata) -> bool { fn is_symlink_dir(metadata: &fs::Metadata) -> bool {
use std::os::raw::c_ulong; use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
pub type DWORD = c_ulong;
pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10;
metadata.file_type().is_symlink() metadata.file_type().is_symlink()
&& ((metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY) != 0) && ((metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY) != 0)

View file

@ -88,7 +88,7 @@ fn remove(dirs: Vec<String>, ignore: bool, parents: bool, verbose: bool) -> Resu
for dir in &dirs { for dir in &dirs {
let path = Path::new(&dir[..]); let path = Path::new(&dir[..]);
r = remove_dir(&path, ignore, verbose).and(r); r = remove_dir(path, ignore, verbose).and(r);
if parents { if parents {
let mut p = path; let mut p = path;
while let Some(new_p) = p.parent() { while let Some(new_p) = p.parent() {

View file

@ -381,7 +381,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
for path_str in matches.values_of(options::FILE).unwrap() { for path_str in matches.values_of(options::FILE).unwrap() {
wipe_file( wipe_file(
&path_str, iterations, remove, size, exact, zero, verbose, force, path_str, iterations, remove, size, exact, zero, verbose, force,
); );
} }
@ -659,7 +659,7 @@ fn do_remove(path: &Path, orig_filename: &str, verbose: bool) -> Result<(), io::
println!("{}: {}: removing", NAME, orig_filename); println!("{}: {}: removing", NAME, orig_filename);
} }
let renamed_path: Option<PathBuf> = wipe_name(&path, verbose); let renamed_path: Option<PathBuf> = wipe_name(path, verbose);
if let Some(rp) = renamed_path { if let Some(rp) = renamed_path {
fs::remove_file(rp)?; fs::remove_file(rp)?;
} }

View file

@ -49,7 +49,7 @@ pub fn check(path: &str, settings: &GlobalSettings) -> i32 {
let prev_last = prev_chunk.borrow_lines().last().unwrap(); let prev_last = prev_chunk.borrow_lines().last().unwrap();
let new_first = chunk.borrow_lines().first().unwrap(); let new_first = chunk.borrow_lines().first().unwrap();
if compare_by(prev_last, new_first, &settings) == Ordering::Greater { if compare_by(prev_last, new_first, settings) == Ordering::Greater {
if !settings.check_silent { if !settings.check_silent {
println!("sort: {}:{}: disorder: {}", path, line_idx, new_first.line); println!("sort: {}:{}: disorder: {}", path, line_idx, new_first.line);
} }
@ -60,7 +60,7 @@ pub fn check(path: &str, settings: &GlobalSettings) -> i32 {
for (a, b) in chunk.borrow_lines().iter().tuple_windows() { for (a, b) in chunk.borrow_lines().iter().tuple_windows() {
line_idx += 1; line_idx += 1;
if compare_by(a, b, &settings) == Ordering::Greater { if compare_by(a, b, settings) == Ordering::Greater {
if !settings.check_silent { if !settings.check_silent {
println!("sort: {}:{}: disorder: {}", path, line_idx, b.line); println!("sort: {}:{}: disorder: {}", path, line_idx, b.line);
} }

View file

@ -90,7 +90,7 @@ pub fn read(
if buffer.len() < carry_over.len() { if buffer.len() < carry_over.len() {
buffer.resize(carry_over.len() + 10 * 1024, 0); buffer.resize(carry_over.len() + 10 * 1024, 0);
} }
buffer[..carry_over.len()].copy_from_slice(&carry_over); buffer[..carry_over.len()].copy_from_slice(carry_over);
let (read, should_continue) = read_to_buffer( let (read, should_continue) = read_to_buffer(
file, file,
next_files, next_files,
@ -110,7 +110,7 @@ pub fn read(
std::mem::transmute::<Vec<Line<'static>>, Vec<Line<'_>>>(lines) std::mem::transmute::<Vec<Line<'static>>, Vec<Line<'_>>>(lines)
}; };
let read = crash_if_err!(1, std::str::from_utf8(&buf[..read])); let read = crash_if_err!(1, std::str::from_utf8(&buf[..read]));
parse_lines(read, &mut lines, separator, &settings); parse_lines(read, &mut lines, separator, settings);
lines lines
}); });
sender.send(payload).unwrap(); sender.send(payload).unwrap();
@ -194,7 +194,7 @@ fn read_to_buffer(
continue; continue;
} }
} }
let mut sep_iter = memchr_iter(separator, &buffer).rev(); let mut sep_iter = memchr_iter(separator, buffer).rev();
let last_line_end = sep_iter.next(); let last_line_end = sep_iter.next();
if sep_iter.next().is_some() { if sep_iter.next().is_some() {
// We read enough lines. // We read enough lines.

View file

@ -38,7 +38,7 @@ pub fn custom_str_cmp(
) -> Ordering { ) -> Ordering {
if !(ignore_case || ignore_non_dictionary || ignore_non_printing) { if !(ignore_case || ignore_non_dictionary || ignore_non_printing) {
// There are no custom settings. Fall back to the default strcmp, which is faster. // There are no custom settings. Fall back to the default strcmp, which is faster.
return a.cmp(&b); return a.cmp(b);
} }
let mut a_chars = a let mut a_chars = a
.chars() .chars()

View file

@ -400,9 +400,9 @@ impl<'a> Line<'a> {
let line = self.line.replace('\t', ">"); let line = self.line.replace('\t', ">");
writeln!(writer, "{}", line)?; writeln!(writer, "{}", line)?;
let fields = tokenize(&self.line, settings.separator); let fields = tokenize(self.line, settings.separator);
for selector in settings.selectors.iter() { for selector in settings.selectors.iter() {
let mut selection = selector.get_range(&self.line, Some(&fields)); let mut selection = selector.get_range(self.line, Some(&fields));
match selector.settings.mode { match selector.settings.mode {
SortMode::Numeric | SortMode::HumanNumeric => { SortMode::Numeric | SortMode::HumanNumeric => {
// find out which range is used for numeric comparisons // find out which range is used for numeric comparisons
@ -756,7 +756,7 @@ impl FieldSelector {
/// Get the selection that corresponds to this selector for the line. /// Get the selection that corresponds to this selector for the line.
/// If needs_fields returned false, tokens may be None. /// If needs_fields returned false, tokens may be None.
fn get_selection<'a>(&self, line: &'a str, tokens: Option<&[Field]>) -> Selection<'a> { fn get_selection<'a>(&self, line: &'a str, tokens: Option<&[Field]>) -> Selection<'a> {
let mut range = &line[self.get_range(&line, tokens)]; let mut range = &line[self.get_range(line, tokens)];
let num_cache = if self.settings.mode == SortMode::Numeric let num_cache = if self.settings.mode == SortMode::Numeric
|| self.settings.mode == SortMode::HumanNumeric || self.settings.mode == SortMode::HumanNumeric
{ {
@ -846,7 +846,7 @@ impl FieldSelector {
match resolve_index(line, tokens, &self.from) { match resolve_index(line, tokens, &self.from) {
Resolution::StartOfChar(from) => { Resolution::StartOfChar(from) => {
let to = self.to.as_ref().map(|to| resolve_index(line, tokens, &to)); let to = self.to.as_ref().map(|to| resolve_index(line, tokens, to));
let mut range = match to { let mut range = match to {
Some(Resolution::StartOfChar(mut to)) => { Some(Resolution::StartOfChar(mut to)) => {
@ -1259,11 +1259,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
fn output_sorted_lines<'a>(iter: impl Iterator<Item = &'a Line<'a>>, settings: &GlobalSettings) { fn output_sorted_lines<'a>(iter: impl Iterator<Item = &'a Line<'a>>, settings: &GlobalSettings) {
if settings.unique { if settings.unique {
print_sorted( print_sorted(
iter.dedup_by(|a, b| compare_by(a, b, &settings) == Ordering::Equal), iter.dedup_by(|a, b| compare_by(a, b, settings) == Ordering::Equal),
&settings, settings,
); );
} else { } else {
print_sorted(iter, &settings); print_sorted(iter, settings);
} }
} }
@ -1279,16 +1279,16 @@ fn exec(files: &[String], settings: &GlobalSettings) -> i32 {
} else { } else {
let mut lines = files.iter().map(open); let mut lines = files.iter().map(open);
ext_sort(&mut lines, &settings); ext_sort(&mut lines, settings);
} }
0 0
} }
fn sort_by<'a>(unsorted: &mut Vec<Line<'a>>, settings: &GlobalSettings) { fn sort_by<'a>(unsorted: &mut Vec<Line<'a>>, settings: &GlobalSettings) {
if settings.stable || settings.unique { if settings.stable || settings.unique {
unsorted.par_sort_by(|a, b| compare_by(a, b, &settings)) unsorted.par_sort_by(|a, b| compare_by(a, b, settings))
} else { } else {
unsorted.par_sort_unstable_by(|a, b| compare_by(a, b, &settings)) unsorted.par_sort_unstable_by(|a, b| compare_by(a, b, settings))
} }
} }

View file

@ -66,7 +66,7 @@ impl FilterWriter {
/// * `filepath` - Path of the output file (forwarded to command as $FILE) /// * `filepath` - Path of the output file (forwarded to command as $FILE)
fn new(command: &str, filepath: &str) -> FilterWriter { fn new(command: &str, filepath: &str) -> FilterWriter {
// set $FILE, save previous value (if there was one) // set $FILE, save previous value (if there was one)
let _with_env_var_set = WithEnvVarSet::new("FILE", &filepath); let _with_env_var_set = WithEnvVarSet::new("FILE", filepath);
let shell_process = let shell_process =
Command::new(env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_owned())) Command::new(env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_owned()))
@ -117,7 +117,7 @@ pub fn instantiate_current_writer(
) as Box<dyn Write>), ) as Box<dyn Write>),
Some(ref filter_command) => BufWriter::new(Box::new( Some(ref filter_command) => BufWriter::new(Box::new(
// spawn a shell command and write to it // spawn a shell command and write to it
FilterWriter::new(&filter_command, &filename), FilterWriter::new(filter_command, filename),
) as Box<dyn Write>), ) as Box<dyn Write>),
} }
} }

View file

@ -477,7 +477,7 @@ impl Stater {
Stater::generate_tokens(&Stater::default_format(show_fs, terse, false), use_printf) Stater::generate_tokens(&Stater::default_format(show_fs, terse, false), use_printf)
.unwrap() .unwrap()
} else { } else {
Stater::generate_tokens(&format_str, use_printf)? Stater::generate_tokens(format_str, use_printf)?
}; };
let default_dev_tokens = let default_dev_tokens =
Stater::generate_tokens(&Stater::default_format(show_fs, terse, true), use_printf) Stater::generate_tokens(&Stater::default_format(show_fs, terse, true), use_printf)

View file

@ -70,9 +70,9 @@ impl<'a> TryFrom<&ArgMatches<'a>> for ProgramOptions {
fn try_from(matches: &ArgMatches) -> Result<Self, Self::Error> { fn try_from(matches: &ArgMatches) -> Result<Self, Self::Error> {
Ok(ProgramOptions { Ok(ProgramOptions {
stdin: check_option(&matches, options::INPUT)?, stdin: check_option(matches, options::INPUT)?,
stdout: check_option(&matches, options::OUTPUT)?, stdout: check_option(matches, options::OUTPUT)?,
stderr: check_option(&matches, options::ERROR)?, stderr: check_option(matches, options::ERROR)?,
}) })
} }
} }

View file

@ -55,7 +55,7 @@ impl Config {
fn from(options: clap::ArgMatches) -> Config { fn from(options: clap::ArgMatches) -> Config {
let signal = match options.value_of(options::SIGNAL) { let signal = match options.value_of(options::SIGNAL) {
Some(signal_) => { Some(signal_) => {
let signal_result = signal_by_name_or_value(&signal_); let signal_result = signal_by_name_or_value(signal_);
match signal_result { match signal_result {
None => { None => {
unreachable!("invalid signal '{}'", signal_); unreachable!("invalid signal '{}'", signal_);
@ -67,7 +67,7 @@ impl Config {
}; };
let kill_after: Duration = match options.value_of(options::KILL_AFTER) { let kill_after: Duration = match options.value_of(options::KILL_AFTER) {
Some(time) => uucore::parse_time::from_str(&time).unwrap(), Some(time) => uucore::parse_time::from_str(time).unwrap(),
None => Duration::new(0, 0), None => Duration::new(0, 0),
}; };

View file

@ -374,8 +374,8 @@ fn wc(inputs: Vec<Input>, settings: &Settings) -> Result<(), u32> {
let num_inputs = inputs.len(); let num_inputs = inputs.len();
for input in &inputs { for input in &inputs {
let word_count = word_count_from_input(&input, settings).unwrap_or_else(|err| { let word_count = word_count_from_input(input, settings).unwrap_or_else(|err| {
show_error(&input, err); show_error(input, err);
error_count += 1; error_count += 1;
WordCount::default() WordCount::default()
}); });

View file

@ -5,7 +5,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) Passwd cstr fnam gecos ngroups // spell-checker:ignore (vars) Passwd cstr fnam gecos ngroups egid
//! Get password/group file entry //! Get password/group file entry
//! //!
@ -72,6 +72,41 @@ pub fn get_groups() -> IOResult<Vec<gid_t>> {
} }
} }
/// The list of group IDs returned from GNU's `groups` and GNU's `id --groups`
/// starts with the effective group ID (egid).
/// This is a wrapper for `get_groups()` to mimic this behavior.
///
/// If `arg_id` is `None` (default), `get_groups_gnu` moves the effective
/// group id (egid) to the first entry in the returned Vector.
/// If `arg_id` is `Some(x)`, `get_groups_gnu` moves the id with value `x`
/// to the first entry in the returned Vector. This might be necessary
/// for `id --groups --real` if `gid` and `egid` are not equal.
///
/// From: https://www.man7.org/linux/man-pages/man3/getgroups.3p.html
/// As implied by the definition of supplementary groups, the
/// effective group ID may appear in the array returned by
/// getgroups() or it may be returned only by getegid(). Duplication
/// may exist, but the application needs to call getegid() to be sure
/// of getting all of the information. Various implementation
/// variations and administrative sequences cause the set of groups
/// appearing in the result of getgroups() to vary in order and as to
/// whether the effective group ID is included, even when the set of
/// groups is the same (in the mathematical sense of ``set''). (The
/// history of a process and its parents could affect the details of
/// the result.)
pub fn get_groups_gnu(arg_id: Option<u32>) -> IOResult<Vec<gid_t>> {
let mut groups = get_groups()?;
let egid = arg_id.unwrap_or_else(crate::features::process::getegid);
if !groups.is_empty() && *groups.first().unwrap() == egid {
return Ok(groups);
} else if let Some(index) = groups.iter().position(|&x| x == egid) {
groups.remove(index);
}
groups.insert(0, egid);
Ok(groups)
}
#[derive(Copy, Clone)]
pub struct Passwd { pub struct Passwd {
inner: passwd, inner: passwd,
} }
@ -268,3 +303,18 @@ pub fn usr2uid(name: &str) -> IOResult<uid_t> {
pub fn grp2gid(name: &str) -> IOResult<gid_t> { pub fn grp2gid(name: &str) -> IOResult<gid_t> {
Group::locate(name).map(|p| p.gid()) Group::locate(name).map(|p| p.gid())
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_entries_get_groups_gnu() {
if let Ok(mut groups) = get_groups() {
if let Some(last) = groups.pop() {
groups.insert(0, last);
assert_eq!(get_groups_gnu(Some(last)).unwrap(), groups);
}
}
}
}

View file

@ -207,7 +207,7 @@ impl Utmpx {
flags: AI_CANONNAME, flags: AI_CANONNAME,
..AddrInfoHints::default() ..AddrInfoHints::default()
}; };
let sockets = getaddrinfo(Some(&hostname), None, Some(hints)) let sockets = getaddrinfo(Some(hostname), None, Some(hints))
.unwrap() .unwrap()
.collect::<IOResult<Vec<_>>>()?; .collect::<IOResult<Vec<_>>>()?;
for socket in sockets { for socket in sockets {

View file

@ -438,7 +438,7 @@ fn test_domain_socket() {
let child = new_ucmd!().args(&[socket_path]).run_no_wait(); let child = new_ucmd!().args(&[socket_path]).run_no_wait();
barrier.wait(); barrier.wait();
let stdout = &child.wait_with_output().unwrap().stdout; let stdout = &child.wait_with_output().unwrap().stdout;
let output = String::from_utf8_lossy(&stdout); let output = String::from_utf8_lossy(stdout);
assert_eq!("a\tb", output); assert_eq!("a\tb", output);
thread.join().unwrap(); thread.join().unwrap();

View file

@ -618,7 +618,7 @@ fn test_cp_deref() {
// Check the content of the destination file that was copied. // Check the content of the destination file that was copied.
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n"); assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
let path_to_check = path_to_new_symlink.to_str().unwrap(); let path_to_check = path_to_new_symlink.to_str().unwrap();
assert_eq!(at.read(&path_to_check), "Hello, World!\n"); assert_eq!(at.read(path_to_check), "Hello, World!\n");
} }
#[test] #[test]
fn test_cp_no_deref() { fn test_cp_no_deref() {
@ -655,7 +655,7 @@ fn test_cp_no_deref() {
// Check the content of the destination file that was copied. // Check the content of the destination file that was copied.
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n"); assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
let path_to_check = path_to_new_symlink.to_str().unwrap(); let path_to_check = path_to_new_symlink.to_str().unwrap();
assert_eq!(at.read(&path_to_check), "Hello, World!\n"); assert_eq!(at.read(path_to_check), "Hello, World!\n");
} }
#[test] #[test]
@ -823,7 +823,7 @@ fn test_cp_deref_folder_to_folder() {
// Check the content of the symlink // Check the content of the symlink
let path_to_check = path_to_new_symlink.to_str().unwrap(); let path_to_check = path_to_new_symlink.to_str().unwrap();
assert_eq!(at.read(&path_to_check), "Hello, World!\n"); assert_eq!(at.read(path_to_check), "Hello, World!\n");
} }
#[test] #[test]
@ -923,7 +923,7 @@ fn test_cp_no_deref_folder_to_folder() {
// Check the content of the symlink // Check the content of the symlink
let path_to_check = path_to_new_symlink.to_str().unwrap(); let path_to_check = path_to_new_symlink.to_str().unwrap();
assert_eq!(at.read(&path_to_check), "Hello, World!\n"); assert_eq!(at.read(path_to_check), "Hello, World!\n");
} }
#[test] #[test]

View file

@ -187,11 +187,10 @@ fn test_change_directory() {
.arg(&temporary_path) .arg(&temporary_path)
.succeeds() .succeeds()
.stdout_move_str(); .stdout_move_str();
assert_eq!(
out.lines() assert!(!out
.any(|line| line.ends_with(temporary_path.file_name().unwrap().to_str().unwrap())), .lines()
false .any(|line| line.ends_with(temporary_path.file_name().unwrap().to_str().unwrap())));
);
} }
#[test] #[test]

View file

@ -1,41 +1,53 @@
use crate::common::util::*; use crate::common::util::*;
#[test] #[test]
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
fn test_groups() { fn test_groups() {
let result = new_ucmd!().run(); if !is_ci() {
println!("result.stdout = {}", result.stdout_str()); new_ucmd!().succeeds().stdout_is(expected_result(&[]));
println!("result.stderr = {}", result.stderr_str()); } else {
if is_ci() && result.stdout_str().trim().is_empty() { // TODO: investigate how this could be tested in CI
// In the CI, some server are failing to return the group. // stderr = groups: cannot find name for group ID 116
// As seems to be a configuration issue, ignoring it println!("test skipped:");
return;
} }
result.success();
assert!(!result.stdout_str().trim().is_empty());
} }
#[test] #[test]
fn test_groups_arg() { #[cfg(any(target_os = "linux"))]
// get the username with the "id -un" command #[ignore = "fixme: 'groups USERNAME' needs more debugging"]
let result = TestScenario::new("id").ucmd_keepenv().arg("-un").run(); fn test_groups_username() {
println!("result.stdout = {}", result.stdout_str()); let scene = TestScenario::new(util_name!());
println!("result.stderr = {}", result.stderr_str()); let whoami_result = scene.cmd("whoami").run();
let s1 = String::from(result.stdout_str().trim());
if is_ci() && s1.parse::<f64>().is_ok() { let username = if whoami_result.succeeded() {
// In the CI, some server are failing to return id -un. whoami_result.stdout_move_str()
// So, if we are getting a uid, just skip this test } else if is_ci() {
// As seems to be a configuration issue, ignoring it String::from("docker")
} else {
println!("test skipped:");
return; return;
} };
println!("result.stdout = {}", result.stdout_str()); // TODO: stdout should be in the form: "username : group1 group2 group3"
println!("result.stderr = {}", result.stderr_str());
result.success();
assert!(!result.stdout_str().is_empty());
let username = result.stdout_str().trim();
// call groups with the user name to check that we scene
// are getting something .ucmd()
new_ucmd!().arg(username).succeeds(); .arg(&username)
assert!(!result.stdout_str().is_empty()); .succeeds()
.stdout_is(expected_result(&[&username]));
}
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
fn expected_result(args: &[&str]) -> String {
#[cfg(target_os = "linux")]
let util_name = util_name!();
#[cfg(target_vendor = "apple")]
let util_name = format!("g{}", util_name!());
TestScenario::new(&util_name)
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.args(args)
.succeeds()
.stdout_move_str()
} }

View file

@ -104,19 +104,23 @@ fn test_id_group() {
} }
#[test] #[test]
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
fn test_id_groups() { fn test_id_groups() {
let scene = TestScenario::new(util_name!()); let scene = TestScenario::new(util_name!());
for g_flag in &["-G", "--groups"] {
let result = scene.ucmd().arg("-G").succeeds(); scene
let groups = result.stdout_str().trim().split_whitespace(); .ucmd()
for s in groups { .arg(g_flag)
assert!(s.parse::<f64>().is_ok()); .succeeds()
} .stdout_is(expected_result(&[g_flag], false));
for &r_flag in &["-r", "--real"] {
let result = scene.ucmd().arg("--groups").succeeds(); let args = [g_flag, r_flag];
let groups = result.stdout_str().trim().split_whitespace(); scene
for s in groups { .ucmd()
assert!(s.parse::<f64>().is_ok()); .args(&args)
.succeeds()
.stdout_is(expected_result(&args, false));
}
} }
} }
@ -167,3 +171,32 @@ fn test_id_password_style() {
assert!(result.stdout_str().starts_with(&username)); assert!(result.stdout_str().starts_with(&username));
} }
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
fn expected_result(args: &[&str], exp_fail: bool) -> String {
#[cfg(target_os = "linux")]
let util_name = util_name!();
#[cfg(target_vendor = "apple")]
let util_name = format!("g{}", util_name!());
let result = if !exp_fail {
TestScenario::new(&util_name)
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.args(args)
.succeeds()
.stdout_move_str()
} else {
TestScenario::new(&util_name)
.cmd_keepenv(util_name)
.env("LANGUAGE", "C")
.args(args)
.fails()
.stderr_move_str()
};
return if cfg!(target_os = "macos") && result.starts_with("gid") {
result[1..].to_string()
} else {
result
};
}

View file

@ -398,7 +398,7 @@ fn test_ls_long_formats() {
.arg("--author") .arg("--author")
.arg("test-long-formats") .arg("test-long-formats")
.succeeds(); .succeeds();
assert!(re_three.is_match(&result.stdout_str())); assert!(re_three.is_match(result.stdout_str()));
#[cfg(unix)] #[cfg(unix)]
{ {
@ -701,20 +701,20 @@ fn test_ls_styles() {
.arg("-l") .arg("-l")
.arg("--time-style=full-iso") .arg("--time-style=full-iso")
.succeeds(); .succeeds();
assert!(re_full.is_match(&result.stdout_str())); assert!(re_full.is_match(result.stdout_str()));
//long-iso //long-iso
let result = scene let result = scene
.ucmd() .ucmd()
.arg("-l") .arg("-l")
.arg("--time-style=long-iso") .arg("--time-style=long-iso")
.succeeds(); .succeeds();
assert!(re_long.is_match(&result.stdout_str())); assert!(re_long.is_match(result.stdout_str()));
//iso //iso
let result = scene.ucmd().arg("-l").arg("--time-style=iso").succeeds(); let result = scene.ucmd().arg("-l").arg("--time-style=iso").succeeds();
assert!(re_iso.is_match(&result.stdout_str())); assert!(re_iso.is_match(result.stdout_str()));
//locale //locale
let result = scene.ucmd().arg("-l").arg("--time-style=locale").succeeds(); let result = scene.ucmd().arg("-l").arg("--time-style=locale").succeeds();
assert!(re_locale.is_match(&result.stdout_str())); assert!(re_locale.is_match(result.stdout_str()));
//Overwrite options tests //Overwrite options tests
let result = scene let result = scene
@ -723,19 +723,19 @@ fn test_ls_styles() {
.arg("--time-style=long-iso") .arg("--time-style=long-iso")
.arg("--time-style=iso") .arg("--time-style=iso")
.succeeds(); .succeeds();
assert!(re_iso.is_match(&result.stdout_str())); assert!(re_iso.is_match(result.stdout_str()));
let result = scene let result = scene
.ucmd() .ucmd()
.arg("--time-style=iso") .arg("--time-style=iso")
.arg("--full-time") .arg("--full-time")
.succeeds(); .succeeds();
assert!(re_full.is_match(&result.stdout_str())); assert!(re_full.is_match(result.stdout_str()));
let result = scene let result = scene
.ucmd() .ucmd()
.arg("--full-time") .arg("--full-time")
.arg("--time-style=iso") .arg("--time-style=iso")
.succeeds(); .succeeds();
assert!(re_iso.is_match(&result.stdout_str())); assert!(re_iso.is_match(result.stdout_str()));
let result = scene let result = scene
.ucmd() .ucmd()
@ -743,7 +743,7 @@ fn test_ls_styles() {
.arg("--time-style=iso") .arg("--time-style=iso")
.arg("--full-time") .arg("--full-time")
.succeeds(); .succeeds();
assert!(re_full.is_match(&result.stdout_str())); assert!(re_full.is_match(result.stdout_str()));
let result = scene let result = scene
.ucmd() .ucmd()
@ -751,7 +751,7 @@ fn test_ls_styles() {
.arg("-x") .arg("-x")
.arg("-l") .arg("-l")
.succeeds(); .succeeds();
assert!(re_full.is_match(&result.stdout_str())); assert!(re_full.is_match(result.stdout_str()));
at.touch("test2"); at.touch("test2");
let result = scene.ucmd().arg("--full-time").arg("-x").succeeds(); let result = scene.ucmd().arg("--full-time").arg("-x").succeeds();
@ -1143,7 +1143,7 @@ fn test_ls_indicator_style() {
for opt in options { for opt in options {
scene scene
.ucmd() .ucmd()
.arg(format!("{}", opt)) .arg(opt.to_string())
.succeeds() .succeeds()
.stdout_contains(&"/"); .stdout_contains(&"/");
} }

View file

@ -38,7 +38,7 @@ fn test_posix_mode() {
// fail on long path // fail on long path
new_ucmd!() new_ucmd!()
.args(&["-p", &"dir".repeat(libc::PATH_MAX as usize + 1).as_str()]) .args(&["-p", "dir".repeat(libc::PATH_MAX as usize + 1).as_str()])
.fails() .fails()
.no_stdout(); .no_stdout();
@ -46,7 +46,7 @@ fn test_posix_mode() {
new_ucmd!() new_ucmd!()
.args(&[ .args(&[
"-p", "-p",
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(), format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
]) ])
.fails() .fails()
.no_stdout(); .no_stdout();
@ -76,7 +76,7 @@ fn test_posix_special() {
// fail on long path // fail on long path
new_ucmd!() new_ucmd!()
.args(&["-P", &"dir".repeat(libc::PATH_MAX as usize + 1).as_str()]) .args(&["-P", "dir".repeat(libc::PATH_MAX as usize + 1).as_str()])
.fails() .fails()
.no_stdout(); .no_stdout();
@ -84,7 +84,7 @@ fn test_posix_special() {
new_ucmd!() new_ucmd!()
.args(&[ .args(&[
"-P", "-P",
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(), format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
]) ])
.fails() .fails()
.no_stdout(); .no_stdout();
@ -117,7 +117,7 @@ fn test_posix_all() {
.args(&[ .args(&[
"-p", "-p",
"-P", "-P",
&"dir".repeat(libc::PATH_MAX as usize + 1).as_str(), "dir".repeat(libc::PATH_MAX as usize + 1).as_str(),
]) ])
.fails() .fails()
.no_stdout(); .no_stdout();
@ -127,7 +127,7 @@ fn test_posix_all() {
.args(&[ .args(&[
"-p", "-p",
"-P", "-P",
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(), format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
]) ])
.fails() .fails()
.no_stdout(); .no_stdout();

View file

@ -102,6 +102,8 @@ fn expected_result(args: &[&str]) -> String {
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
let util_name = format!("g{}", util_name!()); let util_name = format!("g{}", util_name!());
// note: clippy::needless_borrow *false positive*
#[allow(clippy::needless_borrow)]
TestScenario::new(&util_name) TestScenario::new(&util_name)
.cmd_keepenv(util_name) .cmd_keepenv(util_name)
.env("LANGUAGE", "C") .env("LANGUAGE", "C")

View file

@ -313,6 +313,8 @@ fn expected_result(args: &[&str]) -> String {
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
let util_name = format!("g{}", util_name!()); let util_name = format!("g{}", util_name!());
// note: clippy::needless_borrow *false positive*
#[allow(clippy::needless_borrow)]
TestScenario::new(&util_name) TestScenario::new(&util_name)
.cmd_keepenv(util_name) .cmd_keepenv(util_name)
.env("LANGUAGE", "C") .env("LANGUAGE", "C")

View file

@ -13,6 +13,8 @@ fn test_users_check_name() {
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
let util_name = format!("g{}", util_name!()); let util_name = format!("g{}", util_name!());
// note: clippy::needless_borrow *false positive*
#[allow(clippy::needless_borrow)]
let expected = TestScenario::new(&util_name) let expected = TestScenario::new(&util_name)
.cmd_keepenv(util_name) .cmd_keepenv(util_name)
.env("LANGUAGE", "C") .env("LANGUAGE", "C")

View file

@ -238,6 +238,8 @@ fn expected_result(args: &[&str]) -> String {
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
let util_name = format!("g{}", util_name!()); let util_name = format!("g{}", util_name!());
// note: clippy::needless_borrow *false positive*
#[allow(clippy::needless_borrow)]
TestScenario::new(&util_name) TestScenario::new(&util_name)
.cmd_keepenv(util_name) .cmd_keepenv(util_name)
.env("LANGUAGE", "C") .env("LANGUAGE", "C")

View file

@ -625,11 +625,20 @@ impl AtPath {
// Source: // Source:
// http://stackoverflow.com/questions/31439011/getfinalpathnamebyhandle-without-prepended // http://stackoverflow.com/questions/31439011/getfinalpathnamebyhandle-without-prepended
let prefix = "\\\\?\\"; let prefix = "\\\\?\\";
// FixME: replace ...
#[allow(clippy::manual_strip)]
if s.starts_with(prefix) { if s.starts_with(prefix) {
String::from(&s[prefix.len()..]) String::from(&s[prefix.len()..])
} else { } else {
s s
} }
// ... with ...
// if let Some(stripped) = s.strip_prefix(prefix) {
// String::from(stripped)
// } else {
// s
// }
// ... when using MSRV with stabilized `strip_prefix()`
} }
} }

View file

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# spell-checker:ignore (paths) abmon deref discrim getlimits getopt ginstall gnulib inacc infloop inotify reflink ; (misc) INT_OFLOW OFLOW ; (vars/env) BUILDDIR SRCDIR # spell-checker:ignore (paths) abmon deref discrim eacces getlimits getopt ginstall gnulib inacc infloop inotify reflink ; (misc) INT_OFLOW OFLOW ; (vars/env) BUILDDIR SRCDIR
set -e set -e
if test ! -d ../gnu; then if test ! -d ../gnu; then