mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 11:07:44 +00:00
Merge pull request #1449 from rivy/add.cicd
Improves build and maint; fixes all testing issues; adds GHA CICD; fixes a long list of lints
This commit is contained in:
commit
08a2cd0fc8
249 changed files with 3375 additions and 2478 deletions
|
@ -1,5 +1,5 @@
|
|||
# spell-checker:words POSIX repo SDK SDKs toolchain toolchains
|
||||
# spell-checker:ignore uutils ARCH ABI BACKTRACE BINDIR cl COMNTOOLS dllcrt findstr maint MINGW MINGWDIR mkdir MSVC MSYS rustc rustlib rustup USERPROFILE vcvarsall
|
||||
# spell-checker:words POSIX SDK SDKs repo toolchain toolchains
|
||||
# spell-checker:ignore ABI ARCH BACKTRACE BINDIR COMNTOOLS MINGW MINGWDIR MSVC MSYS USERPROFILE cl dllcrt findstr maint mkdir rustc rustlib rustup targetting uutils vcvarsall
|
||||
|
||||
version: "{build} ~ {branch}"
|
||||
|
||||
|
@ -21,8 +21,8 @@ matrix:
|
|||
environment:
|
||||
global:
|
||||
FEATURES: "windows"
|
||||
BUILD_OPTIONS: "--no-default-features"
|
||||
TEST_OPTIONS: "--no-default-features --no-fail-fast"
|
||||
BUILD_OPTIONS: ""
|
||||
TEST_OPTIONS: "--no-fail-fast"
|
||||
|
||||
matrix:
|
||||
# minimum version
|
||||
|
@ -69,6 +69,7 @@ environment:
|
|||
# - CHANNEL: nightly
|
||||
# ARCH: x86_64
|
||||
# ABI: gnu
|
||||
# FEATURES: "windows nightly"
|
||||
# * specific gnu compilers
|
||||
- CHANNEL: stable
|
||||
ARCH: i686
|
||||
|
@ -83,8 +84,8 @@ environment:
|
|||
install:
|
||||
# force branch checkout (if knowable), then reset to the specific commit ## (can be needed for accurate code coverage info)
|
||||
# * this allows later apps to see the branch name using standard `git branch` operations, yet always builds the correct specific commit
|
||||
# * ref: <https://github.com/appveyor/ci/issues/1606>[`@`](https://archive.is/RVpnF)
|
||||
- if DEFINED APPVEYOR_REPO_BRANCH if /I "%APPVEYOR_REPO_SCM%"=="git" ( git checkout "%APPVEYOR_REPO_BRANCH%" 2>NUL & git reset --hard "%APPVEYOR_REPO_COMMIT%" )
|
||||
# * ref: <https://github.com/appveyor/ci/issues/1606>[`@`](https://archive.is/RVpnF) ; note: `git branch -a` may be helpful for debugging edge cases
|
||||
- if DEFINED APPVEYOR_REPO_BRANCH if /I "%APPVEYOR_REPO_SCM%"=="git" ( git checkout "%APPVEYOR_REPO_BRANCH%" 2>NUL & git reset --hard FETCH_HEAD 2>NUL || git reset --hard "%APPVEYOR_REPO_COMMIT%" )
|
||||
# ensure CWD is project main directory
|
||||
- cd "%APPVEYOR_BUILD_FOLDER%"
|
||||
# create a working area
|
||||
|
|
361
.github/workflows/CICD.yml
vendored
Normal file
361
.github/workflows/CICD.yml
vendored
Normal file
|
@ -0,0 +1,361 @@
|
|||
name: CICD
|
||||
|
||||
# spell-checker:ignore (acronyms) CICD MSVC musl
|
||||
# spell-checker:ignore (env/flags) Ccodegen Cinline Coverflow RUSTFLAGS
|
||||
# spell-checker:ignore (jargon) SHAs deps softprops toolchain
|
||||
# spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy
|
||||
# spell-checker:ignore (shell/tools) choco clippy dmake esac fakeroot gmake grcov halium libssl mkdir popd printf pushd rustc rustfmt rustup shopt
|
||||
# spell-checker:ignore (misc) alnum gnueabihf issuecomment maint nullglob onexitbegin onexitend uutils
|
||||
|
||||
|
||||
env:
|
||||
PROJECT_NAME: uutils
|
||||
PROJECT_DESC: "'Universal' (cross-platform) CLI utilities"
|
||||
PROJECT_AUTH: "uutils"
|
||||
RUST_MIN_SRV: "1.31.0"
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
style:
|
||||
name: Style
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- { os: ubuntu-latest , features: unix }
|
||||
- { os: macos-latest , features: unix }
|
||||
- { os: windows-latest , features: windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
## VARs setup
|
||||
# #maint: [rivy; 2020-02-08] 'windows-latest' `cargo fmt` is bugged for this project (see reasons @ GH:rust-lang/rustfmt #3324, #3590, #3688 ; waiting for repair)
|
||||
JOB_DO_FORMAT_TESTING="true"
|
||||
case '${{ matrix.job.os }}' in windows-latest) unset JOB_DO_FORMAT_TESTING ;; esac;
|
||||
echo set-output name=JOB_DO_FORMAT_TESTING::${JOB_DO_FORMAT_TESTING:-<empty>/false}
|
||||
echo ::set-output name=JOB_DO_FORMAT_TESTING::${JOB_DO_FORMAT_TESTING}
|
||||
# target-specific options
|
||||
# * CARGO_FEATURES_OPTION
|
||||
CARGO_FEATURES_OPTION='' ;
|
||||
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
|
||||
echo set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
|
||||
echo ::set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
|
||||
- name: Install `rust` toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
components: rustfmt, clippy
|
||||
- name: "`fmt` testing"
|
||||
if: steps.vars.outputs.JOB_DO_FORMAT_TESTING
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- name: "`clippy` testing"
|
||||
if: success() || failure() # run regardless of prior step ("`fmt` testing") success/failure
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -- -D warnings
|
||||
|
||||
min_version:
|
||||
name: MinSRV # Minimum supported rust version
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
job:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install `rust` toolchain (v${{ env.RUST_MIN_SRV }})
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_MIN_SRV }}
|
||||
default: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
- name: Install `cargo-tree` # for dependency information
|
||||
uses: actions-rs/install@v0.1
|
||||
with:
|
||||
crate: cargo-tree
|
||||
version: latest
|
||||
use-tool-cache: true
|
||||
env:
|
||||
RUSTUP_TOOLCHAIN: stable
|
||||
- name: Info
|
||||
shell: bash
|
||||
run: |
|
||||
# Info
|
||||
## tooling info display
|
||||
echo "## tooling"
|
||||
which gcc >/dev/null 2>&1 && (gcc --version | head -1) || true
|
||||
rustup -V
|
||||
rustup show active-toolchain
|
||||
cargo -V
|
||||
rustc -V
|
||||
## dependencies
|
||||
echo "## dependency list"
|
||||
cargo +stable fetch --quiet
|
||||
cargo +stable tree --all --no-dev-dependencies --no-indent --features ${{ matrix.job.features }} | grep -vE "$PWD" | sort --unique
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --features "feat_os_unix"
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# { os, target, cargo-options, features, use-cross, toolchain }
|
||||
- { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf , features: feat_os_unix_gnueabihf , use-cross: use-cross }
|
||||
- { os: ubuntu-16.04 , target: x86_64-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross }
|
||||
- { os: ubuntu-18.04 , target: i686-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross }
|
||||
- { os: ubuntu-18.04 , target: i686-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross }
|
||||
- { os: ubuntu-18.04 , target: x86_64-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross }
|
||||
- { os: ubuntu-18.04 , target: x86_64-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross }
|
||||
- { os: macos-latest , target: x86_64-apple-darwin , features: feat_os_unix }
|
||||
- { os: windows-latest , target: i686-pc-windows-gnu , features: feat_os_windows }
|
||||
- { os: windows-latest , target: i686-pc-windows-msvc , features: feat_os_windows }
|
||||
- { os: windows-latest , target: x86_64-pc-windows-gnu , features: feat_os_windows , toolchain: nightly-x86_64-pc-windows-gnu } ## !maint: [rivy; due 2020-21-03] disable/remove when rust beta >= v1.43.0 is available (~mid-March)
|
||||
# - { os: windows-latest , target: x86_64-pc-windows-gnu , features: feat_os_windows , toolchain: beta-x86_64-pc-windows-gnu } ## maint: [rivy; due 2020-21-03; due 2020-01-05] enable when rust beta >= v1.43.0 is available (~mid-March); disable when rust stable >= 1.43.0 is available (~early-May)
|
||||
# - { os: windows-latest , target: x86_64-pc-windows-gnu , features: feat_os_windows } ## note: requires rust >= 1.43.0 to link correctly # ! maint: [rivy; due 2020-01-05] enable when rust stable >= 1.43.0 is available
|
||||
- { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install/setup prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
## install/setup prerequisites
|
||||
case '${{ matrix.job.target }}' in
|
||||
arm-unknown-linux-gnueabihf) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
|
||||
x86_64-pc-windows-gnu)
|
||||
# hack: move interfering 'gcc' to head of PATH; fixes linking errors, but only works for rust >= v1.43.0; see GH:rust-lang/rust#68872 (after potential fix GH:rust-lang/rust#67429) for further discussion/repairs; follow issue/solutions? via PR GH:rust-lang/rust#67429 (from GH:rust-lang/rust#47048#issuecomment-437409270); refs: GH:rust-lang/cargo#6754, GH:rust-lang/rust#47048 , GH:rust-lang/rust#53454 , GH:bike-barn/hermit#172
|
||||
echo "::add-path::C:\\ProgramData\\Chocolatey\\lib\\mingw\\tools\\install\\mingw64\\bin"
|
||||
;;
|
||||
esac
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
## VARs setup
|
||||
# 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)
|
||||
case ${{ matrix.job.target }} in *-pc-windows-gnu) TOOLCHAIN="stable-${{ matrix.job.target }}" ;; esac;
|
||||
# * use requested TOOLCHAIN if specified
|
||||
if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi
|
||||
echo set-output name=TOOLCHAIN::${TOOLCHAIN:-<empty>/false}
|
||||
echo ::set-output name=TOOLCHAIN::${TOOLCHAIN}
|
||||
# staging directory
|
||||
STAGING='_staging'
|
||||
echo set-output name=STAGING::${STAGING}
|
||||
echo ::set-output name=STAGING::${STAGING}
|
||||
# determine EXE suffix
|
||||
EXE_suffix="" ; case '${{ matrix.job.target }}' in *-pc-windows-*) EXE_suffix=".exe" ;; esac;
|
||||
echo set-output name=EXE_suffix::${EXE_suffix}
|
||||
echo ::set-output name=EXE_suffix::${EXE_suffix}
|
||||
# parse commit reference info
|
||||
echo GITHUB_REF=${GITHUB_REF}
|
||||
echo GITHUB_SHA=${GITHUB_SHA}
|
||||
REF_NAME=${GITHUB_REF#refs/*/}
|
||||
unset REF_BRANCH ; case "${GITHUB_REF}" in refs/heads/*) REF_BRANCH=${GITHUB_REF#refs/heads/} ;; esac;
|
||||
unset REF_TAG ; case "${GITHUB_REF}" in refs/tags/*) REF_TAG=${GITHUB_REF#refs/tags/} ;; esac;
|
||||
REF_SHAS=${GITHUB_SHA:0:8}
|
||||
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}
|
||||
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
|
||||
unset TARGET_ARCH ; case '${{ matrix.job.target }}' in arm-unknown-linux-gnueabihf) TARGET_ARCH=arm ;; i686-*) TARGET_ARCH=i686 ;; x86_64-*) TARGET_ARCH=x86_64 ;; 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;
|
||||
echo set-output name=TARGET_OS::${TARGET_OS}
|
||||
echo ::set-output name=TARGET_OS::${TARGET_OS}
|
||||
# package name
|
||||
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_NAME=${PKG_BASENAME}${PKG_suffix}
|
||||
echo set-output name=PKG_suffix::${PKG_suffix}
|
||||
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)
|
||||
unset DEPLOYABLE ; if [[ $REF_TAG =~ ^[vV]?[0-9].* ]]; then DEPLOYABLE='true' ; fi
|
||||
echo set-output name=DEPLOYABLE::${DEPLOYABLE:-<empty>/false}
|
||||
echo ::set-output name=DEPLOYABLE::${DEPLOYABLE}
|
||||
# target-specific options
|
||||
# * CARGO_FEATURES_OPTION
|
||||
CARGO_FEATURES_OPTION='' ;
|
||||
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
|
||||
echo set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
|
||||
echo ::set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
|
||||
# * CARGO_USE_CROSS (truthy)
|
||||
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}
|
||||
echo ::set-output name=CARGO_USE_CROSS::${CARGO_USE_CROSS}
|
||||
# # * `arm` cannot be tested on ubuntu-* hosts (b/c testing is currently primarily done via comparison of target outputs with built-in outputs and the `arm` target is not executable on the host)
|
||||
JOB_DO_TESTING="true"
|
||||
case '${{ matrix.job.target }}' in arm-*) unset JOB_DO_TESTING ;; esac;
|
||||
echo set-output name=JOB_DO_TESTING::${JOB_DO_TESTING:-<empty>/false}
|
||||
echo ::set-output name=JOB_DO_TESTING::${JOB_DO_TESTING}
|
||||
# # * test only binary for arm-type targets
|
||||
unset CARGO_TEST_OPTIONS
|
||||
unset CARGO_TEST_OPTIONS ; case '${{ matrix.job.target }}' in arm-*) CARGO_TEST_OPTIONS="--bin ${PROJECT_NAME}" ;; esac;
|
||||
echo set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
|
||||
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
|
||||
# * strip executable?
|
||||
STRIP="strip" ; case '${{ matrix.job.target }}' in arm-unknown-linux-gnueabihf) STRIP="arm-linux-gnueabihf-strip" ;; *-pc-windows-msvc) STRIP="" ;; esac;
|
||||
echo set-output name=STRIP::${STRIP:-<empty>/false}
|
||||
echo ::set-output name=STRIP::${STRIP}
|
||||
- name: Create all needed build/work directories
|
||||
shell: bash
|
||||
run: |
|
||||
## create build/work space
|
||||
mkdir -p '${{ steps.vars.outputs.STAGING }}'
|
||||
mkdir -p '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}'
|
||||
- name: rust toolchain ~ install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ steps.vars.outputs.TOOLCHAIN }}
|
||||
target: ${{ matrix.job.target }}
|
||||
default: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
- name: Install `cargo-tree` # for dependency information
|
||||
uses: actions-rs/install@v0.1
|
||||
with:
|
||||
crate: cargo-tree
|
||||
version: latest
|
||||
use-tool-cache: true
|
||||
env:
|
||||
RUSTUP_TOOLCHAIN: stable
|
||||
- name: Info
|
||||
shell: bash
|
||||
run: |
|
||||
# Info
|
||||
## tooling info display
|
||||
echo "## tooling"
|
||||
which gcc >/dev/null 2>&1 && (gcc --version | head -1) || true
|
||||
rustup -V
|
||||
rustup show active-toolchain
|
||||
cargo -V
|
||||
rustc -V
|
||||
## dependencies
|
||||
echo "## dependency list"
|
||||
cargo fetch --quiet
|
||||
cargo tree --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --all --no-dev-dependencies --no-indent | grep -vE "$PWD" | sort --unique
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
||||
command: build
|
||||
args: --release --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
||||
command: test
|
||||
args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
|
||||
- name: Archive executable artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ${{ env.PROJECT_NAME }}-${{ matrix.job.target }}
|
||||
path: target/${{ matrix.job.target }}/release/${{ env.PROJECT_NAME }}${{ steps.vars.outputs.EXE_suffix }}
|
||||
- name: Package
|
||||
shell: bash
|
||||
run: |
|
||||
## package artifact(s)
|
||||
# binary
|
||||
cp 'target/${{ matrix.job.target }}/release/${{ env.PROJECT_NAME }}${{ steps.vars.outputs.EXE_suffix }}' '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/'
|
||||
# `strip` binary (if needed)
|
||||
if [ -n "${{ steps.vars.outputs.STRIP }}" ]; then "${{ steps.vars.outputs.STRIP }}" '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/${{ env.PROJECT_NAME }}${{ steps.vars.outputs.EXE_suffix }}' ; fi
|
||||
# README and LICENSE
|
||||
# * spell-checker:ignore EADME ICENSE
|
||||
(shopt -s nullglob; for f in [R]"EADME"{,.*}; do cp $f '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/' ; done)
|
||||
(shopt -s nullglob; for f in [L]"ICENSE"{-*,}{,.*}; do cp $f '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/' ; done)
|
||||
# core compressed package
|
||||
pushd '${{ steps.vars.outputs.STAGING }}/' >/dev/null
|
||||
case '${{ matrix.job.target }}' in
|
||||
*-pc-windows-*) 7z -y a '${{ steps.vars.outputs.PKG_NAME }}' '${{ steps.vars.outputs.PKG_BASENAME }}'/* | tail -2 ;;
|
||||
*) tar czf '${{ steps.vars.outputs.PKG_NAME }}' '${{ steps.vars.outputs.PKG_BASENAME }}'/* ;;
|
||||
esac
|
||||
popd >/dev/null
|
||||
- name: Publish
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: steps.vars.outputs.DEPLOYABLE
|
||||
with:
|
||||
files: |
|
||||
${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_NAME }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
coverage:
|
||||
name: Code Coverage
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
# job: [ { os: ubuntu-latest }, { os: macos-latest }, { os: windows-latest } ]
|
||||
job: [ { os: ubuntu-latest } ] ## cargo-tarpaulin is currently only available on linux
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
# - name: Reattach HEAD ## may be needed for accurate code coverage info
|
||||
# run: git checkout ${{ github.head_ref }}
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
## VARs setup
|
||||
# staging directory
|
||||
STAGING='_staging'
|
||||
echo set-output name=STAGING::${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>)
|
||||
unset HAS_CODECOV_TOKEN
|
||||
if [ -n $CODECOV_TOKEN ]; then HAS_CODECOV_TOKEN='true' ; fi
|
||||
echo set-output name=HAS_CODECOV_TOKEN::${HAS_CODECOV_TOKEN}
|
||||
echo ::set-output name=HAS_CODECOV_TOKEN::${HAS_CODECOV_TOKEN}
|
||||
env:
|
||||
CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
||||
- name: Create all needed build/work directories
|
||||
shell: bash
|
||||
run: |
|
||||
## create build/work space
|
||||
mkdir -p '${{ steps.vars.outputs.STAGING }}/work'
|
||||
- name: Install required packages
|
||||
run: |
|
||||
sudo apt-get -y install libssl-dev
|
||||
pushd '${{ steps.vars.outputs.STAGING }}/work' >/dev/null
|
||||
wget --no-verbose https://github.com/xd009642/tarpaulin/releases/download/0.9.3/cargo-tarpaulin-0.9.3-travis.tar.gz
|
||||
tar xf cargo-tarpaulin-0.9.3-travis.tar.gz
|
||||
cp cargo-tarpaulin "$(dirname -- "$(which cargo)")"/
|
||||
popd >/dev/null
|
||||
- name: Generate coverage
|
||||
run: |
|
||||
cargo tarpaulin --out Xml
|
||||
- name: Upload coverage results (CodeCov.io)
|
||||
# CODECOV_TOKEN (aka, "Repository Upload Token" for REPO from CodeCov.io) ## set via REPO/Settings/Secrets
|
||||
# if: secrets.CODECOV_TOKEN (not supported {yet?}; see <https://github.community/t5/GitHub-Actions/jobs-lt-job-id-gt-if-does-not-work-with-env-secrets/m-p/38549>)
|
||||
if: steps.vars.outputs.HAS_CODECOV_TOKEN
|
||||
run: |
|
||||
# CodeCov.io
|
||||
cargo tarpaulin --out Xml
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
env:
|
||||
CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
11
.travis.yml
11
.travis.yml
|
@ -19,21 +19,22 @@ matrix:
|
|||
fast_finish: true
|
||||
include:
|
||||
- rust: 1.31.0
|
||||
env: FEATURES=unix
|
||||
- rust: stable
|
||||
os: linux
|
||||
env: TEST_INSTALL=true
|
||||
env: FEATURES=unix TEST_INSTALL=true
|
||||
- rust: stable
|
||||
os: osx
|
||||
env: TEST_INSTALL=true
|
||||
env: FEATURES=macos TEST_INSTALL=true
|
||||
- rust: nightly
|
||||
os: linux
|
||||
env: FEATURES=nightly
|
||||
env: FEATURES=nightly,unix
|
||||
- rust: nightly
|
||||
os: osx
|
||||
env: FEATURES=nightly
|
||||
env: FEATURES=nightly,macos
|
||||
- rust: nightly
|
||||
os: linux
|
||||
env: FEATURES=nightly,redox CC=x86_64-unknown-redox-gcc CARGO_ARGS='--no-default-features --target=x86_64-unknown-redox' REDOX=1
|
||||
env: FEATURES=nightly,feat_os_unix_redox CC=x86_64-unknown-redox-gcc CARGO_ARGS='--no-default-features --target=x86_64-unknown-redox' REDOX=1
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
|
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -57,7 +57,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.15"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -894,7 +894,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.13.0"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1904,7 +1904,7 @@ dependencies = [
|
|||
"getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"platform-info 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2194,7 +2194,7 @@ dependencies = [
|
|||
"checksum md5 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "79c56d6a0b07f9e19282511c83fc5b086364cbae4ba8c7d5f190c3d9b0425a48"
|
||||
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
|
||||
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
|
||||
"checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b"
|
||||
"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b"
|
||||
"checksum nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47e49f6982987135c5e9620ab317623e723bd06738fd85377e8d55f57c8b6487"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
|
|
151
Cargo.toml
151
Cargo.toml
|
@ -6,7 +6,54 @@ build = "build.rs"
|
|||
autotests = false
|
||||
|
||||
[features]
|
||||
unix = [
|
||||
default = [ "feat_common_core" ]
|
||||
## OS feature shortcodes
|
||||
macos = [ "feat_os_unix" ]
|
||||
unix = [ "feat_os_unix" ]
|
||||
windows = [ "feat_os_windows" ]
|
||||
## project-specific feature shortcodes
|
||||
nightly = []
|
||||
test_unimplemented = []
|
||||
## feature sets
|
||||
# "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms
|
||||
feat_os_unix = [
|
||||
"feat_common",
|
||||
"feat_os_unix_musl",
|
||||
"feat_os_unix_utmpx_required",
|
||||
#
|
||||
"stdbuf",
|
||||
]
|
||||
# "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuschia" OS (refs: <https://fuchsia.dev>; <https://en.wikipedia.org/wiki/Google_Fuchsia>)
|
||||
feat_os_unix_fuchsia = [
|
||||
"feat_common_core",
|
||||
#
|
||||
"chgrp",
|
||||
"chmod",
|
||||
"chown",
|
||||
"du",
|
||||
"groups",
|
||||
"hostid",
|
||||
"install",
|
||||
"logname",
|
||||
"mkfifo",
|
||||
"mknod",
|
||||
"nice",
|
||||
"pathchk",
|
||||
"stdbuf",
|
||||
"tty",
|
||||
"uname",
|
||||
"unlink",
|
||||
]
|
||||
# "feat_os_unix_gnueabihf" == set of utilities which can be built/run on the "arm-unknown-linux-gnueabihf" target (ARMv6 Linux [hardfloat])
|
||||
feat_os_unix_gnueabihf = [
|
||||
"feat_common",
|
||||
"feat_os_unix_musl",
|
||||
"feat_os_unix_utmpx_required",
|
||||
]
|
||||
# "feat_os_unix_musl" == set of utilities which can be built/run on targets binding to the "musl" library (ref: <https://musl.libc.org/about.html>)
|
||||
feat_os_unix_musl = [
|
||||
"feat_common",
|
||||
#
|
||||
"chgrp",
|
||||
"chmod",
|
||||
"chown",
|
||||
|
@ -24,74 +71,57 @@ unix = [
|
|||
"numfmt",
|
||||
"nohup",
|
||||
"pathchk",
|
||||
"pinky",
|
||||
"stat",
|
||||
"stdbuf",
|
||||
"timeout",
|
||||
"touch",
|
||||
"tty",
|
||||
"uname",
|
||||
"unlink",
|
||||
]
|
||||
# "feat_os_unix_redox" == set of utilities which can be built/run on "Redox OS" (refs: <https://www.redox-os.org>; <https://en.wikipedia.org/wiki/Redox_(operating_system)>)
|
||||
feat_os_unix_redox = [
|
||||
"feat_common_core",
|
||||
#
|
||||
"uname",
|
||||
"chmod",
|
||||
"install",
|
||||
]
|
||||
# "feat_os_unix_utmpx_required" == set of utilites requiring utmp/utmpx support
|
||||
# * ref: <https://wiki.musl-libc.org/faq.html#Q:-Why-is-the-utmp/wtmp-functionality-only-implemented-as-stubs?>
|
||||
feat_os_unix_utmpx_required = [
|
||||
"pinky",
|
||||
"uptime",
|
||||
"users",
|
||||
"who",
|
||||
|
||||
"generic"
|
||||
]
|
||||
windows = ["generic"]
|
||||
windows_legacy = [
|
||||
# "feat_os_windows" == set of utilities which can be built/run on modern/usual windows platforms
|
||||
feat_os_windows = [
|
||||
"feat_common", ## == "feat_os_windows_legacy" + "hostname"
|
||||
]
|
||||
# "feat_os_windows_legacy" == slightly restricted set of utilities which can be built/run on early windows platforms (eg, "WinXP")
|
||||
feat_os_windows_legacy = [
|
||||
"feat_common_core",
|
||||
#
|
||||
"arch",
|
||||
"nproc",
|
||||
"sync",
|
||||
"touch",
|
||||
"whoami",
|
||||
|
||||
"redox_generic"
|
||||
]
|
||||
# Feature "fuchsia" contains the exclusive list of utilities
|
||||
# that can be compiled and run on Fuchsia. Should be built
|
||||
# with --no-default-features when selecting this feature.
|
||||
# TODO: merge with "unix" to avoid duplication once we support
|
||||
# all utilities in that feature.
|
||||
fuchsia = [
|
||||
# unix utilities
|
||||
"chgrp",
|
||||
"chmod",
|
||||
"chown",
|
||||
"du",
|
||||
"groups",
|
||||
"hostid",
|
||||
"install",
|
||||
"logname",
|
||||
"mkfifo",
|
||||
"mknod",
|
||||
"nice",
|
||||
"pathchk",
|
||||
"stdbuf",
|
||||
"tty",
|
||||
"uname",
|
||||
"unlink",
|
||||
|
||||
# All generic utilities
|
||||
"generic"
|
||||
]
|
||||
generic = [
|
||||
## (common/core) feature sets
|
||||
# "feat_common" == expanded set of utilities which can be built/run on the usual rust "tier 1" target platforms (ref: <https://forge.rust-lang.org/release/platform-support.html>)
|
||||
feat_common = [
|
||||
"feat_common_core",
|
||||
#
|
||||
"arch",
|
||||
"hostname",
|
||||
"nproc",
|
||||
"sync",
|
||||
"touch",
|
||||
"whoami",
|
||||
"redox_generic"
|
||||
]
|
||||
# Feature "redox"/"redox_generic" contains the exclusive list of utilities
|
||||
# that can be compiled and run on redox. Should be built
|
||||
# with --no-default-features when selecting this feature.
|
||||
# TODO: merge with "generic" to avoid duplication once we support
|
||||
# all utilities in that feature.
|
||||
redox_generic = [
|
||||
|
||||
# And maybe all generic utilities
|
||||
# "feat_common_core" == baseline core set of utilities which can be built/run on most targets
|
||||
feat_common_core = [
|
||||
"base32",
|
||||
"base64",
|
||||
"basename",
|
||||
|
@ -153,20 +183,11 @@ redox_generic = [
|
|||
"wc",
|
||||
"yes",
|
||||
]
|
||||
redox = [
|
||||
"uname",
|
||||
"chmod",
|
||||
"install",
|
||||
"redox_generic"
|
||||
]
|
||||
test_unimplemented = []
|
||||
nightly = []
|
||||
default = ["unix"]
|
||||
|
||||
[workspace]
|
||||
|
||||
[dependencies]
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
arch = { optional=true, path="src/arch" }
|
||||
base32 = { optional=true, path="src/base32" }
|
||||
base64 = { optional=true, path="src/base64" }
|
||||
|
@ -260,16 +281,19 @@ wc = { optional=true, path="src/wc" }
|
|||
who = { optional=true, path="src/who" }
|
||||
whoami = { optional=true, path="src/whoami" }
|
||||
yes = { optional=true, path="src/yes" }
|
||||
#
|
||||
# * transitive dependency via 'failure'; pin to <= v0.3.30 to avoid increasing MinSRV to v1.33.0
|
||||
backtrace = ">= 0.3.3, <= 0.3.30"
|
||||
|
||||
[dev-dependencies]
|
||||
time = "0.1.42"
|
||||
filetime = "0.2.5"
|
||||
libc = "0.2.62"
|
||||
regex = "1.0.3"
|
||||
rand = "0.6.5"
|
||||
tempdir = "0.3.7"
|
||||
unindent = "0.1.3"
|
||||
lazy_static = "1.3.0"
|
||||
libc = "0.2.62"
|
||||
rand = "0.6.5"
|
||||
regex = "1.0.3"
|
||||
tempdir = "0.3.7"
|
||||
time = "0.1.42"
|
||||
unindent = "0.1.3"
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
# FIXME: this should use the normal users crate, but it conflicts with the users utility
|
||||
|
@ -282,3 +306,6 @@ path = "src/uutils/uutils.rs"
|
|||
|
||||
[[test]]
|
||||
name = "tests"
|
||||
|
||||
[patch.crates-io]
|
||||
uucore = { git = "https://github.com/rivy/rust.uucore", tag = "0.0.2" }
|
||||
|
|
151
Makefile.toml
151
Makefile.toml
|
@ -1,17 +1,88 @@
|
|||
# spell-checker:ignore (cargo-make) duckscript macos
|
||||
# spell-checker:ignore (rust) clippy
|
||||
|
||||
[config]
|
||||
min_version = "0.26.2"
|
||||
default_to_workspace = false
|
||||
init_task = "_init"
|
||||
|
||||
[config.modify_core_tasks]
|
||||
namespace = "core"
|
||||
|
||||
[env]
|
||||
CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = { source = "${CARGO_MAKE_RUST_TARGET_OS}", default_value = "", mapping = { "linux" = "--no-default-features --features unix", "windows" = "--no-default-features --features windows" } }
|
||||
### initialization
|
||||
|
||||
[tasks._init]
|
||||
private = true
|
||||
run_task = "_init_"
|
||||
|
||||
[tasks._init_]
|
||||
private = true
|
||||
dependencies = [
|
||||
"_init-vars",
|
||||
]
|
||||
|
||||
[tasks._init-vars]
|
||||
private = true
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
'''
|
||||
# reset build/test flags
|
||||
set_env CARGO_MAKE_CARGO_BUILD_TEST_FLAGS ""
|
||||
# determine features
|
||||
env_features = get_env CARGO_FEATURES
|
||||
if is_empty "${env_features}"
|
||||
env_features = get_env FEATURES
|
||||
end_if
|
||||
if is_empty "${env_features}"
|
||||
if eq "${CARGO_MAKE_RUST_TARGET_OS}" "macos"
|
||||
features = set "unix"
|
||||
else
|
||||
if eq "${CARGO_MAKE_RUST_TARGET_OS}" "linux"
|
||||
features = set "unix"
|
||||
else
|
||||
if eq "${CARGO_MAKE_RUST_TARGET_OS}" "windows"
|
||||
features = set "windows"
|
||||
end_if
|
||||
end_if
|
||||
end_if
|
||||
end_if
|
||||
if is_empty "${features}"
|
||||
features = set "${env_features}"
|
||||
else
|
||||
if not is_empty "${env_features}"
|
||||
features = set "${features},${env_features}"
|
||||
end_if
|
||||
end_if
|
||||
# set build flags from features
|
||||
if not is_empty "${features}"
|
||||
set_env CARGO_MAKE_VAR_BUILD_TEST_FEATURES "${features}"
|
||||
set_env CARGO_MAKE_CARGO_BUILD_TEST_FLAGS "--features ${features}"
|
||||
end_if
|
||||
# determine show-utils helper script
|
||||
show_utils = set "util/show-utils.sh"
|
||||
if eq "${CARGO_MAKE_RUST_TARGET_OS}" "windows"
|
||||
show_utils = set "util/show-utils.BAT"
|
||||
end_if
|
||||
set_env CARGO_MAKE_VAR_SHOW_UTILS "${show_utils}"
|
||||
# rebuild TASK_ARGS for "--features" and package-build compatibility (using "," instead of ";")
|
||||
args = set ${CARGO_MAKE_TASK_ARGS}
|
||||
args = replace ${args} ";" ","
|
||||
set_env CARGO_MAKE_TASK_BUILD_FEATURES_ARGS "${args}"
|
||||
args = replace ${args} "," " -p"
|
||||
if not is_empty "${args}"
|
||||
args = set "-p${args}"
|
||||
end_if
|
||||
set_env CARGO_MAKE_TASK_BUILD_UTILS_ARGS "${args}"
|
||||
'''
|
||||
]
|
||||
|
||||
### tasks
|
||||
|
||||
[tasks.default]
|
||||
description = "Build and Test"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"build",
|
||||
"action-build-debug",
|
||||
"test-terse",
|
||||
]
|
||||
|
||||
|
@ -20,15 +91,27 @@ description = "Build"
|
|||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-build",
|
||||
"core::build",
|
||||
"action-build",
|
||||
"core::post-build",
|
||||
]
|
||||
|
||||
[tasks.build-features]
|
||||
description = "Build (with features); usage: `cargo make (build-features | features) FEATURE..`"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-build",
|
||||
"action-build-features",
|
||||
"core::post-build",
|
||||
]
|
||||
|
||||
[tasks.features]
|
||||
alias = "build-features"
|
||||
|
||||
[tasks.format]
|
||||
description = "Format"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"action.format",
|
||||
"action-format",
|
||||
]
|
||||
|
||||
[tasks.help]
|
||||
|
@ -45,6 +128,11 @@ dependencies = [
|
|||
"action-fmt_report",
|
||||
]
|
||||
|
||||
[tasks.release]
|
||||
alias = "build"
|
||||
description = "Build"
|
||||
category = "[project]"
|
||||
|
||||
[tasks.test]
|
||||
description = "Test"
|
||||
category = "[project]"
|
||||
|
@ -63,13 +151,66 @@ dependencies = [
|
|||
"core::post-test",
|
||||
]
|
||||
|
||||
[tasks.util]
|
||||
alias = "utils"
|
||||
|
||||
[tasks.utils]
|
||||
description = "Build (individual) utilities; usage: `cargo make (util | utils) [UTIL_NAME..]`"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-build",
|
||||
"action-determine-utils",
|
||||
"action-build-utils",
|
||||
"core::post-build",
|
||||
]
|
||||
|
||||
### actions
|
||||
|
||||
[tasks.action-build]
|
||||
description = "`cargo build --release`"
|
||||
command = "cargo"
|
||||
args = ["build", "--release", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )" ]
|
||||
|
||||
[tasks.action-build-debug]
|
||||
description = "`cargo build`"
|
||||
command = "cargo"
|
||||
args = ["build", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )" ]
|
||||
|
||||
[tasks.action-build-features]
|
||||
description = "`cargo build --release --features FEATURES`"
|
||||
command = "cargo"
|
||||
args = ["build", "--release", "--no-default-features", "--features", "${CARGO_MAKE_TASK_BUILD_FEATURES_ARGS}" ]
|
||||
|
||||
[tasks.action-build-utils]
|
||||
description = "Build individual utilities"
|
||||
command = "cargo"
|
||||
# args = ["build", "@@remove-empty(CARGO_MAKE_TASK_BUILD_UTILS_ARGS)" ]
|
||||
args = ["build", "--release", "@@split(CARGO_MAKE_TASK_BUILD_UTILS_ARGS, )" ]
|
||||
|
||||
[tasks.action-clippy]
|
||||
description = "`cargo clippy` lint report"
|
||||
command = "cargo"
|
||||
args = ["clippy", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )"]
|
||||
|
||||
[tasks.action-determine-utils]
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
'''
|
||||
package_options = get_env CARGO_MAKE_TASK_BUILD_UTILS_ARGS
|
||||
if is_empty "${package_options}"
|
||||
show_utils = get_env CARGO_MAKE_VAR_SHOW_UTILS
|
||||
result = exec "${show_utils}"
|
||||
set_env CARGO_MAKE_VAR_UTILS ${result.stdout}
|
||||
utils = array %{result.stdout}
|
||||
for util in ${utils}
|
||||
package_options = set "${package_options} -p${util}"
|
||||
end
|
||||
package_options = trim "${package_options}"
|
||||
end_if
|
||||
set_env CARGO_MAKE_TASK_BUILD_UTILS_ARGS "${package_options}"
|
||||
'''
|
||||
]
|
||||
|
||||
[tasks.action-format]
|
||||
description = "`cargo fmt`"
|
||||
command = "cargo"
|
||||
|
|
28
build.rs
28
build.rs
|
@ -16,8 +16,9 @@ pub fn main() {
|
|||
if val == "1" && key.starts_with(feature_prefix) {
|
||||
let krate = key[feature_prefix.len()..].to_lowercase();
|
||||
match krate.as_ref() {
|
||||
"default" | "unix" | "redox" | "redox_generic" | "fuchsia" | "generic" | "windows" | "windows_legacy"
|
||||
| "nightly" | "test_unimplemented" => continue,
|
||||
"default" | "macos" | "unix" | "windows" => continue,
|
||||
"nightly" | "test_unimplemented" => continue,
|
||||
s if s.starts_with("feat_") => continue,
|
||||
_ => {}
|
||||
}
|
||||
crates.push(krate.to_string());
|
||||
|
@ -35,7 +36,8 @@ pub fn main() {
|
|||
fn util_map() -> UtilityMap {
|
||||
let mut map: UtilityMap = HashMap::new();\n"
|
||||
.as_bytes(),
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
for krate in crates {
|
||||
cf.write_all(format!("extern crate uu_{krate};\n", krate = krate).as_bytes())
|
||||
|
@ -59,18 +61,22 @@ pub fn main() {
|
|||
map.insert(\"shake128sum\", uu_hashsum::uumain);
|
||||
map.insert(\"shake256sum\", uu_hashsum::uumain);\n"
|
||||
.as_bytes(),
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
_ => mf.write_all(
|
||||
format!(
|
||||
"map.insert(\"{krate}\", uu_{krate}::uumain);\n",
|
||||
krate = krate
|
||||
).as_bytes(),
|
||||
).unwrap(),
|
||||
_ => mf
|
||||
.write_all(
|
||||
format!(
|
||||
"map.insert(\"{krate}\", uu_{krate}::uumain);\n",
|
||||
krate = krate
|
||||
)
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
mf.write_all("map\n}\n".as_bytes()).unwrap();
|
||||
mf.write_all(b"map\n}\n").unwrap();
|
||||
|
||||
cf.flush().unwrap();
|
||||
mf.flush().unwrap();
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
static TEMPLATE: &'static str = "\
|
||||
static TEMPLATE: &str = "\
|
||||
extern crate uu_@UTIL_CRATE@;
|
||||
extern crate uucore;
|
||||
|
|
@ -2,7 +2,8 @@
|
|||
name = "arch"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_arch"
|
||||
|
@ -10,8 +11,8 @@ path = "arch.rs"
|
|||
|
||||
[dependencies]
|
||||
platform-info = "0.0.1"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "arch"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -2,20 +2,18 @@
|
|||
name = "base32"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_base32"
|
||||
path = "base32.rs"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["encoding"]
|
||||
|
||||
[dependencies.clippy]
|
||||
version = "0.0.212"
|
||||
optional = true
|
||||
[dependencies]
|
||||
uucore = { version = "0.0.2", features = ["encoding"] }
|
||||
## optional
|
||||
clippy = { version = "0.0.212", optional = true }
|
||||
|
||||
[[bin]]
|
||||
name = "base32"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -16,8 +16,7 @@ use uucore::encoding::Format;
|
|||
mod base_common;
|
||||
|
||||
static SYNTAX: &str = "[OPTION]... [FILE]";
|
||||
static SUMMARY: &str =
|
||||
"Base32 encode or decode FILE, or standard input, to standard output.";
|
||||
static SUMMARY: &str = "Base32 encode or decode FILE, or standard input, to standard output.";
|
||||
static LONG_HELP: &str = "
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
name = "base64"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_base64"
|
||||
path = "base64.rs"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["encoding"]
|
||||
[dependencies]
|
||||
uucore = { version = "0.0.2", features = ["encoding"] }
|
||||
|
||||
[[bin]]
|
||||
name = "base64"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -16,8 +16,7 @@ use uucore::encoding::Format;
|
|||
mod base_common;
|
||||
|
||||
static SYNTAX: &str = "[OPTION]... [FILE]";
|
||||
static SUMMARY: &str =
|
||||
"Base64 encode or decode FILE, or standard input, to standard output.";
|
||||
static SUMMARY: &str = "Base64 encode or decode FILE, or standard input, to standard output.";
|
||||
static LONG_HELP: &str = "
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
|
|
|
@ -36,13 +36,11 @@ pub fn execute(
|
|||
"COLS",
|
||||
)
|
||||
.parse(args);
|
||||
|
||||
let line_wrap = matches.opt_str("wrap").map(|s| {
|
||||
match s.parse() {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
crash!(1, "invalid wrap size: ‘{}’: {}", s, e);
|
||||
}
|
||||
|
||||
let line_wrap = matches.opt_str("wrap").map(|s| match s.parse() {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
crash!(1, "invalid wrap size: ‘{}’: {}", s, e);
|
||||
}
|
||||
});
|
||||
let ignore_garbage = matches.opt_present("ignore-garbage");
|
||||
|
@ -55,7 +53,13 @@ pub fn execute(
|
|||
|
||||
if matches.free.is_empty() || &matches.free[0][..] == "-" {
|
||||
let stdin_raw = stdin();
|
||||
handle_input(&mut stdin_raw.lock(), format, line_wrap, ignore_garbage, decode);
|
||||
handle_input(
|
||||
&mut stdin_raw.lock(),
|
||||
format,
|
||||
line_wrap,
|
||||
ignore_garbage,
|
||||
decode,
|
||||
);
|
||||
} else {
|
||||
let path = Path::new(matches.free[0].as_str());
|
||||
let file_buf = safe_unwrap!(File::open(&path));
|
||||
|
@ -73,8 +77,7 @@ fn handle_input<R: Read>(
|
|||
ignore_garbage: bool,
|
||||
decode: bool,
|
||||
) {
|
||||
let mut data = Data::new(input, format)
|
||||
.ignore_garbage(ignore_garbage);
|
||||
let mut data = Data::new(input, format).ignore_garbage(ignore_garbage);
|
||||
if let Some(wrap) = line_wrap {
|
||||
data = data.line_wrap(wrap);
|
||||
}
|
||||
|
@ -88,4 +91,4 @@ fn handle_input<R: Read>(
|
|||
Err(_) => crash!(1, "invalid input"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
name = "basename"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_basename"
|
||||
path = "basename.rs"
|
||||
|
||||
[dependencies]
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "basename"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -2,22 +2,20 @@
|
|||
name = "cat"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_cat"
|
||||
path = "cat.rs"
|
||||
|
||||
[dependencies]
|
||||
quick-error = "1.2.2"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["fs"]
|
||||
quick-error = "1.2.3"
|
||||
uucore = { version = "0.0.2", features = ["fs"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
unix_socket = "0.5.0"
|
||||
|
||||
[[bin]]
|
||||
name = "cat"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -38,9 +38,9 @@ static LONG_HELP: &str = "";
|
|||
|
||||
#[derive(PartialEq)]
|
||||
enum NumberingMode {
|
||||
NumberNone,
|
||||
NumberNonEmpty,
|
||||
NumberAll,
|
||||
None,
|
||||
NonEmpty,
|
||||
All,
|
||||
}
|
||||
|
||||
quick_error! {
|
||||
|
@ -147,11 +147,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
.parse(args);
|
||||
|
||||
let number_mode = if matches.opt_present("b") {
|
||||
NumberingMode::NumberNonEmpty
|
||||
NumberingMode::NonEmpty
|
||||
} else if matches.opt_present("n") {
|
||||
NumberingMode::NumberAll
|
||||
NumberingMode::All
|
||||
} else {
|
||||
NumberingMode::NumberNone
|
||||
NumberingMode::None
|
||||
};
|
||||
|
||||
let show_nonprint = matches.opts_present(&[
|
||||
|
@ -168,8 +168,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
files.push("-".to_owned());
|
||||
}
|
||||
|
||||
let can_write_fast = !(show_tabs || show_nonprint || show_ends || squeeze_blank
|
||||
|| number_mode != NumberingMode::NumberNone);
|
||||
let can_write_fast = !(show_tabs
|
||||
|| show_nonprint
|
||||
|| show_ends
|
||||
|| squeeze_blank
|
||||
|| number_mode != NumberingMode::None);
|
||||
|
||||
let success = if can_write_fast {
|
||||
write_fast(files).is_ok()
|
||||
|
@ -190,7 +193,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
write_lines(files, &options).is_ok()
|
||||
};
|
||||
|
||||
if success { 0 } else { 1 }
|
||||
if success {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
/// Classifies the `InputType` of file at `path` if possible
|
||||
|
@ -205,25 +212,13 @@ fn get_input_type(path: &str) -> CatResult<InputType> {
|
|||
|
||||
match metadata(path).context(path)?.file_type() {
|
||||
#[cfg(unix)]
|
||||
ft if ft.is_block_device() =>
|
||||
{
|
||||
Ok(InputType::BlockDevice)
|
||||
}
|
||||
ft if ft.is_block_device() => Ok(InputType::BlockDevice),
|
||||
#[cfg(unix)]
|
||||
ft if ft.is_char_device() =>
|
||||
{
|
||||
Ok(InputType::CharacterDevice)
|
||||
}
|
||||
ft if ft.is_char_device() => Ok(InputType::CharacterDevice),
|
||||
#[cfg(unix)]
|
||||
ft if ft.is_fifo() =>
|
||||
{
|
||||
Ok(InputType::Fifo)
|
||||
}
|
||||
ft if ft.is_fifo() => Ok(InputType::Fifo),
|
||||
#[cfg(unix)]
|
||||
ft if ft.is_socket() =>
|
||||
{
|
||||
Ok(InputType::Socket)
|
||||
}
|
||||
ft if ft.is_socket() => Ok(InputType::Socket),
|
||||
ft if ft.is_dir() => Ok(InputType::Directory),
|
||||
ft if ft.is_file() => Ok(InputType::File),
|
||||
ft if ft.is_symlink() => Ok(InputType::SymLink),
|
||||
|
@ -282,12 +277,14 @@ fn write_fast(files: Vec<String>) -> CatResult<()> {
|
|||
|
||||
for file in files {
|
||||
match open(&file[..]) {
|
||||
Ok(mut handle) => while let Ok(n) = handle.reader.read(&mut in_buf) {
|
||||
if n == 0 {
|
||||
break;
|
||||
Ok(mut handle) => {
|
||||
while let Ok(n) = handle.reader.read(&mut in_buf) {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
writer.write_all(&in_buf[..n]).context(&file[..])?;
|
||||
}
|
||||
writer.write_all(&in_buf[..n]).context(&file[..])?;
|
||||
},
|
||||
}
|
||||
Err(error) => {
|
||||
writeln!(&mut stderr(), "{}", error)?;
|
||||
error_count += 1;
|
||||
|
@ -357,7 +354,7 @@ fn write_file_lines(file: &str, options: &OutputOptions, state: &mut OutputState
|
|||
if in_buf[pos] == b'\n' {
|
||||
if !state.at_line_start || !options.squeeze_blank || !one_blank_kept {
|
||||
one_blank_kept = true;
|
||||
if state.at_line_start && options.number == NumberingMode::NumberAll {
|
||||
if state.at_line_start && options.number == NumberingMode::All {
|
||||
write!(&mut writer, "{0:6}\t", state.line_number)?;
|
||||
state.line_number += 1;
|
||||
}
|
||||
|
@ -371,7 +368,7 @@ fn write_file_lines(file: &str, options: &OutputOptions, state: &mut OutputState
|
|||
continue;
|
||||
}
|
||||
one_blank_kept = false;
|
||||
if state.at_line_start && options.number != NumberingMode::NumberNone {
|
||||
if state.at_line_start && options.number != NumberingMode::None {
|
||||
write!(&mut writer, "{0:6}\t", state.line_number)?;
|
||||
state.line_number += 1;
|
||||
}
|
||||
|
@ -421,10 +418,7 @@ fn write_to_end<W: Write>(in_buf: &[u8], writer: &mut W) -> usize {
|
|||
fn write_tab_to_end<W: Write>(mut in_buf: &[u8], writer: &mut W) -> usize {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
match in_buf
|
||||
.iter()
|
||||
.position(|c| *c == b'\n' || *c == b'\t')
|
||||
{
|
||||
match in_buf.iter().position(|c| *c == b'\n' || *c == b'\t') {
|
||||
Some(p) => {
|
||||
writer.write_all(&in_buf[..p]).unwrap();
|
||||
if in_buf[p] == b'\n' {
|
||||
|
@ -458,7 +452,8 @@ fn write_nonprint_to_end<W: Write>(in_buf: &[u8], writer: &mut W, tab: &[u8]) ->
|
|||
128..=159 => writer.write_all(&[b'M', b'-', b'^', byte - 64]),
|
||||
160..=254 => writer.write_all(&[b'M', b'-', byte - 128]),
|
||||
_ => writer.write_all(&[b'M', b'-', b'^', 63]),
|
||||
}.unwrap();
|
||||
}
|
||||
.unwrap();
|
||||
count += 1;
|
||||
}
|
||||
if count != in_buf.len() {
|
||||
|
|
|
@ -2,19 +2,17 @@
|
|||
name = "chgrp"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_chgrp"
|
||||
path = "chgrp.rs"
|
||||
|
||||
[dependencies]
|
||||
uucore = { version = "0.0.2", features = ["entries", "fs"] }
|
||||
walkdir = "2.2.8"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["entries", "fs"]
|
||||
|
||||
[[bin]]
|
||||
name = "chgrp"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -10,15 +10,15 @@
|
|||
|
||||
#[macro_use]
|
||||
extern crate uucore;
|
||||
use uucore::libc::{self, gid_t, lchown};
|
||||
pub use uucore::entries;
|
||||
use uucore::fs::resolve_relative_path;
|
||||
use uucore::libc::{self, gid_t, lchown};
|
||||
|
||||
extern crate walkdir;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use std::io::Result as IOResult;
|
||||
use std::io::Error as IOError;
|
||||
use std::io::Result as IOResult;
|
||||
|
||||
use std::fs;
|
||||
use std::fs::Metadata;
|
||||
|
@ -183,12 +183,12 @@ struct Chgrper {
|
|||
}
|
||||
|
||||
macro_rules! unwrap {
|
||||
($m:expr, $e:ident, $err:block) => (
|
||||
($m:expr, $e:ident, $err:block) => {
|
||||
match $m {
|
||||
Ok(meta) => meta,
|
||||
Err($e) => $err,
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
impl Chgrper {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "chmod"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_chmod"
|
||||
|
@ -10,12 +11,9 @@ path = "chmod.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
uucore = { version = "0.0.2", features = ["mode"] }
|
||||
walker = "1.0.0"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["mode"]
|
||||
|
||||
[[bin]]
|
||||
name = "chmod"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -19,10 +19,10 @@ extern crate uucore;
|
|||
use std::fs;
|
||||
use std::os::unix::fs::{MetadataExt, PermissionsExt};
|
||||
use std::path::Path;
|
||||
use walker::Walker;
|
||||
use uucore::fs::display_permissions_unix;
|
||||
#[cfg(not(windows))]
|
||||
use uucore::mode;
|
||||
use uucore::fs::display_permissions_unix;
|
||||
use walker::Walker;
|
||||
|
||||
const NAME: &str = "chmod";
|
||||
static SUMMARY: &str = "Change the mode of each FILE to MODE.
|
||||
|
@ -39,14 +39,31 @@ pub fn uumain(mut args: Vec<String>) -> i32 {
|
|||
NAME
|
||||
);
|
||||
let mut opts = new_coreopts!(&syntax, SUMMARY, LONG_HELP);
|
||||
opts.optflag("c", "changes", "like verbose but report only when a change is made")
|
||||
// TODO: support --silent (can be done using clap)
|
||||
.optflag("f", "quiet", "suppress most error messages")
|
||||
.optflag("v", "verbose", "output a diagnostic for every file processed")
|
||||
.optflag("", "no-preserve-root", "do not treat '/' specially (the default)")
|
||||
.optflag("", "preserve-root", "fail to operate recursively on '/'")
|
||||
.optopt("", "reference", "use RFILE's mode instead of MODE values", "RFILE")
|
||||
.optflag("R", "recursive", "change files and directories recursively");
|
||||
opts.optflag(
|
||||
"c",
|
||||
"changes",
|
||||
"like verbose but report only when a change is made",
|
||||
)
|
||||
// TODO: support --silent (can be done using clap)
|
||||
.optflag("f", "quiet", "suppress most error messages")
|
||||
.optflag(
|
||||
"v",
|
||||
"verbose",
|
||||
"output a diagnostic for every file processed",
|
||||
)
|
||||
.optflag(
|
||||
"",
|
||||
"no-preserve-root",
|
||||
"do not treat '/' specially (the default)",
|
||||
)
|
||||
.optflag("", "preserve-root", "fail to operate recursively on '/'")
|
||||
.optopt(
|
||||
"",
|
||||
"reference",
|
||||
"use RFILE's mode instead of MODE values",
|
||||
"RFILE",
|
||||
)
|
||||
.optflag("R", "recursive", "change files and directories recursively");
|
||||
|
||||
// sanitize input for - at beginning (e.g. chmod -x testfile). Remove
|
||||
// the option and save it for later, after parsing is finished.
|
||||
|
@ -100,7 +117,7 @@ pub fn uumain(mut args: Vec<String>) -> i32 {
|
|||
|
||||
fn sanitize_input(args: &mut Vec<String>) -> Option<String> {
|
||||
for i in 0..args.len() {
|
||||
let first = args[i].chars().nth(0).unwrap();
|
||||
let first = args[i].chars().next().unwrap();
|
||||
if first != '-' {
|
||||
continue;
|
||||
}
|
||||
|
@ -148,17 +165,19 @@ impl Chmoder {
|
|||
// on Windows OsStrings cannot be built out of non-UTF-8 chars. One
|
||||
// possible fix is to use CStrings rather than Strings in the args
|
||||
// to chmod() and chmod_file().
|
||||
r = self.chmod(
|
||||
walk_dir
|
||||
.filter_map(|x| match x {
|
||||
Ok(o) => match o.path().into_os_string().to_str() {
|
||||
Some(s) => Some(s.to_owned()),
|
||||
None => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
})
|
||||
.collect(),
|
||||
).and(r);
|
||||
r = self
|
||||
.chmod(
|
||||
walk_dir
|
||||
.filter_map(|x| match x {
|
||||
Ok(o) => match o.path().into_os_string().to_str() {
|
||||
Some(s) => Some(s.to_owned()),
|
||||
None => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.and(r);
|
||||
r = self.chmod_file(&file, filename).and(r);
|
||||
}
|
||||
} else {
|
||||
|
@ -230,7 +249,12 @@ impl Chmoder {
|
|||
fn change_file(&self, fperm: u32, mode: u32, file: &Path, path: &str) -> Result<(), i32> {
|
||||
if fperm == mode {
|
||||
if self.verbose && !self.changes {
|
||||
show_info!("mode of '{}' retained as {:o} ({})", file.display(), fperm, display_permissions_unix(fperm));
|
||||
show_info!(
|
||||
"mode of '{}' retained as {:o} ({})",
|
||||
file.display(),
|
||||
fperm,
|
||||
display_permissions_unix(fperm)
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
} else if let Err(err) =
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "chown"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_chown"
|
||||
|
@ -10,16 +11,13 @@ path = "chown.rs"
|
|||
|
||||
[dependencies]
|
||||
glob = "0.3.0"
|
||||
uucore = { version = "0.0.2", features = ["entries", "fs"] }
|
||||
walkdir = "2.2"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["entries", "fs"]
|
||||
|
||||
[dependencies.clippy]
|
||||
version = "0.0.212"
|
||||
optional = true
|
||||
|
||||
[[bin]]
|
||||
name = "chown"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
#[macro_use]
|
||||
extern crate uucore;
|
||||
use uucore::libc::{self, gid_t, lchown, uid_t};
|
||||
pub use uucore::entries::{self, Group, Locate, Passwd};
|
||||
use uucore::fs::resolve_relative_path;
|
||||
use uucore::libc::{self, gid_t, lchown, uid_t};
|
||||
|
||||
extern crate walkdir;
|
||||
use walkdir::WalkDir;
|
||||
|
@ -24,8 +24,8 @@ use std::os::unix::fs::MetadataExt;
|
|||
use std::io;
|
||||
use std::io::Result as IOResult;
|
||||
|
||||
use std::path::Path;
|
||||
use std::convert::AsRef;
|
||||
use std::path::Path;
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
@ -253,12 +253,12 @@ struct Chowner {
|
|||
}
|
||||
|
||||
macro_rules! unwrap {
|
||||
($m:expr, $e:ident, $err:block) => (
|
||||
($m:expr, $e:ident, $err:block) => {
|
||||
match $m {
|
||||
Ok(meta) => meta,
|
||||
Err($e) => $err,
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
impl Chowner {
|
||||
|
@ -395,8 +395,8 @@ impl Chowner {
|
|||
fn wrap_chown<P: AsRef<Path>>(&self, path: P, meta: &Metadata, follow: bool) -> i32 {
|
||||
use self::Verbosity::*;
|
||||
let mut ret = 0;
|
||||
let dest_uid = self.dest_uid.unwrap_or(meta.uid());
|
||||
let dest_gid = self.dest_gid.unwrap_or(meta.gid());
|
||||
let dest_uid = self.dest_uid.unwrap_or_else(|| meta.uid());
|
||||
let dest_gid = self.dest_gid.unwrap_or_else(|| meta.gid());
|
||||
let path = path.as_ref();
|
||||
if let Err(e) = self.chown(path, dest_uid, dest_gid, follow) {
|
||||
match self.verbosity {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "chroot"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_chroot"
|
||||
|
@ -10,11 +11,8 @@ path = "chroot.rs"
|
|||
|
||||
[dependencies]
|
||||
getopts = "0.2.18"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["entries"]
|
||||
uucore = { version = "0.0.2", features = ["entries"] }
|
||||
|
||||
[[bin]]
|
||||
name = "chroot"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -14,8 +14,8 @@ extern crate getopts;
|
|||
|
||||
#[macro_use]
|
||||
extern crate uucore;
|
||||
use uucore::libc::{self, chroot, setgid, setgroups, setuid};
|
||||
use uucore::entries;
|
||||
use uucore::libc::{self, chroot, setgid, setgroups, setuid};
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::io::Error;
|
||||
|
@ -140,10 +140,7 @@ fn enter_chroot(root: &Path) {
|
|||
let root_str = root.display();
|
||||
std::env::set_current_dir(root).unwrap();
|
||||
let err = unsafe {
|
||||
chroot(CString::new(".")
|
||||
.unwrap()
|
||||
.as_bytes_with_nul()
|
||||
.as_ptr() as *const libc::c_char)
|
||||
chroot(CString::new(".").unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char)
|
||||
};
|
||||
if err != 0 {
|
||||
crash!(
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
name = "cksum"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "uu_cksum"
|
||||
|
@ -9,8 +10,8 @@ path = "cksum.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "cksum"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::path::Path;
|
|||
|
||||
const CRC_TABLE_LEN: usize = 256;
|
||||
|
||||
#[path = "../../mkmain.rs"]
|
||||
#[path = "../#common/mkmain.rs"]
|
||||
mod mkmain;
|
||||
|
||||
fn main() {
|
||||
|
@ -30,9 +30,10 @@ fn main() {
|
|||
let file = File::create(&Path::new(&out_dir).join("crc_table.rs")).unwrap();
|
||||
write!(
|
||||
&file,
|
||||
"const CRC_TABLE: [u32; {}] = {:?};",
|
||||
"#[allow(clippy::unreadable_literal)]\nconst CRC_TABLE: [u32; {}] = {:?};",
|
||||
CRC_TABLE_LEN, table
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -40,9 +41,9 @@ fn crc_entry(input: u8) -> u32 {
|
|||
let mut crc = (input as u32) << 24;
|
||||
|
||||
for _ in 0..8 {
|
||||
if crc & 0x80000000 != 0 {
|
||||
if crc & 0x8000_0000 != 0 {
|
||||
crc <<= 1;
|
||||
crc ^= 0x04c11db7;
|
||||
crc ^= 0x04c1_1db7;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@ extern crate uucore;
|
|||
|
||||
use std::fs::File;
|
||||
use std::io::{self, stdin, BufReader, Read};
|
||||
#[cfg(not(windows))]
|
||||
use std::mem;
|
||||
use std::path::Path;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/crc_table.rs"));
|
||||
|
@ -39,16 +37,10 @@ fn crc_final(mut crc: u32, mut length: usize) -> u32 {
|
|||
!crc
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn init_byte_array() -> Vec<u8> {
|
||||
vec![0; 1024 * 1024]
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn init_byte_array() -> [u8; 1024 * 1024] {
|
||||
unsafe { mem::uninitialized() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cksum(fname: &str) -> io::Result<(u32, usize)> {
|
||||
let mut crc = 0u32;
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
name = "comm"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_comm"
|
||||
path = "comm.rs"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
getopts = "0.2.18"
|
||||
uucore = "0.0.1"
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "comm"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -26,7 +26,7 @@ static LONG_HELP: &str = "";
|
|||
fn mkdelim(col: usize, opts: &getopts::Matches) -> String {
|
||||
let mut s = String::new();
|
||||
let delim = match opts.opt_str("output-delimiter") {
|
||||
Some(d) => d.clone(),
|
||||
Some(d) => d,
|
||||
None => "\t".to_owned(),
|
||||
};
|
||||
|
||||
|
|
|
@ -5,23 +5,21 @@ authors = [
|
|||
"Jordy Dickinson <jordy.dickinson@gmail.com>",
|
||||
"Joshua S. Miller <jsmiller@uchicago.edu>",
|
||||
]
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_cp"
|
||||
path = "cp.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.32.0"
|
||||
filetime = "0.2"
|
||||
getopts = "0.2.18"
|
||||
libc = "0.2.42"
|
||||
quick-error = "1.2.3"
|
||||
uucore = { version = "0.0.2", features = ["fs"] }
|
||||
walkdir = "2.2.8"
|
||||
clap = "2.32.0"
|
||||
quick-error = "1.2.2"
|
||||
filetime = "0.2"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["fs"]
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
ioctl-sys = "0.5.2"
|
||||
|
@ -35,4 +33,4 @@ xattr="0.2.1"
|
|||
|
||||
[[bin]]
|
||||
name = "cp"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
83
src/cp/cp.rs
83
src/cp/cp.rs
|
@ -1,4 +1,5 @@
|
|||
#![crate_name = "uu_cp"]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
||||
/*
|
||||
* This file is part of the uutils coreutils package.
|
||||
|
@ -27,35 +28,42 @@ extern crate xattr;
|
|||
#[cfg(windows)]
|
||||
extern crate kernel32;
|
||||
#[cfg(windows)]
|
||||
use kernel32::GetFileInformationByHandle;
|
||||
#[cfg(windows)]
|
||||
use kernel32::CreateFileW;
|
||||
#[cfg(windows)]
|
||||
use kernel32::GetFileInformationByHandle;
|
||||
#[cfg(windows)]
|
||||
extern crate winapi;
|
||||
|
||||
use std::mem;
|
||||
use std::ffi::CString;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use filetime::FileTime;
|
||||
use quick_error::ResultExt;
|
||||
use std::collections::HashSet;
|
||||
#[cfg(not(windows))]
|
||||
use std::ffi::CString;
|
||||
#[cfg(windows)]
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf, StripPrefixError};
|
||||
use std::str::FromStr;
|
||||
use uucore::fs::{canonicalize, CanonicalizeMode};
|
||||
use walkdir::WalkDir;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::fs::File;
|
||||
use std::fs::OpenOptions;
|
||||
use filetime::FileTime;
|
||||
use std::io;
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use std::mem;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::path::{Path, PathBuf, StripPrefixError};
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use uucore::fs::{canonicalize, CanonicalizeMode};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
ioctl!(write ficlone with 0x94, 9; std::os::raw::c_int);
|
||||
|
||||
quick_error! {
|
||||
|
@ -121,7 +129,7 @@ macro_rules! prompt_yes(
|
|||
crash_if_err!(1, stdout().flush());
|
||||
let mut s = String::new();
|
||||
match stdin().read_line(&mut s) {
|
||||
Ok(_) => match s.char_indices().nth(0) {
|
||||
Ok(_) => match s.char_indices().next() {
|
||||
Some((_, x)) => x == 'y' || x == 'Y',
|
||||
_ => false
|
||||
},
|
||||
|
@ -470,7 +478,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
let options = crash_if_err!(EXIT_ERR, Options::from_matches(&matches));
|
||||
let paths: Vec<String> = matches
|
||||
.values_of("paths")
|
||||
.map(|v| v.map(|p| p.to_string()).collect())
|
||||
.map(|v| v.map(ToString::to_string).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
let (sources, target) = crash_if_err!(EXIT_ERR, parse_path_args(&paths, &options));
|
||||
|
@ -576,7 +584,8 @@ impl Options {
|
|||
}
|
||||
}
|
||||
|
||||
let recursive = matches.is_present(OPT_RECURSIVE) || matches.is_present(OPT_RECURSIVE_ALIAS)
|
||||
let recursive = matches.is_present(OPT_RECURSIVE)
|
||||
|| matches.is_present(OPT_RECURSIVE_ALIAS)
|
||||
|| matches.is_present(OPT_ARCHIVE);
|
||||
|
||||
let backup = matches.is_present(OPT_BACKUP) || (matches.occurrences_of(OPT_SUFFIX) > 0);
|
||||
|
@ -585,7 +594,7 @@ impl Options {
|
|||
let no_target_dir = matches.is_present(OPT_NO_TARGET_DIRECTORY);
|
||||
let target_dir = matches
|
||||
.value_of(OPT_TARGET_DIRECTORY)
|
||||
.map(|v| v.to_string());
|
||||
.map(ToString::to_string);
|
||||
|
||||
// Parse attributes to preserve
|
||||
let preserve_attributes: Vec<Attribute> = if matches.is_present(OPT_PRESERVE) {
|
||||
|
@ -712,27 +721,30 @@ fn preserve_hardlinks(
|
|||
{
|
||||
if !source.is_dir() {
|
||||
unsafe {
|
||||
let src_path = CString::new(source.as_os_str().to_str().unwrap()).unwrap();
|
||||
let inode: u64;
|
||||
let nlinks: u64;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let src_path = CString::new(source.as_os_str().to_str().unwrap()).unwrap();
|
||||
let mut stat = mem::zeroed();
|
||||
if libc::lstat(src_path.as_ptr(), &mut stat) < 0 {
|
||||
return Err(format!(
|
||||
"cannot stat {:?}: {}",
|
||||
src_path,
|
||||
std::io::Error::last_os_error()
|
||||
).into());
|
||||
)
|
||||
.into());
|
||||
}
|
||||
inode = stat.st_ino as u64;
|
||||
nlinks = stat.st_nlink as u64;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let src_path: Vec<u16> = OsStr::new(source).encode_wide().collect();
|
||||
#[allow(deprecated)]
|
||||
let stat = mem::uninitialized();
|
||||
let handle = CreateFileW(
|
||||
src_path.as_ptr() as *const u16,
|
||||
src_path.as_ptr(),
|
||||
winapi::um::winnt::GENERIC_READ,
|
||||
winapi::um::winnt::FILE_SHARE_READ,
|
||||
std::ptr::null_mut(),
|
||||
|
@ -745,7 +757,8 @@ fn preserve_hardlinks(
|
|||
"cannot get file information {:?}: {}",
|
||||
source,
|
||||
std::io::Error::last_os_error()
|
||||
).into());
|
||||
)
|
||||
.into());
|
||||
}
|
||||
inode = ((*stat).nFileIndexHigh as u64) << 32 | (*stat).nFileIndexLow as u64;
|
||||
nlinks = (*stat).nNumberOfLinks as u64;
|
||||
|
@ -758,7 +771,7 @@ fn preserve_hardlinks(
|
|||
}
|
||||
}
|
||||
if !(*found_hard_link) && nlinks > 1 {
|
||||
hard_links.push((dest.clone().to_str().unwrap().to_string(), inode));
|
||||
hard_links.push((dest.to_str().unwrap().to_string(), inode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -826,7 +839,8 @@ fn construct_dest_path(
|
|||
return Err(format!(
|
||||
"cannot overwrite directory '{}' with non-directory",
|
||||
target.display()
|
||||
).into());
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
Ok(match *target_type {
|
||||
|
@ -940,7 +954,7 @@ impl OverwriteMode {
|
|||
|
||||
fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResult<()> {
|
||||
let context = &*format!("'{}' -> '{}'", source.display().to_string(), dest.display());
|
||||
Ok(match *attribute {
|
||||
match *attribute {
|
||||
#[cfg(unix)]
|
||||
Attribute::Mode => {
|
||||
let mode = fs::metadata(source).context(context)?.permissions().mode();
|
||||
|
@ -973,10 +987,11 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu
|
|||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
return Err(format!("XAttrs are only supported on unix.").into());
|
||||
return Err("XAttrs are only supported on unix.".to_string().into());
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
@ -1072,8 +1087,8 @@ fn copy_file(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> {
|
|||
CopyMode::Sparse => return Err(Error::NotImplemented(OPT_SPARSE.to_string())),
|
||||
CopyMode::Update => {
|
||||
if dest.exists() {
|
||||
let src_metadata = fs::metadata(source.clone())?;
|
||||
let dest_metadata = fs::metadata(dest.clone())?;
|
||||
let src_metadata = fs::metadata(source)?;
|
||||
let dest_metadata = fs::metadata(dest)?;
|
||||
|
||||
let src_time = src_metadata.modified()?;
|
||||
let dest_time = dest_metadata.modified()?;
|
||||
|
@ -1108,7 +1123,7 @@ fn copy_file(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> {
|
|||
fn copy_helper(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> {
|
||||
if options.reflink {
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
return Err(format!("--reflink is only supported on linux").into());
|
||||
return Err("--reflink is only supported on linux".to_string().into());
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
|
@ -1129,7 +1144,8 @@ fn copy_helper(source: &Path, dest: &Path, options: &Options) -> CopyResult<()>
|
|||
source,
|
||||
dest,
|
||||
std::io::Error::last_os_error()
|
||||
).into());
|
||||
)
|
||||
.into());
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1158,7 +1174,8 @@ pub fn verify_target_type(target: &Path, target_type: &TargetType) -> CopyResult
|
|||
(&TargetType::File, true) => Err(format!(
|
||||
"cannot overwrite directory '{}' with non-directory",
|
||||
target.display()
|
||||
).into()),
|
||||
)
|
||||
.into()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
@ -1194,6 +1211,8 @@ fn test_cp_localize_to_target() {
|
|||
&Path::new("a/source/"),
|
||||
&Path::new("a/source/c.txt"),
|
||||
&Path::new("target/")
|
||||
).unwrap() == Path::new("target/c.txt")
|
||||
)
|
||||
.unwrap()
|
||||
== Path::new("target/c.txt")
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
name = "cut"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_cut"
|
||||
path = "cut.rs"
|
||||
|
||||
[dependencies]
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "cut"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use std::io::{BufRead, BufReader, Read, Write};
|
||||
use std::io::Result as IoResult;
|
||||
use std::io::{BufRead, BufReader, Read, Write};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub mod Bytes {
|
||||
|
|
|
@ -203,6 +203,7 @@ fn cut_bytes<R: Read>(reader: R, ranges: &[Range], opts: &Options) -> i32 {
|
|||
0
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn cut_fields_delimiter<R: Read>(
|
||||
reader: R,
|
||||
ranges: &[Range],
|
||||
|
@ -288,6 +289,7 @@ fn cut_fields_delimiter<R: Read>(
|
|||
0
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn cut_fields<R: Read>(reader: R, ranges: &[Range], opts: &FieldOptions) -> i32 {
|
||||
let newline_char = if opts.zero_terminated { b'\0' } else { b'\n' };
|
||||
if let Some(ref o_delim) = opts.out_delimeter {
|
||||
|
@ -464,8 +466,8 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
)
|
||||
})
|
||||
}
|
||||
(None, None, Some(field_ranges)) => list_to_ranges(&field_ranges[..], complement)
|
||||
.and_then(|ranges| {
|
||||
(None, None, Some(field_ranges)) => {
|
||||
list_to_ranges(&field_ranges[..], complement).and_then(|ranges| {
|
||||
let out_delim = match matches.opt_str("output-delimiter") {
|
||||
Some(s) => {
|
||||
if s.is_empty() {
|
||||
|
@ -488,7 +490,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
"a value 2 characters or longer",
|
||||
"--delimiter",
|
||||
"-d"
|
||||
).to_owned())
|
||||
))
|
||||
} else {
|
||||
let delim = if delim.is_empty() {
|
||||
"\0".to_owned()
|
||||
|
@ -517,27 +519,30 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
},
|
||||
)),
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
(ref b, ref c, ref f) if b.is_some() || c.is_some() || f.is_some() => Err(
|
||||
msg_expects_no_more_than_one_of!("--fields (-f)", "--chars (-c)", "--bytes (-b)")
|
||||
.to_owned(),
|
||||
msg_expects_no_more_than_one_of!("--fields (-f)", "--chars (-c)", "--bytes (-b)"),
|
||||
),
|
||||
_ => Err(msg_expects_one_of!("--fields (-f)", "--chars (-c)", "--bytes (-b)").to_owned()),
|
||||
_ => Err(msg_expects_one_of!(
|
||||
"--fields (-f)",
|
||||
"--chars (-c)",
|
||||
"--bytes (-b)"
|
||||
)),
|
||||
};
|
||||
|
||||
let mode_parse = match mode_parse {
|
||||
Err(_) => mode_parse,
|
||||
Ok(mode) => match mode {
|
||||
Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.opt_present("delimiter") => Err(
|
||||
msg_opt_only_usable_if!("printing a sequence of fields", "--delimiter", "-d")
|
||||
.to_owned(),
|
||||
msg_opt_only_usable_if!("printing a sequence of fields", "--delimiter", "-d"),
|
||||
),
|
||||
Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.opt_present("only-delimited") => {
|
||||
Err(msg_opt_only_usable_if!(
|
||||
"printing a sequence of fields",
|
||||
"--only-delimited",
|
||||
"-s"
|
||||
).to_owned())
|
||||
))
|
||||
}
|
||||
_ => Ok(mode),
|
||||
},
|
||||
|
|
|
@ -42,10 +42,7 @@ impl FromStr for Range {
|
|||
(Some(n), Some(m)) if m.is_empty() => {
|
||||
if let Ok(low) = n.parse::<usize>() {
|
||||
if low > 0 {
|
||||
Ok(Range {
|
||||
low,
|
||||
high: MAX - 1,
|
||||
})
|
||||
Ok(Range { low, high: MAX - 1 })
|
||||
} else {
|
||||
Err(field)
|
||||
}
|
||||
|
@ -53,7 +50,7 @@ impl FromStr for Range {
|
|||
Err(inval)
|
||||
}
|
||||
}
|
||||
(Some(n), Some(m)) if n.len() == 0 => {
|
||||
(Some(n), Some(m)) if n.is_empty() => {
|
||||
if let Ok(high) = m.parse::<usize>() {
|
||||
if high > 0 {
|
||||
Ok(Range { low: 1, high })
|
||||
|
@ -67,10 +64,7 @@ impl FromStr for Range {
|
|||
(Some(n), Some(m)) => match (n.parse::<usize>(), m.parse::<usize>()) {
|
||||
(Ok(low), Ok(high)) => {
|
||||
if low > 0 && low <= high {
|
||||
Ok(Range {
|
||||
low,
|
||||
high,
|
||||
})
|
||||
Ok(Range { low, high })
|
||||
} else if low == 0 {
|
||||
Err(field)
|
||||
} else {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "date"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_date"
|
||||
|
@ -11,8 +12,8 @@ path = "date.rs"
|
|||
[dependencies]
|
||||
chrono = "0.4.4"
|
||||
clap = "2.32.0"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "date"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -14,8 +14,8 @@ extern crate chrono;
|
|||
extern crate clap;
|
||||
extern crate uucore;
|
||||
|
||||
use chrono::{DateTime, FixedOffset, Local, Offset};
|
||||
use chrono::offset::Utc;
|
||||
use chrono::{DateTime, FixedOffset, Local, Offset};
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::path::PathBuf;
|
||||
|
@ -210,12 +210,11 @@ fn parse_cli(args: Vec<String>) -> Settings {
|
|||
"set time described by STRING")
|
||||
(@arg utc: -u --utc --universal
|
||||
"print or set Coordinated Universal Time (UTC)"))
|
||||
|
||||
// TODO: Decide whether this is appropriate.
|
||||
// The GNU date command has an explanation of all formatting options,
|
||||
// but the `chrono` crate has a few differences (most notably, the %Z option)
|
||||
// (after_help: include_str!("usage.txt")))
|
||||
.get_matches_from(args);
|
||||
.get_matches_from(args);
|
||||
|
||||
let format = if let Some(form) = matches.value_of("custom_format") {
|
||||
let form = form[1..].into();
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "dircolors"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_dircolors"
|
||||
|
@ -10,8 +11,8 @@ path = "dircolors.rs"
|
|||
|
||||
[dependencies]
|
||||
glob = "0.3.0"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "dircolors"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
pub const INTERNAL_DB: &str =
|
||||
r#"# Configuration file for dircolors, a utility to help you set the
|
||||
pub const INTERNAL_DB: &str = r#"# Configuration file for dircolors, a utility to help you set the
|
||||
# LS_COLORS environment variable used by GNU ls with the --color option.
|
||||
# Copyright (C) 1996-2016 Free Software Foundation, Inc.
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
|
|
|
@ -13,10 +13,10 @@ extern crate glob;
|
|||
#[macro_use]
|
||||
extern crate uucore;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::borrow::Borrow;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
||||
static SYNTAX: &str = "[OPTION]... [FILE]";
|
||||
static SUMMARY: &str = "Output commands to set the LS_COLORS environment variable.";
|
||||
|
@ -68,8 +68,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
.optflag("p", "print-database", "print the byte counts")
|
||||
.parse(args);
|
||||
|
||||
if (matches.opt_present("csh") || matches.opt_present("c-shell") || matches.opt_present("sh")
|
||||
|| matches.opt_present("bourne-shell")) && matches.opt_present("print-database")
|
||||
if (matches.opt_present("csh")
|
||||
|| matches.opt_present("c-shell")
|
||||
|| matches.opt_present("sh")
|
||||
|| matches.opt_present("bourne-shell"))
|
||||
&& matches.opt_present("print-database")
|
||||
{
|
||||
disp_err!(
|
||||
"the options to output dircolors' internal database and\nto select a shell \
|
||||
|
@ -120,7 +123,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
Ok(f) => {
|
||||
let fin = BufReader::new(f);
|
||||
result = parse(
|
||||
fin.lines().filter_map(|l| l.ok()),
|
||||
fin.lines().filter_map(Result::ok),
|
||||
out_format,
|
||||
matches.free[0].as_str(),
|
||||
)
|
||||
|
@ -291,7 +294,7 @@ where
|
|||
} else if key.starts_with('*') {
|
||||
result.push_str(format!("{}={}:", key, val).as_str());
|
||||
} else if lower == "options" || lower == "color" || lower == "eightbit" {
|
||||
// Slackware only. Ignore
|
||||
// Slackware only. Ignore
|
||||
} else if let Some(s) = table.get(lower.as_str()) {
|
||||
result.push_str(format!("{}={}:", s, val).as_str());
|
||||
} else {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "dirname"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_dirname"
|
||||
|
@ -10,8 +11,8 @@ path = "dirname.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "dirname"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "du"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_du"
|
||||
|
@ -10,8 +11,8 @@ path = "du.rs"
|
|||
|
||||
[dependencies]
|
||||
time = "0.1.40"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "du"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
259
src/du/du.rs
259
src/du/du.rs
|
@ -163,44 +163,36 @@ fn du(
|
|||
|
||||
for f in read {
|
||||
match f {
|
||||
Ok(entry) => {
|
||||
match Stat::new(entry.path()) {
|
||||
Ok(this_stat) => {
|
||||
if this_stat.is_dir {
|
||||
futures.push(du(this_stat, options, depth + 1, inodes));
|
||||
} else {
|
||||
if inodes.contains(&this_stat.inode) {
|
||||
continue;
|
||||
}
|
||||
inodes.insert(this_stat.inode);
|
||||
my_stat.size += this_stat.size;
|
||||
my_stat.blocks += this_stat.blocks;
|
||||
if options.all {
|
||||
stats.push(this_stat);
|
||||
}
|
||||
Ok(entry) => match Stat::new(entry.path()) {
|
||||
Ok(this_stat) => {
|
||||
if this_stat.is_dir {
|
||||
futures.push(du(this_stat, options, depth + 1, inodes));
|
||||
} else {
|
||||
if inodes.contains(&this_stat.inode) {
|
||||
continue;
|
||||
}
|
||||
inodes.insert(this_stat.inode);
|
||||
my_stat.size += this_stat.size;
|
||||
my_stat.blocks += this_stat.blocks;
|
||||
if options.all {
|
||||
stats.push(this_stat);
|
||||
}
|
||||
}
|
||||
Err(error) => show_error!("{}", error),
|
||||
}
|
||||
}
|
||||
Err(error) => show_error!("{}", error),
|
||||
},
|
||||
Err(error) => show_error!("{}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stats.extend(futures.into_iter().flat_map(|val| val).rev().filter_map(
|
||||
|stat| {
|
||||
if !options.separate_dirs && stat.path.parent().unwrap() == my_stat.path {
|
||||
my_stat.size += stat.size;
|
||||
my_stat.blocks += stat.blocks;
|
||||
}
|
||||
if options.max_depth == None || depth < options.max_depth.unwrap() {
|
||||
Some(stat)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
));
|
||||
stats.extend(futures.into_iter().flatten().rev().filter(|stat| {
|
||||
if !options.separate_dirs && stat.path.parent().unwrap() == my_stat.path {
|
||||
my_stat.size += stat.size;
|
||||
my_stat.blocks += stat.blocks;
|
||||
}
|
||||
options.max_depth == None || depth < options.max_depth.unwrap()
|
||||
}));
|
||||
stats.push(my_stat);
|
||||
Box::new(stats.into_iter())
|
||||
}
|
||||
|
@ -216,7 +208,7 @@ fn convert_size_human(size: u64, multiplier: u64, _block_size: u64) -> String {
|
|||
}
|
||||
|
||||
fn convert_size_b(size: u64, _multiplier: u64, _block_size: u64) -> String {
|
||||
format!("{}", ((size as f64) / (1 as f64)).ceil())
|
||||
format!("{}", ((size as f64) / (1_f64)).ceil())
|
||||
}
|
||||
|
||||
fn convert_size_k(size: u64, multiplier: u64, _block_size: u64) -> String {
|
||||
|
@ -224,13 +216,17 @@ fn convert_size_k(size: u64, multiplier: u64, _block_size: u64) -> String {
|
|||
}
|
||||
|
||||
fn convert_size_m(size: u64, multiplier: u64, _block_size: u64) -> String {
|
||||
format!("{}", ((size as f64) / ((multiplier * multiplier) as f64)).ceil())
|
||||
format!(
|
||||
"{}",
|
||||
((size as f64) / ((multiplier * multiplier) as f64)).ceil()
|
||||
)
|
||||
}
|
||||
|
||||
fn convert_size_other(size: u64, _multiplier: u64, block_size: u64) -> String {
|
||||
format!("{}", ((size as f64) / (block_size as f64)).ceil())
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn uumain(args: Vec<String>) -> i32 {
|
||||
let syntax = format!(
|
||||
"[OPTION]... [FILE]...
|
||||
|
@ -238,66 +234,109 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
NAME
|
||||
);
|
||||
let matches = new_coreopts!(&syntax, SUMMARY, LONG_HELP)
|
||||
// In task
|
||||
.optflag("a", "all", " write counts for all files, not just directories")
|
||||
// In main
|
||||
.optflag("", "apparent-size", "print apparent sizes, rather than disk usage
|
||||
// In task
|
||||
.optflag(
|
||||
"a",
|
||||
"all",
|
||||
" write counts for all files, not just directories",
|
||||
)
|
||||
// In main
|
||||
.optflag(
|
||||
"",
|
||||
"apparent-size",
|
||||
"print apparent sizes, rather than disk usage
|
||||
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 main
|
||||
.optopt("B", "block-size", "scale sizes by SIZE before printing them.
|
||||
in ('sparse') files, internal fragmentation, indirect blocks, and the like",
|
||||
)
|
||||
// In main
|
||||
.optopt(
|
||||
"B",
|
||||
"block-size",
|
||||
"scale sizes by SIZE before printing them.
|
||||
E.g., '-BM' prints sizes in units of 1,048,576 bytes. See SIZE format below.",
|
||||
"SIZE")
|
||||
// In main
|
||||
.optflag("b", "bytes", "equivalent to '--apparent-size --block-size=1'")
|
||||
// In main
|
||||
"SIZE",
|
||||
)
|
||||
// In main
|
||||
.optflag(
|
||||
"b",
|
||||
"bytes",
|
||||
"equivalent to '--apparent-size --block-size=1'",
|
||||
)
|
||||
// In main
|
||||
.optflag("c", "total", "produce a grand total")
|
||||
// In task
|
||||
// opts.optflag("D", "dereference-args", "dereference only symlinks that are listed
|
||||
// on the command line"),
|
||||
// In main
|
||||
// opts.optopt("", "files0-from", "summarize disk usage of the NUL-terminated file
|
||||
// names specified in file F;
|
||||
// If F is - then read names from standard input", "F"),
|
||||
// // In task
|
||||
// opts.optflag("H", "", "equivalent to --dereference-args (-D)"),
|
||||
// In main
|
||||
.optflag("h", "human-readable", "print sizes in human readable format (e.g., 1K 234M 2G)")
|
||||
// In main
|
||||
// In task
|
||||
// opts.optflag("D", "dereference-args", "dereference only symlinks that are listed
|
||||
// on the command line"),
|
||||
// In main
|
||||
// opts.optopt("", "files0-from", "summarize disk usage of the NUL-terminated file
|
||||
// names specified in file F;
|
||||
// If F is - then read names from standard input", "F"),
|
||||
// // In task
|
||||
// opts.optflag("H", "", "equivalent to --dereference-args (-D)"),
|
||||
// In main
|
||||
.optflag(
|
||||
"h",
|
||||
"human-readable",
|
||||
"print sizes in human readable format (e.g., 1K 234M 2G)",
|
||||
)
|
||||
// In main
|
||||
.optflag("", "si", "like -h, but use powers of 1000 not 1024")
|
||||
// In main
|
||||
// In main
|
||||
.optflag("k", "", "like --block-size=1K")
|
||||
// In task
|
||||
// In task
|
||||
.optflag("l", "count-links", "count sizes many times if hard linked")
|
||||
// // In main
|
||||
// // In main
|
||||
.optflag("m", "", "like --block-size=1M")
|
||||
// // In task
|
||||
// opts.optflag("L", "dereference", "dereference all symbolic links"),
|
||||
// // In task
|
||||
// opts.optflag("P", "no-dereference", "don't follow any symbolic links (this is the default)"),
|
||||
// // In main
|
||||
.optflag("0", "null", "end each output line with 0 byte rather than newline")
|
||||
// In main
|
||||
.optflag("S", "separate-dirs", "do not include size of subdirectories")
|
||||
// In main
|
||||
// // In task
|
||||
// opts.optflag("L", "dereference", "dereference all symbolic links"),
|
||||
// // In task
|
||||
// opts.optflag("P", "no-dereference", "don't follow any symbolic links (this is the default)"),
|
||||
// // In main
|
||||
.optflag(
|
||||
"0",
|
||||
"null",
|
||||
"end each output line with 0 byte rather than newline",
|
||||
)
|
||||
// In main
|
||||
.optflag(
|
||||
"S",
|
||||
"separate-dirs",
|
||||
"do not include size of subdirectories",
|
||||
)
|
||||
// In main
|
||||
.optflag("s", "summarize", "display only a total for each argument")
|
||||
// // In task
|
||||
// opts.optflag("x", "one-file-system", "skip directories on different file systems"),
|
||||
// // In task
|
||||
// opts.optopt("X", "exclude-from", "exclude files that match any pattern in FILE", "FILE"),
|
||||
// // In task
|
||||
// opts.optopt("", "exclude", "exclude files that match PATTERN", "PATTERN"),
|
||||
// In main
|
||||
.optopt("d", "max-depth", "print the total for a directory (or file, with --all)
|
||||
// // In task
|
||||
// opts.optflag("x", "one-file-system", "skip directories on different file systems"),
|
||||
// // In task
|
||||
// opts.optopt("X", "exclude-from", "exclude files that match any pattern in FILE", "FILE"),
|
||||
// // In task
|
||||
// opts.optopt("", "exclude", "exclude files that match PATTERN", "PATTERN"),
|
||||
// In main
|
||||
.optopt(
|
||||
"d",
|
||||
"max-depth",
|
||||
"print the total for a directory (or file, with --all)
|
||||
only if it is N or fewer levels below the command
|
||||
line argument; --max-depth=0 is the same as --summarize", "N")
|
||||
// In main
|
||||
.optflagopt("", "time", "show time of the last modification of any file in the
|
||||
line argument; --max-depth=0 is the same as --summarize",
|
||||
"N",
|
||||
)
|
||||
// In main
|
||||
.optflagopt(
|
||||
"",
|
||||
"time",
|
||||
"show time of the last modification of any file in the
|
||||
directory, or any of its subdirectories. If WORD is given, show time as WORD instead
|
||||
of modification time: atime, access, use, ctime or status", "WORD")
|
||||
// In main
|
||||
.optopt("", "time-style", "show times using style STYLE:
|
||||
full-iso, long-iso, iso, +FORMAT FORMAT is interpreted like 'date'", "STYLE")
|
||||
of modification time: atime, access, use, ctime or status",
|
||||
"WORD",
|
||||
)
|
||||
// In main
|
||||
.optopt(
|
||||
"",
|
||||
"time-style",
|
||||
"show times using style STYLE:
|
||||
full-iso, long-iso, iso, +FORMAT FORMAT is interpreted like 'date'",
|
||||
"STYLE",
|
||||
)
|
||||
.parse(args);
|
||||
|
||||
let summarize = matches.opt_present("summarize");
|
||||
|
@ -339,7 +378,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
};
|
||||
let convert_size_fn = {
|
||||
if matches.opt_present("human-readable") || matches.opt_present("si") {
|
||||
convert_size_human
|
||||
convert_size_human
|
||||
} else if matches.opt_present("b") {
|
||||
convert_size_b
|
||||
} else if matches.opt_present("k") {
|
||||
|
@ -353,26 +392,24 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
let convert_size = |size| convert_size_fn(size, multiplier, block_size);
|
||||
|
||||
let time_format_str = match matches.opt_str("time-style") {
|
||||
Some(s) => {
|
||||
match &s[..] {
|
||||
"full-iso" => "%Y-%m-%d %H:%M:%S.%f %z",
|
||||
"long-iso" => "%Y-%m-%d %H:%M",
|
||||
"iso" => "%Y-%m-%d",
|
||||
_ => {
|
||||
show_error!(
|
||||
"invalid argument '{}' for 'time style'
|
||||
Some(s) => match &s[..] {
|
||||
"full-iso" => "%Y-%m-%d %H:%M:%S.%f %z",
|
||||
"long-iso" => "%Y-%m-%d %H:%M",
|
||||
"iso" => "%Y-%m-%d",
|
||||
_ => {
|
||||
show_error!(
|
||||
"invalid argument '{}' for 'time style'
|
||||
Valid arguments are:
|
||||
- 'full-iso'
|
||||
- 'long-iso'
|
||||
- 'iso'
|
||||
Try '{} --help' for more information.",
|
||||
s,
|
||||
NAME
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
s,
|
||||
NAME
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
None => "%Y-%m-%d %H:%M",
|
||||
};
|
||||
|
||||
|
@ -389,9 +426,7 @@ Try '{} --help' for more information.",
|
|||
let (_, len) = iter.size_hint();
|
||||
let len = len.unwrap();
|
||||
for (index, stat) in iter.enumerate() {
|
||||
let size = if matches.opt_present("apparent-size") {
|
||||
stat.size
|
||||
} else if matches.opt_present("b") {
|
||||
let size = if matches.opt_present("apparent-size") || matches.opt_present("b") {
|
||||
stat.size
|
||||
} else {
|
||||
// C's stat is such that each block is assume to be 512 bytes
|
||||
|
@ -402,23 +437,21 @@ Try '{} --help' for more information.",
|
|||
let tm = {
|
||||
let (secs, nsecs) = {
|
||||
let time = match matches.opt_str("time") {
|
||||
Some(s) => {
|
||||
match &s[..] {
|
||||
"accessed" => stat.accessed,
|
||||
"created" => stat.created,
|
||||
"modified" => stat.modified,
|
||||
_ => {
|
||||
show_error!(
|
||||
"invalid argument 'modified' for '--time'
|
||||
Some(s) => match &s[..] {
|
||||
"accessed" => stat.accessed,
|
||||
"created" => stat.created,
|
||||
"modified" => stat.modified,
|
||||
_ => {
|
||||
show_error!(
|
||||
"invalid argument 'modified' for '--time'
|
||||
Valid arguments are:
|
||||
- 'accessed', 'created', 'modified'
|
||||
Try '{} --help' for more information.",
|
||||
NAME
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
NAME
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
None => stat.modified,
|
||||
};
|
||||
((time / 1000) as i64, (time % 1000 * 1_000_000) as i32)
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
name = "echo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_echo"
|
||||
path = "echo.rs"
|
||||
|
||||
[dependencies]
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "echo"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -43,7 +43,7 @@ fn parse_code(
|
|||
max_digits: u32,
|
||||
bits_per_digit: u32,
|
||||
) -> Option<char> {
|
||||
let mut ret = 0x80000000;
|
||||
let mut ret = 0x8000_0000;
|
||||
for _ in 0..max_digits {
|
||||
match input.peek().and_then(|c| c.to_digit(base)) {
|
||||
Some(n) => ret = (ret << bits_per_digit) | n,
|
||||
|
@ -71,8 +71,8 @@ fn print_escaped(input: &str, mut output: impl Write) -> io::Result<bool> {
|
|||
'b' => '\x08',
|
||||
'c' => {
|
||||
should_stop = true;
|
||||
break
|
||||
},
|
||||
break;
|
||||
}
|
||||
'e' => '\x1b',
|
||||
'f' => '\x0c',
|
||||
'n' => '\n',
|
||||
|
@ -90,7 +90,7 @@ fn print_escaped(input: &str, mut output: impl Write) -> io::Result<bool> {
|
|||
_ => {
|
||||
start = 0;
|
||||
next
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
let matches = new_coreopts!(SYNTAX, SUMMARY, HELP)
|
||||
.optflag("n", "", "do not output the trailing newline")
|
||||
.optflag("e", "", "enable interpretation of backslash escapes")
|
||||
.optflag("E", "", "disable interpretation of backslash escapes (default)")
|
||||
.optflag(
|
||||
"E",
|
||||
"",
|
||||
"disable interpretation of backslash escapes (default)",
|
||||
)
|
||||
.parse(args);
|
||||
|
||||
let no_newline = matches.opt_present("n");
|
||||
|
|
7
src/env/Cargo.toml
vendored
7
src/env/Cargo.toml
vendored
|
@ -3,7 +3,8 @@ name = "env"
|
|||
version = "0.0.1"
|
||||
authors = ["uutils developers"]
|
||||
description = "Set each NAME to VALUE in the environment and run COMMAND"
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
|
@ -13,9 +14,9 @@ path = "env.rs"
|
|||
[dependencies]
|
||||
clap = "2.33"
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
rust-ini = "0.13.0"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "env"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
8
src/env/env.rs
vendored
8
src/env/env.rs
vendored
|
@ -18,6 +18,7 @@ use ini::Ini;
|
|||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
use std::iter::Iterator;
|
||||
use std::process::Command;
|
||||
|
||||
const USAGE: &str = "env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]";
|
||||
|
@ -89,7 +90,8 @@ fn load_config_file(opts: &mut Options) -> Result<(), i32> {
|
|||
}
|
||||
};
|
||||
|
||||
for (_, prop) in &conf { // ignore all INI section lines (treat them as comments)
|
||||
for (_, prop) in &conf {
|
||||
// ignore all INI section lines (treat them as comments)
|
||||
for (key, value) in prop {
|
||||
env::set_var(key, value);
|
||||
}
|
||||
|
@ -159,11 +161,11 @@ fn run_env(args: Vec<String>) -> Result<(), i32> {
|
|||
let null = matches.is_present("null");
|
||||
let files = matches
|
||||
.values_of("file")
|
||||
.map(|v| v.collect())
|
||||
.map(Iterator::collect)
|
||||
.unwrap_or_else(|| Vec::with_capacity(0));
|
||||
let unsets = matches
|
||||
.values_of("unset")
|
||||
.map(|v| v.collect())
|
||||
.map(Iterator::collect)
|
||||
.unwrap_or_else(|| Vec::with_capacity(0));
|
||||
|
||||
let mut opts = Options {
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
name = "expand"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_expand"
|
||||
path = "expand.rs"
|
||||
|
||||
[dependencies]
|
||||
unicode-width = "0.1.5"
|
||||
getopts = "0.2.18"
|
||||
uucore = "0.0.1"
|
||||
unicode-width = "0.1.5"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "expand"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -45,7 +45,8 @@ fn tabstops_parse(s: String) -> Vec<usize> {
|
|||
crash!(1, "{}\n", "tab size cannot be 0");
|
||||
}
|
||||
|
||||
if let (false, _) = nums.iter()
|
||||
if let (false, _) = nums
|
||||
.iter()
|
||||
.fold((true, 0), |(acc, last), &n| (acc && last <= n, n))
|
||||
{
|
||||
crash!(1, "{}\n", "tab sizes must be ascending");
|
||||
|
@ -145,7 +146,7 @@ fn next_tabstop(tabstops: &[usize], col: usize) -> usize {
|
|||
if tabstops.len() == 1 {
|
||||
tabstops[0] - col % tabstops[0]
|
||||
} else {
|
||||
match tabstops.iter().skip_while(|&&t| t <= col).next() {
|
||||
match tabstops.iter().find(|&&t| t > col) {
|
||||
Some(t) => t - col,
|
||||
None => 1,
|
||||
}
|
||||
|
@ -169,7 +170,7 @@ fn expand(options: Options) {
|
|||
for file in options.files.into_iter() {
|
||||
let mut fh = open(file);
|
||||
|
||||
while match fh.read_until('\n' as u8, &mut buf) {
|
||||
while match fh.read_until(b'\n', &mut buf) {
|
||||
Ok(s) => s > 0,
|
||||
Err(_) => buf.is_empty(),
|
||||
} {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "expr"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_expr"
|
||||
|
@ -11,8 +12,8 @@ path = "expr.rs"
|
|||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
onig = "~4.3.2"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "expr"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -13,8 +13,8 @@ extern crate onig;
|
|||
#[macro_use]
|
||||
extern crate uucore;
|
||||
|
||||
mod tokens;
|
||||
mod syntax_tree;
|
||||
mod tokens;
|
||||
|
||||
static NAME: &str = "expr";
|
||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
@ -80,7 +80,7 @@ fn maybe_handle_help_or_version(args: &[String]) -> bool {
|
|||
|
||||
fn print_help() {
|
||||
//! The following is taken from GNU coreutils' "expr --help" output.
|
||||
print!(
|
||||
println!(
|
||||
r#"Usage: expr EXPRESSION
|
||||
or: expr OPTION
|
||||
|
||||
|
@ -131,8 +131,7 @@ Environment variables:
|
|||
* EXPR_DEBUG_TOKENS=1 dump expression's tokens
|
||||
* EXPR_DEBUG_RPN=1 dump expression represented in reverse polish notation
|
||||
* EXPR_DEBUG_SYA_STEP=1 dump each parser step
|
||||
* EXPR_DEBUG_AST=1 dump expression represented abstract syntax tree
|
||||
"#
|
||||
* EXPR_DEBUG_AST=1 dump expression represented abstract syntax tree"#
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
//! * https://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
||||
//!
|
||||
|
||||
use tokens::Token;
|
||||
use onig::{Regex, RegexOptions, Syntax};
|
||||
use tokens::Token;
|
||||
|
||||
type TokenStack = Vec<(usize, Token)>;
|
||||
pub type OperandsList = Vec<Box<ASTNode>>;
|
||||
|
@ -68,9 +68,9 @@ impl ASTNode {
|
|||
|
||||
fn new_node(token_idx: usize, op_type: &str, operands: OperandsList) -> Box<ASTNode> {
|
||||
Box::new(ASTNode::Node {
|
||||
token_idx: token_idx,
|
||||
token_idx,
|
||||
op_type: op_type.into(),
|
||||
operands: operands,
|
||||
operands,
|
||||
})
|
||||
}
|
||||
fn new_leaf(token_idx: usize, value: &str) -> Box<ASTNode> {
|
||||
|
@ -85,25 +85,27 @@ impl ASTNode {
|
|||
ASTNode::Node { ref op_type, .. } => match self.operand_values() {
|
||||
Err(reason) => Err(reason),
|
||||
Ok(operand_values) => match op_type.as_ref() {
|
||||
"+" => infix_operator_two_ints(|a: i64, b: i64| {
|
||||
checked_binop(|| a.checked_add(b), "+")
|
||||
}, &operand_values
|
||||
"+" => infix_operator_two_ints(
|
||||
|a: i64, b: i64| checked_binop(|| a.checked_add(b), "+"),
|
||||
&operand_values,
|
||||
),
|
||||
"-" => infix_operator_two_ints(|a: i64, b: i64| {
|
||||
checked_binop(|| a.checked_sub(b), "-")
|
||||
}, &operand_values
|
||||
"-" => infix_operator_two_ints(
|
||||
|a: i64, b: i64| checked_binop(|| a.checked_sub(b), "-"),
|
||||
&operand_values,
|
||||
),
|
||||
"*" => infix_operator_two_ints(|a: i64, b: i64| {
|
||||
checked_binop(|| a.checked_mul(b), "*")
|
||||
}, &operand_values
|
||||
"*" => infix_operator_two_ints(
|
||||
|a: i64, b: i64| checked_binop(|| a.checked_mul(b), "*"),
|
||||
&operand_values,
|
||||
),
|
||||
"/" => infix_operator_two_ints(|a: i64, b: i64| {
|
||||
"/" => infix_operator_two_ints(
|
||||
|a: i64, b: i64| {
|
||||
if b == 0 {
|
||||
Err("division by zero".to_owned())
|
||||
} else {
|
||||
checked_binop(|| a.checked_div(b), "/")
|
||||
}
|
||||
}, &operand_values
|
||||
},
|
||||
&operand_values,
|
||||
),
|
||||
"%" => infix_operator_two_ints(
|
||||
|a: i64, b: i64| {
|
||||
|
@ -158,7 +160,7 @@ impl ASTNode {
|
|||
}
|
||||
}
|
||||
pub fn operand_values(&self) -> Result<Vec<String>, String> {
|
||||
if let &ASTNode::Node { ref operands, .. } = self {
|
||||
if let ASTNode::Node { ref operands, .. } = *self {
|
||||
let mut out = Vec::with_capacity(operands.len());
|
||||
for operand in operands {
|
||||
match operand.evaluate() {
|
||||
|
@ -219,6 +221,7 @@ fn maybe_dump_ast(result: &Result<Box<ASTNode>, String>) {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn maybe_dump_rpn(rpn: &TokenStack) {
|
||||
use std::env;
|
||||
if let Ok(debug_var) = env::var("EXPR_DEBUG_RPN") {
|
||||
|
@ -298,17 +301,29 @@ fn push_token_to_either_stack(
|
|||
op_stack: &mut TokenStack,
|
||||
) -> Result<(), String> {
|
||||
let result = match *token {
|
||||
Token::Value { .. } => Ok(out_stack.push((token_idx, token.clone()))),
|
||||
Token::Value { .. } => {
|
||||
out_stack.push((token_idx, token.clone()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Token::InfixOp { .. } => if op_stack.is_empty() {
|
||||
Ok(op_stack.push((token_idx, token.clone())))
|
||||
} else {
|
||||
push_op_to_stack(token_idx, token, out_stack, op_stack)
|
||||
},
|
||||
Token::InfixOp { .. } => {
|
||||
if op_stack.is_empty() {
|
||||
op_stack.push((token_idx, token.clone()));
|
||||
Ok(())
|
||||
} else {
|
||||
push_op_to_stack(token_idx, token, out_stack, op_stack)
|
||||
}
|
||||
}
|
||||
|
||||
Token::PrefixOp { .. } => Ok(op_stack.push((token_idx, token.clone()))),
|
||||
Token::PrefixOp { .. } => {
|
||||
op_stack.push((token_idx, token.clone()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Token::ParOpen => Ok(op_stack.push((token_idx, token.clone()))),
|
||||
Token::ParOpen => {
|
||||
op_stack.push((token_idx, token.clone()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Token::ParClose => move_till_match_paren(out_stack, op_stack),
|
||||
};
|
||||
|
@ -316,6 +331,7 @@ fn push_token_to_either_stack(
|
|||
result
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn maybe_dump_shunting_yard_step(
|
||||
token_idx: usize,
|
||||
token: &Token,
|
||||
|
@ -341,15 +357,18 @@ fn push_op_to_stack(
|
|||
out_stack: &mut TokenStack,
|
||||
op_stack: &mut TokenStack,
|
||||
) -> Result<(), String> {
|
||||
if let &Token::InfixOp {
|
||||
if let Token::InfixOp {
|
||||
precedence: prec,
|
||||
left_assoc: la,
|
||||
..
|
||||
} = token
|
||||
} = *token
|
||||
{
|
||||
loop {
|
||||
match op_stack.last() {
|
||||
None => return Ok(op_stack.push((token_idx, token.clone()))),
|
||||
None => {
|
||||
op_stack.push((token_idx, token.clone()));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Some(&(_, Token::ParOpen)) => {
|
||||
op_stack.push((token_idx, token.clone()));
|
||||
|
@ -362,12 +381,14 @@ fn push_op_to_stack(
|
|||
precedence: prev_prec,
|
||||
..
|
||||
},
|
||||
)) => if la && prev_prec >= prec || !la && prev_prec > prec {
|
||||
out_stack.push(op_stack.pop().unwrap())
|
||||
} else {
|
||||
op_stack.push((token_idx, token.clone()));
|
||||
return Ok(());
|
||||
},
|
||||
)) => {
|
||||
if la && prev_prec >= prec || !la && prev_prec > prec {
|
||||
out_stack.push(op_stack.pop().unwrap())
|
||||
} else {
|
||||
op_stack.push((token_idx, token.clone()));
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Some(&(_, Token::PrefixOp { .. })) => {
|
||||
op_stack.push((token_idx, token.clone()));
|
||||
|
@ -487,10 +508,7 @@ fn prefix_operator_index(values: &[String]) -> Result<String, String> {
|
|||
let haystack = &values[0];
|
||||
let needles = &values[1];
|
||||
|
||||
let mut current_idx = 0;
|
||||
for ch_h in haystack.chars() {
|
||||
current_idx += 1;
|
||||
|
||||
for (current_idx, ch_h) in haystack.chars().enumerate() {
|
||||
for ch_n in needles.chars() {
|
||||
if ch_n == ch_h {
|
||||
return Ok(current_idx.to_string());
|
||||
|
|
|
@ -58,10 +58,7 @@ impl Token {
|
|||
}
|
||||
fn is_a_number(&self) -> bool {
|
||||
match *self {
|
||||
Token::Value { ref value, .. } => match value.parse::<i64>() {
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
},
|
||||
Token::Value { ref value, .. } => value.parse::<i64>().is_ok(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -144,12 +141,7 @@ fn maybe_dump_tokens_acc(tokens_acc: &[(usize, Token)]) {
|
|||
}
|
||||
}
|
||||
|
||||
fn push_token_if_not_escaped(
|
||||
acc: &mut Vec<(usize, Token)>,
|
||||
tok_idx: usize,
|
||||
token: Token,
|
||||
s: &str,
|
||||
) {
|
||||
fn push_token_if_not_escaped(acc: &mut Vec<(usize, Token)>, tok_idx: usize, token: Token, s: &str) {
|
||||
// Smells heuristics... :(
|
||||
let prev_is_plus = match acc.last() {
|
||||
None => false,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
name = "factor"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "uu_factor"
|
||||
|
@ -9,8 +10,8 @@ path = "factor.rs"
|
|||
|
||||
[dependencies]
|
||||
rand = "0.5"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "factor"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -33,7 +33,7 @@ mod numeric;
|
|||
|
||||
mod sieve;
|
||||
|
||||
#[path = "../../mkmain.rs"]
|
||||
#[path = "../#common/mkmain.rs"]
|
||||
mod mkmain;
|
||||
|
||||
// extended Euclid algorithm
|
||||
|
@ -80,9 +80,8 @@ fn main() {
|
|||
|
||||
// By default, we print the multiplicative inverses mod 2^64 of the first 1k primes
|
||||
let n = args()
|
||||
.skip(1)
|
||||
.next()
|
||||
.unwrap_or("1027".to_string())
|
||||
.nth(1)
|
||||
.unwrap_or_else(|| "1027".to_string())
|
||||
.parse::<usize>()
|
||||
.ok()
|
||||
.unwrap_or(1027);
|
||||
|
@ -115,7 +114,8 @@ fn main() {
|
|||
file,
|
||||
"\n];\n\n#[allow(dead_code)]\npub const NEXT_PRIME: u64 = {};\n",
|
||||
x
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -131,12 +131,12 @@ fn test_inverter() {
|
|||
|
||||
#[test]
|
||||
fn test_generator() {
|
||||
let prime_10001 = Sieve::primes().skip(10000).next();
|
||||
assert_eq!(prime_10001, Some(104743));
|
||||
let prime_10001 = Sieve::primes().skip(10_000).next();
|
||||
assert_eq!(prime_10001, Some(104_743));
|
||||
}
|
||||
|
||||
const MAX_WIDTH: usize = 102;
|
||||
const PREAMBLE: &'static str = r##"/*
|
||||
const PREAMBLE: &str = r##"/*
|
||||
* This file is part of the uutils coreutils package.
|
||||
*
|
||||
* (c) kwantam <kwantam@gmail.com>
|
||||
|
@ -149,5 +149,6 @@ const PREAMBLE: &'static str = r##"/*
|
|||
// Please do not edit by hand. Instead, modify and
|
||||
// re-run src/factor/gen_tables.rs.
|
||||
|
||||
pub const P_INVS_U64: &'static [(u64, u64, u64)] = &[
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
pub const P_INVS_U64: &[(u64, u64, u64)] = &[
|
||||
"##;
|
||||
|
|
|
@ -20,12 +20,12 @@ extern crate uucore;
|
|||
|
||||
use numeric::*;
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
use rand::{SeedableRng, thread_rng};
|
||||
use rand::rngs::SmallRng;
|
||||
use rand::{thread_rng, SeedableRng};
|
||||
use std::cmp::{max, min};
|
||||
use std::io::{stdin, BufRead};
|
||||
use std::num::Wrapping;
|
||||
use std::mem::swap;
|
||||
use std::num::Wrapping;
|
||||
|
||||
mod numeric;
|
||||
|
||||
|
@ -53,6 +53,7 @@ fn gcd(mut a: u64, mut b: u64) -> u64 {
|
|||
}
|
||||
|
||||
fn rho_pollard_find_divisor(num: u64) -> u64 {
|
||||
#![allow(clippy::many_single_char_names)]
|
||||
let range = Uniform::new(1, num);
|
||||
let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
|
||||
let mut x = range.sample(&mut rng);
|
||||
|
@ -154,7 +155,10 @@ fn print_factors(num: u64) {
|
|||
}
|
||||
|
||||
fn print_factors_str(num_str: &str) {
|
||||
if let Err(e) = num_str.parse::<u64>().and_then(|x| Ok(print_factors(x))) {
|
||||
if let Err(e) = num_str.parse::<u64>().and_then(|x| {
|
||||
print_factors(x);
|
||||
Ok(())
|
||||
}) {
|
||||
show_warning!("{}: {}", num_str, e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
* that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use std::u64::MAX as MAX_U64;
|
||||
use std::num::Wrapping;
|
||||
use std::u64::MAX as MAX_U64;
|
||||
|
||||
pub fn big_add(a: u64, b: u64, m: u64) -> u64 {
|
||||
let Wrapping(msb_mod_m) = Wrapping(MAX_U64) - Wrapping(m) + Wrapping(1);
|
||||
|
@ -125,7 +125,7 @@ pub fn is_prime(num: u64) -> bool {
|
|||
|
||||
// These witnesses detect all composites up to at least 2^64.
|
||||
// Discovered by Jim Sinclair, according to http://miller-rabin.appspot.com
|
||||
let witnesses = [2, 325, 9375, 28178, 450775, 9780504, 1795265022];
|
||||
let witnesses = [2, 325, 9_375, 28_178, 450_775, 9_780_504, 1_795_265_022];
|
||||
!witnesses
|
||||
.iter()
|
||||
.any(|&wit| witness(wit % num, exponent, num))
|
||||
|
|
|
@ -68,6 +68,7 @@ impl Sieve {
|
|||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn primes() -> PrimeSieve {
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
fn deref(x: &u64) -> u64 {
|
||||
*x
|
||||
}
|
||||
|
@ -78,6 +79,7 @@ impl Sieve {
|
|||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn odd_primes() -> PrimeSieve {
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
fn deref(x: &u64) -> u64 {
|
||||
*x
|
||||
}
|
||||
|
@ -124,11 +126,11 @@ impl Wheel {
|
|||
|
||||
/// The increments of a wheel of circumference 210
|
||||
/// (i.e., a wheel that skips all multiples of 2, 3, 5, 7)
|
||||
const WHEEL_INCS: &'static [u64] = &[
|
||||
const WHEEL_INCS: &[u64] = &[
|
||||
2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6,
|
||||
2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 2, 10, 2, 10,
|
||||
];
|
||||
const INIT_PRIMES: &'static [u64] = &[2, 3, 5, 7];
|
||||
const INIT_PRIMES: &[u64] = &[2, 3, 5, 7];
|
||||
|
||||
/// A min-heap of "infinite lists" of prime multiples, where a list is
|
||||
/// represented as (head, increment).
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
name = "false"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_false"
|
||||
path = "false.rs"
|
||||
|
||||
[dependencies]
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "false"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "fmt"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_fmt"
|
||||
|
@ -11,8 +12,8 @@ path = "fmt.rs"
|
|||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
unicode-width = "0.1.5"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "fmt"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -14,12 +14,12 @@ extern crate unicode_width;
|
|||
#[macro_use]
|
||||
extern crate uucore;
|
||||
|
||||
use std::cmp;
|
||||
use std::io::{BufReader, BufWriter, Read};
|
||||
use std::fs::File;
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use linebreak::break_lines;
|
||||
use parasplit::ParagraphStream;
|
||||
use std::cmp;
|
||||
use std::fs::File;
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use std::io::{BufReader, BufWriter, Read};
|
||||
|
||||
macro_rules! silent_unwrap(
|
||||
($exp:expr) => (
|
||||
|
@ -57,6 +57,7 @@ pub struct FmtOptions {
|
|||
tabwidth: usize,
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn uumain(args: Vec<String>) -> i32 {
|
||||
let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
|
||||
.optflag("c", "crown-margin", "First and second line of paragraph may have different indentations, in which case the first line's indentation is preserved, and each subsequent line's indentation matches the second line.")
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use FmtOptions;
|
||||
use parasplit::{ParaWords, Paragraph, WordInfo};
|
||||
use std::io::{BufWriter, Stdout, Write};
|
||||
use std::i64;
|
||||
use std::cmp;
|
||||
use std::i64;
|
||||
use std::io::{BufWriter, Stdout, Write};
|
||||
use std::mem;
|
||||
use FmtOptions;
|
||||
|
||||
struct BreakArgs<'a> {
|
||||
opts: &'a FmtOptions,
|
||||
|
@ -58,18 +58,19 @@ pub fn break_lines(para: &Paragraph, opts: &FmtOptions, ostream: &mut BufWriter<
|
|||
}
|
||||
};
|
||||
// print the init, if it exists, and get its length
|
||||
let p_init_len = w_len + if opts.crown || opts.tagged {
|
||||
// handle "init" portion
|
||||
silent_unwrap!(ostream.write_all(para.init_str.as_bytes()));
|
||||
para.init_len
|
||||
} else if !para.mail_header {
|
||||
// for non-(crown, tagged) that's the same as a normal indent
|
||||
silent_unwrap!(ostream.write_all(p_indent.as_bytes()));
|
||||
p_indent_len
|
||||
} else {
|
||||
// except that mail headers get no indent at all
|
||||
0
|
||||
};
|
||||
let p_init_len = w_len
|
||||
+ if opts.crown || opts.tagged {
|
||||
// handle "init" portion
|
||||
silent_unwrap!(ostream.write_all(para.init_str.as_bytes()));
|
||||
para.init_len
|
||||
} else if !para.mail_header {
|
||||
// for non-(crown, tagged) that's the same as a normal indent
|
||||
silent_unwrap!(ostream.write_all(p_indent.as_bytes()));
|
||||
p_indent_len
|
||||
} else {
|
||||
// except that mail headers get no indent at all
|
||||
0
|
||||
};
|
||||
// write first word after writing init
|
||||
silent_unwrap!(ostream.write_all(w.as_bytes()));
|
||||
|
||||
|
@ -218,17 +219,15 @@ fn find_kp_breakpoints<'a, T: Iterator<Item = &'a WordInfo<'a>>>(
|
|||
) -> Vec<(&'a WordInfo<'a>, bool)> {
|
||||
let mut iter = iter.peekable();
|
||||
// set up the initial null linebreak
|
||||
let mut linebreaks = vec![
|
||||
LineBreak {
|
||||
prev: 0,
|
||||
linebreak: None,
|
||||
break_before: false,
|
||||
demerits: 0,
|
||||
prev_rat: 0.0f32,
|
||||
length: args.init_len,
|
||||
fresh: false,
|
||||
},
|
||||
];
|
||||
let mut linebreaks = vec![LineBreak {
|
||||
prev: 0,
|
||||
linebreak: None,
|
||||
break_before: false,
|
||||
demerits: 0,
|
||||
prev_rat: 0.0f32,
|
||||
length: args.init_len,
|
||||
fresh: false,
|
||||
}];
|
||||
// this vec holds the current active linebreaks; next_ holds the breaks that will be active for
|
||||
// the next word
|
||||
let active_breaks = &mut vec![0];
|
||||
|
@ -275,7 +274,9 @@ fn find_kp_breakpoints<'a, T: Iterator<Item = &'a WordInfo<'a>>>(
|
|||
}
|
||||
|
||||
// get the new length
|
||||
let tlen = w.word_nchars + args.compute_width(w, active.length, active.fresh) + slen
|
||||
let tlen = w.word_nchars
|
||||
+ args.compute_width(w, active.length, active.fresh)
|
||||
+ slen
|
||||
+ active.length;
|
||||
|
||||
// if tlen is longer than args.opts.width, we drop this break from the active list
|
||||
|
@ -304,7 +305,8 @@ fn find_kp_breakpoints<'a, T: Iterator<Item = &'a WordInfo<'a>>>(
|
|||
// do not even consider adding a line that has too many demerits
|
||||
// also, try to detect overflow by checking signum
|
||||
let total_demerits = new_demerits + active.demerits;
|
||||
if new_demerits < BAD_INFTY_SQ && total_demerits < ld_new
|
||||
if new_demerits < BAD_INFTY_SQ
|
||||
&& total_demerits < ld_new
|
||||
&& active.demerits.signum() <= new_demerits.signum()
|
||||
{
|
||||
ld_new = total_demerits;
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use std::iter::Peekable;
|
||||
use std::io::{BufRead, Lines};
|
||||
use std::iter::Peekable;
|
||||
use std::slice::Iter;
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
use FileOrStdReader;
|
||||
|
@ -72,10 +72,7 @@ pub struct FileLines<'a> {
|
|||
|
||||
impl<'a> FileLines<'a> {
|
||||
fn new<'b>(opts: &'b FmtOptions, lines: Lines<&'b mut FileOrStdReader>) -> FileLines<'b> {
|
||||
FileLines {
|
||||
opts,
|
||||
lines,
|
||||
}
|
||||
FileLines { opts, lines }
|
||||
}
|
||||
|
||||
// returns true if this line should be formatted
|
||||
|
@ -164,24 +161,28 @@ impl<'a> Iterator for FileLines<'a> {
|
|||
// emit a blank line
|
||||
// Err(true) indicates that this was a linebreak,
|
||||
// which is important to know when detecting mail headers
|
||||
if n.chars().all(|c| c.is_whitespace()) {
|
||||
if n.chars().all(char::is_whitespace) {
|
||||
return Some(Line::NoFormatLine("".to_owned(), true));
|
||||
}
|
||||
|
||||
let (pmatch, poffset) = self.match_prefix(&n[..]);
|
||||
|
||||
// if this line does not match the prefix,
|
||||
// emit the line unprocessed and iterate again
|
||||
let (pmatch, poffset) = self.match_prefix(&n[..]);
|
||||
if !pmatch {
|
||||
return Some(Line::NoFormatLine(n, false));
|
||||
} else if n[poffset + self.opts.prefix.len()..]
|
||||
.chars()
|
||||
.all(|c| c.is_whitespace())
|
||||
}
|
||||
|
||||
// if the line matches the prefix, but is blank after,
|
||||
// don't allow lines to be combined through it (that is,
|
||||
// treat it like a blank line, except that since it's
|
||||
// not truly blank we will not allow mail headers on the
|
||||
// following line)
|
||||
if pmatch
|
||||
&& n[poffset + self.opts.prefix.len()..]
|
||||
.chars()
|
||||
.all(char::is_whitespace)
|
||||
{
|
||||
// if the line matches the prefix, but is blank after,
|
||||
// don't allow lines to be combined through it (that is,
|
||||
// treat it like a blank line, except that since it's
|
||||
// not truly blank we will not allow mail headers on the
|
||||
// following line)
|
||||
return Some(Line::NoFormatLine(n, false));
|
||||
}
|
||||
|
||||
|
@ -363,25 +364,31 @@ impl<'a> Iterator for ParagraphStream<'a> {
|
|||
}
|
||||
} else if !second_done {
|
||||
// now we have enough info to handle crown margin and tagged mode
|
||||
|
||||
// in both crown and tagged modes we require that prefix_len is the same
|
||||
if prefix_len != fl.prefix_len || pfxind_end != fl.pfxind_end {
|
||||
// in both crown and tagged modes we require that prefix_len is the same
|
||||
break;
|
||||
} else if self.opts.tagged && indent_len - 4 == fl.indent_len
|
||||
}
|
||||
|
||||
// in tagged mode, indent has to be *different* on following lines
|
||||
if self.opts.tagged
|
||||
&& indent_len - 4 == fl.indent_len
|
||||
&& indent_end == fl.indent_end
|
||||
{
|
||||
// in tagged mode, indent has to be *different* on following lines
|
||||
break;
|
||||
} else {
|
||||
// this is part of the same paragraph, get the indent info from this line
|
||||
indent_str.clear();
|
||||
indent_str.push_str(&fl.line[..fl.indent_end]);
|
||||
indent_len = fl.indent_len;
|
||||
indent_end = fl.indent_end;
|
||||
}
|
||||
|
||||
// this is part of the same paragraph, get the indent info from this line
|
||||
indent_str.clear();
|
||||
indent_str.push_str(&fl.line[..fl.indent_end]);
|
||||
indent_len = fl.indent_len;
|
||||
indent_end = fl.indent_end;
|
||||
|
||||
second_done = true;
|
||||
} else {
|
||||
// detect mismatch
|
||||
if indent_end != fl.indent_end || pfxind_end != fl.pfxind_end
|
||||
if indent_end != fl.indent_end
|
||||
|| pfxind_end != fl.pfxind_end
|
||||
|| indent_len != fl.indent_len
|
||||
|| prefix_len != fl.prefix_len
|
||||
{
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
name = "fold"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_fold"
|
||||
path = "fold.rs"
|
||||
|
||||
[dependencies]
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "fold"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -70,9 +70,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
fn handle_obsolete(args: &[String]) -> (Vec<String>, Option<String>) {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
let slice = &arg;
|
||||
if slice.starts_with('-') && slice.len() > 1
|
||||
&& slice.chars().nth(1).unwrap().is_digit(10)
|
||||
{
|
||||
if slice.starts_with('-') && slice.len() > 1 && slice.chars().nth(1).unwrap().is_digit(10) {
|
||||
let mut v = args.to_vec();
|
||||
v.remove(i);
|
||||
return (v, Some(slice[1..].to_owned()));
|
||||
|
@ -110,7 +108,7 @@ fn fold_file<T: Read>(mut file: BufReader<T>, bytes: bool, spaces: bool, width:
|
|||
let slice = {
|
||||
let slice = &line[i..i + width];
|
||||
if spaces && i + width < len {
|
||||
match slice.rfind(|ch: char| ch.is_whitespace()) {
|
||||
match slice.rfind(char::is_whitespace) {
|
||||
Some(m) => &slice[..=m],
|
||||
None => slice,
|
||||
}
|
||||
|
@ -145,11 +143,13 @@ fn fold_file<T: Read>(mut file: BufReader<T>, bytes: bool, spaces: bool, width:
|
|||
let ncount = routput.chars().fold(0, |out, ch: char| {
|
||||
out + match ch {
|
||||
'\t' => 8,
|
||||
'\x08' => if out > 0 {
|
||||
!0
|
||||
} else {
|
||||
0
|
||||
},
|
||||
'\x08' => {
|
||||
if out > 0 {
|
||||
!0
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
'\r' => return 0,
|
||||
_ => 1,
|
||||
}
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
name = "groups"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_groups"
|
||||
path = "groups.rs"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["entries"]
|
||||
[dependencies]
|
||||
uucore = { version = "0.0.2", features = ["entries"] }
|
||||
|
||||
[[bin]]
|
||||
name = "groups"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#[macro_use]
|
||||
extern crate uucore;
|
||||
use uucore::entries::{get_groups, Locate, Passwd, gid2grp};
|
||||
use uucore::entries::{get_groups, gid2grp, Locate, Passwd};
|
||||
|
||||
static SYNTAX: &str = "[user]";
|
||||
static SUMMARY: &str = "display current group names";
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "hashsum"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_hashsum"
|
||||
|
@ -19,8 +20,8 @@ regex-syntax = "0.6.7"
|
|||
sha1 = "0.6.0"
|
||||
sha2 = "0.6.0"
|
||||
sha3 = "0.6.0"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "hashsum"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -71,7 +71,7 @@ impl Digest for sha1::Sha1 {
|
|||
|
||||
// Implements the Digest trait for sha2 / sha3 algorithms with fixed ouput
|
||||
macro_rules! impl_digest_sha {
|
||||
($type: ty, $size: expr) => (
|
||||
($type: ty, $size: expr) => {
|
||||
impl Digest for $type {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
|
@ -89,14 +89,16 @@ macro_rules! impl_digest_sha {
|
|||
*self = Self::new();
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> usize { $size }
|
||||
fn output_bits(&self) -> usize {
|
||||
$size
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
// Implements the Digest trait for sha2 / sha3 algorithms with variable ouput
|
||||
macro_rules! impl_digest_shake {
|
||||
($type: ty) => (
|
||||
($type: ty) => {
|
||||
impl Digest for $type {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
|
@ -114,9 +116,11 @@ macro_rules! impl_digest_shake {
|
|||
*self = Self::new();
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> usize { 0 }
|
||||
fn output_bits(&self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
impl_digest_sha!(sha2::Sha224, 224);
|
||||
|
|
|
@ -32,6 +32,7 @@ use regex::Regex;
|
|||
use sha1::Sha1;
|
||||
use sha2::{Sha224, Sha256, Sha384, Sha512};
|
||||
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512, Shake128, Shake256};
|
||||
use std::cmp::Ordering;
|
||||
use std::fs::File;
|
||||
use std::io::{self, stdin, BufRead, BufReader, Read};
|
||||
use std::path::Path;
|
||||
|
@ -48,6 +49,7 @@ fn is_custom_binary(program: &str) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn detect_algo(
|
||||
program: &str,
|
||||
matches: &getopts::Matches,
|
||||
|
@ -64,10 +66,26 @@ fn detect_algo(
|
|||
"sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<dyn Digest>, 512),
|
||||
"sha3sum" => match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(224) => ("SHA3-224", Box::new(Sha3_224::new()) as Box<dyn Digest>, 224),
|
||||
Ok(256) => ("SHA3-256", Box::new(Sha3_256::new()) as Box<dyn Digest>, 256),
|
||||
Ok(384) => ("SHA3-384", Box::new(Sha3_384::new()) as Box<dyn Digest>, 384),
|
||||
Ok(512) => ("SHA3-512", Box::new(Sha3_512::new()) as Box<dyn Digest>, 512),
|
||||
Ok(224) => (
|
||||
"SHA3-224",
|
||||
Box::new(Sha3_224::new()) as Box<dyn Digest>,
|
||||
224,
|
||||
),
|
||||
Ok(256) => (
|
||||
"SHA3-256",
|
||||
Box::new(Sha3_256::new()) as Box<dyn Digest>,
|
||||
256,
|
||||
),
|
||||
Ok(384) => (
|
||||
"SHA3-384",
|
||||
Box::new(Sha3_384::new()) as Box<dyn Digest>,
|
||||
384,
|
||||
),
|
||||
Ok(512) => (
|
||||
"SHA3-512",
|
||||
Box::new(Sha3_512::new()) as Box<dyn Digest>,
|
||||
512,
|
||||
),
|
||||
Ok(_) => crash!(
|
||||
1,
|
||||
"Invalid output size for SHA3 (expected 224, 256, 384, or 512)"
|
||||
|
@ -76,27 +94,51 @@ fn detect_algo(
|
|||
},
|
||||
None => crash!(1, "--bits required for SHA3"),
|
||||
},
|
||||
"sha3-224sum" => ("SHA3-224", Box::new(Sha3_224::new()) as Box<dyn Digest>, 224),
|
||||
"sha3-256sum" => ("SHA3-256", Box::new(Sha3_256::new()) as Box<dyn Digest>, 256),
|
||||
"sha3-384sum" => ("SHA3-384", Box::new(Sha3_384::new()) as Box<dyn Digest>, 384),
|
||||
"sha3-512sum" => ("SHA3-512", Box::new(Sha3_512::new()) as Box<dyn Digest>, 512),
|
||||
"sha3-224sum" => (
|
||||
"SHA3-224",
|
||||
Box::new(Sha3_224::new()) as Box<dyn Digest>,
|
||||
224,
|
||||
),
|
||||
"sha3-256sum" => (
|
||||
"SHA3-256",
|
||||
Box::new(Sha3_256::new()) as Box<dyn Digest>,
|
||||
256,
|
||||
),
|
||||
"sha3-384sum" => (
|
||||
"SHA3-384",
|
||||
Box::new(Sha3_384::new()) as Box<dyn Digest>,
|
||||
384,
|
||||
),
|
||||
"sha3-512sum" => (
|
||||
"SHA3-512",
|
||||
Box::new(Sha3_512::new()) as Box<dyn Digest>,
|
||||
512,
|
||||
),
|
||||
"shake128sum" => match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(bits) => ("SHAKE128", Box::new(Shake128::new()) as Box<dyn Digest>, bits),
|
||||
Ok(bits) => (
|
||||
"SHAKE128",
|
||||
Box::new(Shake128::new()) as Box<dyn Digest>,
|
||||
bits,
|
||||
),
|
||||
Err(err) => crash!(1, "{}", err),
|
||||
},
|
||||
None => crash!(1, "--bits required for SHAKE-128"),
|
||||
},
|
||||
"shake256sum" => match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(bits) => ("SHAKE256", Box::new(Shake256::new()) as Box<dyn Digest>, bits),
|
||||
Ok(bits) => (
|
||||
"SHAKE256",
|
||||
Box::new(Shake256::new()) as Box<dyn Digest>,
|
||||
bits,
|
||||
),
|
||||
Err(err) => crash!(1, "{}", err),
|
||||
},
|
||||
None => crash!(1, "--bits required for SHAKE-256"),
|
||||
},
|
||||
_ => {
|
||||
{
|
||||
let mut set_or_crash = |n, val, bits| -> () {
|
||||
let mut set_or_crash = |n, val, bits| {
|
||||
if alg.is_some() {
|
||||
crash!(1, "You cannot combine multiple hash algorithms!")
|
||||
};
|
||||
|
@ -318,17 +360,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
matches.free
|
||||
};
|
||||
match hashsum(
|
||||
name,
|
||||
algo,
|
||||
files,
|
||||
binary,
|
||||
check,
|
||||
tag,
|
||||
status,
|
||||
quiet,
|
||||
strict,
|
||||
warn,
|
||||
bits,
|
||||
name, algo, files, binary, check, tag, status, quiet, strict, warn, bits,
|
||||
) {
|
||||
Ok(()) => return 0,
|
||||
Err(e) => return e,
|
||||
|
@ -367,6 +399,8 @@ Compute and check message digests.",
|
|||
print!("{}", opts.usage(&msg));
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn hashsum(
|
||||
algoname: &str,
|
||||
mut digest: Box<dyn Digest>,
|
||||
|
@ -442,11 +476,12 @@ fn hashsum(
|
|||
let f = safe_unwrap!(File::open(ck_filename));
|
||||
let mut ckf = BufReader::new(Box::new(f) as Box<dyn Read>);
|
||||
let real_sum = safe_unwrap!(digest_reader(
|
||||
&mut digest,
|
||||
&mut *digest,
|
||||
&mut ckf,
|
||||
binary_check,
|
||||
output_bits
|
||||
)).to_ascii_lowercase();
|
||||
))
|
||||
.to_ascii_lowercase();
|
||||
if sum == real_sum {
|
||||
if !quiet {
|
||||
println!("{}: OK", ck_filename);
|
||||
|
@ -459,7 +494,7 @@ fn hashsum(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary, output_bits));
|
||||
let sum = safe_unwrap!(digest_reader(&mut *digest, &mut file, binary, output_bits));
|
||||
if tag {
|
||||
println!("{} ({}) = {}", algoname, filename, sum);
|
||||
} else {
|
||||
|
@ -468,11 +503,11 @@ fn hashsum(
|
|||
}
|
||||
}
|
||||
if !status {
|
||||
if bad_format == 1 {
|
||||
show_warning!("{} line is improperly formatted", bad_format);
|
||||
} else if bad_format > 1 {
|
||||
show_warning!("{} lines are improperly formatted", bad_format);
|
||||
}
|
||||
match bad_format.cmp(&1) {
|
||||
Ordering::Equal => show_warning!("{} line is improperly formatted", bad_format),
|
||||
Ordering::Greater => show_warning!("{} lines are improperly formatted", bad_format),
|
||||
_ => {}
|
||||
};
|
||||
if failed > 0 {
|
||||
show_warning!("{} computed checksum did NOT match", failed);
|
||||
}
|
||||
|
@ -482,7 +517,7 @@ fn hashsum(
|
|||
}
|
||||
|
||||
fn digest_reader<'a, T: Read>(
|
||||
digest: &mut Box<dyn Digest + 'a>,
|
||||
digest: &mut (dyn Digest + 'a),
|
||||
reader: &mut BufReader<T>,
|
||||
binary: bool,
|
||||
output_bits: usize,
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "head"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_head"
|
||||
|
@ -10,8 +11,8 @@ path = "head.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "head"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#[macro_use]
|
||||
extern crate uucore;
|
||||
|
||||
use std::io::{stdin, BufRead, BufReader, Read};
|
||||
use std::fs::File;
|
||||
use std::io::{stdin, BufRead, BufReader, Read};
|
||||
use std::path::Path;
|
||||
use std::str::from_utf8;
|
||||
|
||||
|
@ -90,12 +90,14 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
}
|
||||
}
|
||||
}
|
||||
None => if let Some(count) = matches.opt_str("c") {
|
||||
match count.parse::<usize>() {
|
||||
Ok(m) => settings.mode = FilterMode::Bytes(m),
|
||||
Err(e) => {
|
||||
show_error!("invalid byte count '{}': {}", count, e);
|
||||
return 1;
|
||||
None => {
|
||||
if let Some(count) = matches.opt_str("c") {
|
||||
match count.parse::<usize>() {
|
||||
Ok(m) => settings.mode = FilterMode::Bytes(m),
|
||||
Err(e) => {
|
||||
show_error!("invalid byte count '{}': {}", count, e);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -186,12 +188,16 @@ fn obsolete(options: &[String]) -> (Vec<String>, Option<usize>) {
|
|||
// TODO: handle errors on read
|
||||
fn head<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> bool {
|
||||
match settings.mode {
|
||||
FilterMode::Bytes(count) => for byte in reader.bytes().take(count) {
|
||||
print!("{}", byte.unwrap() as char);
|
||||
},
|
||||
FilterMode::Lines(count) => for line in reader.lines().take(count) {
|
||||
println!("{}", line.unwrap());
|
||||
},
|
||||
FilterMode::Bytes(count) => {
|
||||
for byte in reader.bytes().take(count) {
|
||||
print!("{}", byte.unwrap() as char);
|
||||
}
|
||||
}
|
||||
FilterMode::Lines(count) => {
|
||||
for line in reader.lines().take(count) {
|
||||
println!("{}", line.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "hostid"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_hostid"
|
||||
|
@ -10,8 +11,8 @@ path = "hostid.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "hostid"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -43,6 +43,9 @@ fn hostid() {
|
|||
result = gethostid();
|
||||
}
|
||||
|
||||
result &= 0xffff_ffff;
|
||||
#[allow(overflowing_literals)]
|
||||
let mask = 0xffff_ffff;
|
||||
|
||||
result &= mask;
|
||||
println!("{:0>8x}", result);
|
||||
}
|
||||
|
|
|
@ -2,18 +2,19 @@
|
|||
name = "hostname"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_hostname"
|
||||
path = "hostname.rs"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
winapi = { version = "0.3", features = ["sysinfoapi", "winsock2"] }
|
||||
getopts = "0.2"
|
||||
uucore = "0.0.1"
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.2"
|
||||
winapi = { version = "0.3", features = ["sysinfoapi", "winsock2"] }
|
||||
|
||||
[[bin]]
|
||||
name = "hostname"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -17,21 +17,21 @@ extern crate winapi;
|
|||
#[macro_use]
|
||||
extern crate uucore;
|
||||
|
||||
use std::collections::hash_set::HashSet;
|
||||
use std::iter::repeat;
|
||||
use std::io;
|
||||
use std::str;
|
||||
use std::net::ToSocketAddrs;
|
||||
use getopts::Matches;
|
||||
use std::collections::hash_set::HashSet;
|
||||
use std::io;
|
||||
use std::iter::repeat;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::str;
|
||||
|
||||
#[cfg(windows)]
|
||||
use winapi::um::winsock2::{GetHostNameW, WSACleanup, WSAStartup};
|
||||
#[cfg(windows)]
|
||||
use winapi::um::sysinfoapi::{ComputerNamePhysicalDnsHostname, SetComputerNameExW};
|
||||
use uucore::wide::*;
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::minwindef::MAKEWORD;
|
||||
#[cfg(windows)]
|
||||
use uucore::wide::*;
|
||||
use winapi::um::sysinfoapi::{ComputerNamePhysicalDnsHostname, SetComputerNameExW};
|
||||
#[cfg(windows)]
|
||||
use winapi::um::winsock2::{GetHostNameW, WSACleanup, WSAStartup};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use libc::gethostname;
|
||||
|
@ -43,8 +43,10 @@ const SUMMARY: &str = "Print or set the system's host name.";
|
|||
const LONG_HELP: &str = "";
|
||||
|
||||
pub fn uumain(args: Vec<String>) -> i32 {
|
||||
#![allow(clippy::let_and_return)]
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
#[allow(deprecated)]
|
||||
let mut data = std::mem::uninitialized();
|
||||
if WSAStartup(MAKEWORD(2, 2), &mut data as *mut _) != 0 {
|
||||
eprintln!("Failed to start Winsock 2.2");
|
||||
|
@ -61,12 +63,28 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
|
||||
fn execute(args: Vec<String>) -> i32 {
|
||||
let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
|
||||
.optflag("d", "domain", "Display the name of the DNS domain if possible")
|
||||
.optflag("i", "ip-address", "Display the network address(es) of the host")
|
||||
.optflag(
|
||||
"d",
|
||||
"domain",
|
||||
"Display the name of the DNS domain if possible",
|
||||
)
|
||||
.optflag(
|
||||
"i",
|
||||
"ip-address",
|
||||
"Display the network address(es) of the host",
|
||||
)
|
||||
// TODO: support --long
|
||||
.optflag("f", "fqdn", "Display the FQDN (Fully Qualified Domain Name) (default)")
|
||||
.optflag("s", "short", "Display the short hostname (the portion before the first dot) if \
|
||||
possible")
|
||||
.optflag(
|
||||
"f",
|
||||
"fqdn",
|
||||
"Display the FQDN (Fully Qualified Domain Name) (default)",
|
||||
)
|
||||
.optflag(
|
||||
"s",
|
||||
"short",
|
||||
"Display the short hostname (the portion before the first dot) if \
|
||||
possible",
|
||||
)
|
||||
.parse(args);
|
||||
|
||||
match matches.free.len() {
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
name = "id"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_id"
|
||||
path = "id.rs"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["entries", "process"]
|
||||
[dependencies]
|
||||
uucore = { version = "0.0.2", features = ["entries", "process"] }
|
||||
|
||||
[[bin]]
|
||||
name = "id"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
33
src/id/id.rs
33
src/id/id.rs
|
@ -16,28 +16,28 @@
|
|||
|
||||
#[macro_use]
|
||||
extern crate uucore;
|
||||
use std::ffi::CStr;
|
||||
use uucore::entries::{self, Group, Locate, Passwd};
|
||||
pub use uucore::libc;
|
||||
use uucore::libc::{getlogin, uid_t};
|
||||
use uucore::entries::{self, Group, Locate, Passwd};
|
||||
use uucore::process::{getegid, geteuid, getgid, getuid};
|
||||
use std::ffi::CStr;
|
||||
|
||||
macro_rules! cstr2cow {
|
||||
($v:expr) => (
|
||||
($v:expr) => {
|
||||
unsafe { CStr::from_ptr($v).to_string_lossy() }
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
mod audit {
|
||||
pub use std::mem::uninitialized;
|
||||
use super::libc::{c_int, c_uint, dev_t, pid_t, uid_t, uint64_t};
|
||||
use super::libc::{c_int, c_uint, dev_t, pid_t, uid_t};
|
||||
|
||||
pub type au_id_t = uid_t;
|
||||
pub type au_asid_t = pid_t;
|
||||
pub type au_event_t = c_uint;
|
||||
pub type au_emod_t = c_uint;
|
||||
pub type au_class_t = c_int;
|
||||
pub type au_flag_t = u64;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct au_mask {
|
||||
|
@ -58,7 +58,7 @@ mod audit {
|
|||
pub ai_mask: au_mask_t, // Audit masks.
|
||||
pub ai_termid: au_tid_addr_t, // Terminal ID.
|
||||
pub ai_asid: au_asid_t, // Audit session ID.
|
||||
pub ai_flags: uint64_t, // Audit session flags
|
||||
pub ai_flags: au_flag_t, // Audit session flags
|
||||
}
|
||||
pub type c_auditinfo_addr_t = c_auditinfo_addr;
|
||||
|
||||
|
@ -67,8 +67,8 @@ mod audit {
|
|||
}
|
||||
}
|
||||
|
||||
static SYNTAX: &'static str = "[OPTION]... [USER]";
|
||||
static SUMMARY: &'static str = "Print user and group information for the specified USER,\n or (when USER omitted) for the current user.";
|
||||
static SYNTAX: &str = "[OPTION]... [USER]";
|
||||
static SUMMARY: &str = "Print user and group information for the specified USER,\n or (when USER omitted) for the current user.";
|
||||
|
||||
pub fn uumain(args: Vec<String>) -> i32 {
|
||||
let mut opts = new_coreopts!(SYNTAX, SUMMARY, "");
|
||||
|
@ -117,7 +117,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
println!(
|
||||
"{}",
|
||||
if nflag {
|
||||
entries::gid2grp(id).unwrap_or(id.to_string())
|
||||
entries::gid2grp(id).unwrap_or_else(|_| id.to_string())
|
||||
} else {
|
||||
id.to_string()
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
println!(
|
||||
"{}",
|
||||
if nflag {
|
||||
entries::uid2usr(id).unwrap_or(id.to_string())
|
||||
entries::uid2usr(id).unwrap_or_else(|_| id.to_string())
|
||||
} else {
|
||||
id.to_string()
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
if nflag {
|
||||
possible_pw
|
||||
.map(|p| p.belongs_to())
|
||||
.unwrap_or(entries::get_groups().unwrap())
|
||||
.unwrap_or_else(|| entries::get_groups().unwrap())
|
||||
.iter()
|
||||
.map(|&id| entries::gid2grp(id).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -154,7 +154,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
} else {
|
||||
possible_pw
|
||||
.map(|p| p.belongs_to())
|
||||
.unwrap_or(entries::get_groups().unwrap())
|
||||
.unwrap_or_else(|| entries::get_groups().unwrap())
|
||||
.iter()
|
||||
.map(|&id| id.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -238,7 +238,7 @@ fn pretty(possible_pw: Option<Passwd>) {
|
|||
|
||||
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
||||
fn pline(possible_uid: Option<uid_t>) {
|
||||
let uid = possible_uid.unwrap_or(getuid());
|
||||
let uid = possible_uid.unwrap_or_else(getuid);
|
||||
let pw = Passwd::locate(uid).unwrap();
|
||||
|
||||
println!(
|
||||
|
@ -258,7 +258,7 @@ fn pline(possible_uid: Option<uid_t>) {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn pline(possible_uid: Option<uid_t>) {
|
||||
let uid = possible_uid.unwrap_or(getuid());
|
||||
let uid = possible_uid.unwrap_or_else(getuid);
|
||||
let pw = Passwd::locate(uid).unwrap();
|
||||
|
||||
println!(
|
||||
|
@ -278,7 +278,8 @@ fn auditid() {}
|
|||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn auditid() {
|
||||
let mut auditinfo: audit::c_auditinfo_addr_t = unsafe { audit::uninitialized() };
|
||||
#[allow(deprecated)]
|
||||
let mut auditinfo: audit::c_auditinfo_addr_t = unsafe { std::mem::uninitialized() };
|
||||
let address = &mut auditinfo as *mut audit::c_auditinfo_addr_t;
|
||||
if unsafe { audit::getaudit(address) } < 0 {
|
||||
println!("couldn't retrieve information");
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "install"
|
||||
version = "0.0.1"
|
||||
authors = ["Ben Eills <ben@beneills.com>"]
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_install"
|
||||
|
@ -11,11 +12,11 @@ path = "install.rs"
|
|||
[dependencies]
|
||||
getopts = "0.2.18"
|
||||
libc = ">= 0.2"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
time = "0.1.40"
|
||||
|
||||
[[bin]]
|
||||
name = "install"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -74,7 +74,8 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
};
|
||||
|
||||
let paths: Vec<PathBuf> = {
|
||||
fn string_to_path<'a>(s: &'a String) -> &'a Path {
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn string_to_path(s: &String) -> &Path {
|
||||
Path::new(s)
|
||||
};
|
||||
let to_owned = |p: &Path| p.to_owned();
|
||||
|
@ -100,49 +101,115 @@ fn parse_opts(args: Vec<String>) -> getopts::Matches {
|
|||
NAME
|
||||
);
|
||||
new_coreopts!(&syntax, SUMMARY, LONG_HELP)
|
||||
// TODO implement flag
|
||||
.optflagopt("", "backup", "(unimplemented) make a backup of each existing destination\n \
|
||||
file", "CONTROL")
|
||||
// TODO implement flag
|
||||
.optflag("b", "", "(unimplemented) like --backup but does not accept an argument")
|
||||
// TODO implement flag
|
||||
.optflagopt(
|
||||
"",
|
||||
"backup",
|
||||
"(unimplemented) make a backup of each existing destination\n \
|
||||
file",
|
||||
"CONTROL",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optflag(
|
||||
"b",
|
||||
"",
|
||||
"(unimplemented) like --backup but does not accept an argument",
|
||||
)
|
||||
.optflag("c", "", "ignored")
|
||||
// TODO implement flag
|
||||
.optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \
|
||||
files, and in some cases, do not modify the destination at all")
|
||||
.optflag("d", "directory", "treat all arguments as directory names.\n \
|
||||
create all components of the specified directories")
|
||||
// TODO implement flag
|
||||
.optflag("D", "", "(unimplemented) create all leading components of DEST except the\n \
|
||||
last, then copy SOURCE to DEST")
|
||||
// TODO implement flag
|
||||
.optflagopt("g", "group", "(unimplemented) set group ownership, instead of process'\n \
|
||||
current group", "GROUP")
|
||||
.optflagopt("m", "mode", "set permission mode (as in chmod), instead\n \
|
||||
of rwxr-xr-x", "MODE")
|
||||
// TODO implement flag
|
||||
.optflagopt("o", "owner", "(unimplemented) set ownership (super-user only)",
|
||||
"OWNER")
|
||||
// TODO implement flag
|
||||
.optflag("p", "preserve-timestamps", "(unimplemented) apply access/modification times\n \
|
||||
of SOURCE files to corresponding destination files")
|
||||
// TODO implement flag
|
||||
// TODO implement flag
|
||||
.optflag(
|
||||
"C",
|
||||
"compare",
|
||||
"(unimplemented) compare each pair of source and destination\n \
|
||||
files, and in some cases, do not modify the destination at all",
|
||||
)
|
||||
.optflag(
|
||||
"d",
|
||||
"directory",
|
||||
"treat all arguments as directory names.\n \
|
||||
create all components of the specified directories",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optflag(
|
||||
"D",
|
||||
"",
|
||||
"(unimplemented) create all leading components of DEST except the\n \
|
||||
last, then copy SOURCE to DEST",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optflagopt(
|
||||
"g",
|
||||
"group",
|
||||
"(unimplemented) set group ownership, instead of process'\n \
|
||||
current group",
|
||||
"GROUP",
|
||||
)
|
||||
.optflagopt(
|
||||
"m",
|
||||
"mode",
|
||||
"set permission mode (as in chmod), instead\n \
|
||||
of rwxr-xr-x",
|
||||
"MODE",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optflagopt(
|
||||
"o",
|
||||
"owner",
|
||||
"(unimplemented) set ownership (super-user only)",
|
||||
"OWNER",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optflag(
|
||||
"p",
|
||||
"preserve-timestamps",
|
||||
"(unimplemented) apply access/modification times\n \
|
||||
of SOURCE files to corresponding destination files",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optflag("s", "strip", "(unimplemented) strip symbol tables")
|
||||
// TODO implement flag
|
||||
.optflagopt("", "strip-program", "(unimplemented) program used to strip binaries",
|
||||
"PROGRAM")
|
||||
// TODO implement flag
|
||||
.optopt("S", "suffix", "(unimplemented) override the usual backup suffix", "SUFFIX")
|
||||
// TODO implement flag
|
||||
.optopt("t", "target-directory", "(unimplemented) move all SOURCE arguments into\n \
|
||||
DIRECTORY", "DIRECTORY")
|
||||
// TODO implement flag
|
||||
.optflag("T", "no-target-directory", "(unimplemented) treat DEST as a normal file")
|
||||
// TODO implement flag
|
||||
.optflagopt(
|
||||
"",
|
||||
"strip-program",
|
||||
"(unimplemented) program used to strip binaries",
|
||||
"PROGRAM",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optopt(
|
||||
"S",
|
||||
"suffix",
|
||||
"(unimplemented) override the usual backup suffix",
|
||||
"SUFFIX",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optopt(
|
||||
"t",
|
||||
"target-directory",
|
||||
"(unimplemented) move all SOURCE arguments into\n \
|
||||
DIRECTORY",
|
||||
"DIRECTORY",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optflag(
|
||||
"T",
|
||||
"no-target-directory",
|
||||
"(unimplemented) treat DEST as a normal file",
|
||||
)
|
||||
.optflag("v", "verbose", "explain what is being done")
|
||||
// TODO implement flag
|
||||
.optflag("P", "preserve-context", "(unimplemented) preserve security context")
|
||||
// TODO implement flag
|
||||
.optflagopt("Z", "context", "(unimplemented) set security context of files and\n \
|
||||
directories", "CONTEXT")
|
||||
// TODO implement flag
|
||||
.optflag(
|
||||
"P",
|
||||
"preserve-context",
|
||||
"(unimplemented) preserve security context",
|
||||
)
|
||||
// TODO implement flag
|
||||
.optflagopt(
|
||||
"Z",
|
||||
"context",
|
||||
"(unimplemented) set security context of files and\n \
|
||||
directories",
|
||||
"CONTEXT",
|
||||
)
|
||||
.parse(args)
|
||||
}
|
||||
|
||||
|
@ -244,8 +311,8 @@ fn behaviour(matches: &getopts::Matches) -> Result<Behaviour, i32> {
|
|||
};
|
||||
|
||||
Ok(Behaviour {
|
||||
main_function: main_function,
|
||||
specified_mode: specified_mode,
|
||||
main_function,
|
||||
specified_mode,
|
||||
suffix: backup_suffix,
|
||||
verbose: matches.opt_present("v"),
|
||||
})
|
||||
|
@ -259,7 +326,7 @@ fn behaviour(matches: &getopts::Matches) -> Result<Behaviour, i32> {
|
|||
/// Returns an integer intended as a program return code.
|
||||
///
|
||||
fn directory(paths: &[PathBuf], b: Behaviour) -> i32 {
|
||||
if paths.len() < 1 {
|
||||
if paths.is_empty() {
|
||||
println!("{} with -d requires at least one argument.", NAME);
|
||||
1
|
||||
} else {
|
||||
|
@ -297,7 +364,7 @@ fn directory(paths: &[PathBuf], b: Behaviour) -> i32 {
|
|||
/// Test if the path is a a new file path that can be
|
||||
/// created immediately
|
||||
fn is_new_file_path(path: &Path) -> bool {
|
||||
path.is_file() || !path.exists() && path.parent().map(|p| p.is_dir()).unwrap_or(true)
|
||||
path.is_file() || !path.exists() && path.parent().map(Path::is_dir).unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Perform an install, given a list of paths and behaviour.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extern crate libc;
|
||||
|
||||
use std::path::Path;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
#[cfg(not(windows))]
|
||||
use uucore::mode;
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "join"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_join"
|
||||
|
@ -10,8 +11,8 @@ path = "join.rs"
|
|||
|
||||
[dependencies]
|
||||
clap = "2.32.0"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "join"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -14,10 +14,10 @@ extern crate clap;
|
|||
#[macro_use]
|
||||
extern crate uucore;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use std::cmp::{min, Ordering};
|
||||
use std::fs::File;
|
||||
use std::io::{stdin, BufRead, BufReader, Lines, Stdin};
|
||||
use std::cmp::{min, Ordering};
|
||||
use clap::{App, Arg};
|
||||
|
||||
static NAME: &str = "join";
|
||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
@ -186,7 +186,7 @@ impl Spec {
|
|||
let file_num = match chars.next() {
|
||||
Some('0') => {
|
||||
// Must be all alone without a field specifier.
|
||||
if let None = chars.next() {
|
||||
if chars.next().is_none() {
|
||||
return Spec::Key;
|
||||
}
|
||||
|
||||
|
@ -260,9 +260,9 @@ impl<'a> State<'a> {
|
|||
};
|
||||
|
||||
State {
|
||||
key: key,
|
||||
key,
|
||||
file_name: name,
|
||||
file_num: file_num,
|
||||
file_num,
|
||||
print_unpaired: print_unpaired == file_num,
|
||||
lines: f.lines(),
|
||||
seq: Vec::new(),
|
||||
|
@ -294,7 +294,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
None
|
||||
}
|
||||
|
||||
/// Print lines in the buffers as headers.
|
||||
|
@ -317,9 +317,9 @@ impl<'a> State<'a> {
|
|||
for line1 in &self.seq {
|
||||
for line2 in &other.seq {
|
||||
if repr.uses_format() {
|
||||
repr.print_format(|spec| match spec {
|
||||
&Spec::Key => key,
|
||||
&Spec::Field(file_num, field_num) => {
|
||||
repr.print_format(|spec| match *spec {
|
||||
Spec::Key => key,
|
||||
Spec::Field(file_num, field_num) => {
|
||||
if file_num == self.file_num {
|
||||
return line1.get_field(field_num);
|
||||
}
|
||||
|
@ -423,13 +423,15 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_line(&self, line: &Line, repr: &Repr) {
|
||||
if repr.uses_format() {
|
||||
repr.print_format(|spec| match spec {
|
||||
&Spec::Key => line.get_field(self.key),
|
||||
&Spec::Field(file_num, field_num) => if file_num == self.file_num {
|
||||
line.get_field(field_num)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
repr.print_format(|spec| match *spec {
|
||||
Spec::Key => line.get_field(self.key),
|
||||
Spec::Field(file_num, field_num) => {
|
||||
if file_num == self.file_num {
|
||||
line.get_field(field_num)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
repr.print_field(line.get_field(self.key));
|
||||
|
@ -567,7 +569,7 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2",
|
|||
if let Some(value) = matches.value_of("t") {
|
||||
settings.separator = match value.len() {
|
||||
0 => Sep::Line,
|
||||
1 => Sep::Char(value.chars().nth(0).unwrap()),
|
||||
1 => Sep::Char(value.chars().next().unwrap()),
|
||||
_ => crash!(1, "multi-character tab {}", value),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "kill"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_kill"
|
||||
|
@ -10,11 +11,8 @@ path = "kill.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["signals"]
|
||||
uucore = { version = "0.0.2", features = ["signals"] }
|
||||
|
||||
[[bin]]
|
||||
name = "kill"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -58,7 +58,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
return kill(
|
||||
&matches
|
||||
.opt_str("signal")
|
||||
.unwrap_or(obs_signal.unwrap_or("9".to_owned())),
|
||||
.unwrap_or_else(|| obs_signal.unwrap_or_else(|| "9".to_owned())),
|
||||
matches.free,
|
||||
)
|
||||
}
|
||||
|
@ -74,9 +74,7 @@ fn handle_obsolete(mut args: Vec<String>) -> (Vec<String>, Option<String>) {
|
|||
while i < args.len() {
|
||||
// this is safe because slice is valid when it is referenced
|
||||
let slice = &args[i].clone();
|
||||
if slice.chars().next().unwrap() == '-' && slice.len() > 1
|
||||
&& slice.chars().nth(1).unwrap().is_digit(10)
|
||||
{
|
||||
if slice.starts_with('-') && slice.len() > 1 && slice.chars().nth(1).unwrap().is_digit(10) {
|
||||
let val = &slice[1..];
|
||||
match val.parse() {
|
||||
Ok(num) => {
|
||||
|
@ -107,7 +105,7 @@ fn table() {
|
|||
//TODO: obtain max signal width here
|
||||
|
||||
if (idx + 1) % 7 == 0 {
|
||||
println!("");
|
||||
println!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +131,7 @@ fn print_signals() {
|
|||
pos += signal.name.len();
|
||||
print!("{}", signal.name);
|
||||
if idx > 0 && pos > 73 {
|
||||
println!("");
|
||||
println!();
|
||||
pos = 0;
|
||||
} else {
|
||||
pos += 1;
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "link"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_link"
|
||||
|
@ -10,8 +11,8 @@ path = "link.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "link"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
extern crate uucore;
|
||||
|
||||
use std::fs::hard_link;
|
||||
use std::path::Path;
|
||||
use std::io::Error;
|
||||
use std::path::Path;
|
||||
|
||||
static SYNTAX: &str = "[OPTIONS] FILE1 FILE2";
|
||||
static SUMMARY: &str = "Create a link named FILE2 to FILE1";
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "ln"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_ln"
|
||||
|
@ -10,8 +11,8 @@ path = "ln.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "ln"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
59
src/ln/ln.rs
59
src/ln/ln.rs
|
@ -67,24 +67,45 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
NAME
|
||||
);
|
||||
let matches = new_coreopts!(&syntax, SUMMARY, LONG_HELP)
|
||||
.optflag("b", "", "make a backup of each file that would otherwise be overwritten or \
|
||||
removed")
|
||||
.optflagopt("", "backup", "make a backup of each file that would otherwise be overwritten \
|
||||
or removed", "METHOD")
|
||||
// TODO: opts.optflag("d", "directory", "allow users with appropriate privileges to attempt \
|
||||
// to make hard links to directories");
|
||||
.optflag(
|
||||
"b",
|
||||
"",
|
||||
"make a backup of each file that would otherwise be overwritten or \
|
||||
removed",
|
||||
)
|
||||
.optflagopt(
|
||||
"",
|
||||
"backup",
|
||||
"make a backup of each file that would otherwise be overwritten \
|
||||
or removed",
|
||||
"METHOD",
|
||||
)
|
||||
// TODO: opts.optflag("d", "directory", "allow users with appropriate privileges to attempt \
|
||||
// to make hard links to directories");
|
||||
.optflag("f", "force", "remove existing destination files")
|
||||
.optflag("i", "interactive", "prompt whether to remove existing destination files")
|
||||
// TODO: opts.optflag("L", "logical", "dereference TARGETs that are symbolic links");
|
||||
// TODO: opts.optflag("n", "no-dereference", "treat LINK_NAME as a normal file if it is a \
|
||||
// symbolic link to a directory");
|
||||
// TODO: opts.optflag("P", "physical", "make hard links directly to symbolic links");
|
||||
// TODO: opts.optflag("r", "relative", "create symbolic links relative to link location");
|
||||
.optflag(
|
||||
"i",
|
||||
"interactive",
|
||||
"prompt whether to remove existing destination files",
|
||||
)
|
||||
// TODO: opts.optflag("L", "logical", "dereference TARGETs that are symbolic links");
|
||||
// TODO: opts.optflag("n", "no-dereference", "treat LINK_NAME as a normal file if it is a \
|
||||
// symbolic link to a directory");
|
||||
// TODO: opts.optflag("P", "physical", "make hard links directly to symbolic links");
|
||||
// TODO: opts.optflag("r", "relative", "create symbolic links relative to link location");
|
||||
.optflag("s", "symbolic", "make symbolic links instead of hard links")
|
||||
.optopt("S", "suffix", "override the usual backup suffix", "SUFFIX")
|
||||
.optopt("t", "target-directory", "specify the DIRECTORY in which to create the links",
|
||||
"DIRECTORY")
|
||||
.optflag("T", "no-target-directory", "treat LINK_NAME as a normal file always")
|
||||
.optopt(
|
||||
"t",
|
||||
"target-directory",
|
||||
"specify the DIRECTORY in which to create the links",
|
||||
"DIRECTORY",
|
||||
)
|
||||
.optflag(
|
||||
"T",
|
||||
"no-target-directory",
|
||||
"treat LINK_NAME as a normal file always",
|
||||
)
|
||||
.optflag("v", "verbose", "print name of each linked file")
|
||||
.parse(args);
|
||||
|
||||
|
@ -159,7 +180,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
}
|
||||
|
||||
fn exec(files: &[PathBuf], settings: &Settings) -> i32 {
|
||||
if files.len() == 0 {
|
||||
if files.is_empty() {
|
||||
show_error!(
|
||||
"missing file operand\nTry '{} --help' for more information.",
|
||||
NAME
|
||||
|
@ -201,7 +222,7 @@ fn exec(files: &[PathBuf], settings: &Settings) -> i32 {
|
|||
);
|
||||
return 1;
|
||||
}
|
||||
assert!(files.len() != 0);
|
||||
assert!(!files.is_empty());
|
||||
|
||||
match link(&files[0], &files[1], settings) {
|
||||
Ok(_) => 0,
|
||||
|
@ -295,7 +316,7 @@ fn link(src: &PathBuf, dst: &PathBuf, settings: &Settings) -> Result<()> {
|
|||
print!("'{}' -> '{}'", dst.display(), src.display());
|
||||
match backup_path {
|
||||
Some(path) => println!(" (backup: '{}')", path.display()),
|
||||
None => println!(""),
|
||||
None => println!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -304,7 +325,7 @@ fn link(src: &PathBuf, dst: &PathBuf, settings: &Settings) -> Result<()> {
|
|||
fn read_yes() -> bool {
|
||||
let mut s = String::new();
|
||||
match stdin().read_line(&mut s) {
|
||||
Ok(_) => match s.char_indices().nth(0) {
|
||||
Ok(_) => match s.char_indices().next() {
|
||||
Some((_, x)) => x == 'y' || x == 'Y',
|
||||
_ => false,
|
||||
},
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "logname"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_logname"
|
||||
|
@ -10,8 +11,8 @@ path = "logname.rs"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "logname"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "ls"
|
||||
version = "0.0.1"
|
||||
authors = ["Jeremiah Peschka <jeremiah.peschka@gmail.com>"]
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_ls"
|
||||
|
@ -11,17 +12,14 @@ path = "ls.rs"
|
|||
[dependencies]
|
||||
getopts = "0.2.18"
|
||||
isatty = "0.1"
|
||||
lazy_static = "1.0.1"
|
||||
number_prefix = "0.2.8"
|
||||
term_grid = "0.1.5"
|
||||
termsize = "0.1.6"
|
||||
time = "0.1.40"
|
||||
lazy_static = "1.0.1"
|
||||
unicode-width = "0.1.5"
|
||||
|
||||
[dependencies.uucore]
|
||||
version = "0.0.1"
|
||||
features = ["entries", "fs"]
|
||||
uucore = { version = "0.0.2", features = ["entries", "fs"] }
|
||||
|
||||
[[bin]]
|
||||
name = "ls"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
108
src/ls/ls.rs
108
src/ls/ls.rs
|
@ -9,43 +9,41 @@
|
|||
//
|
||||
|
||||
extern crate getopts;
|
||||
#[cfg(unix)]
|
||||
extern crate isatty;
|
||||
extern crate number_prefix;
|
||||
extern crate term_grid;
|
||||
extern crate termsize;
|
||||
extern crate time;
|
||||
extern crate unicode_width;
|
||||
extern crate number_prefix;
|
||||
extern crate isatty;
|
||||
use isatty::stdout_isatty;
|
||||
use number_prefix::{Standalone, Prefixed, decimal_prefix};
|
||||
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
|
||||
use time::{strftime, Timespec};
|
||||
|
||||
#[cfg(unix)]
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
#[macro_use]
|
||||
extern crate uucore;
|
||||
#[cfg(unix)]
|
||||
use uucore::libc::{mode_t, S_ISGID, S_ISUID, S_ISVTX, S_IWOTH,
|
||||
S_IXGRP, S_IXOTH, S_IXUSR};
|
||||
|
||||
use std::fs;
|
||||
use std::fs::{DirEntry, FileType, Metadata};
|
||||
use std::path::{Path, PathBuf};
|
||||
#[cfg(unix)]
|
||||
use isatty::stdout_isatty;
|
||||
use number_prefix::{decimal_prefix, Prefixed, Standalone};
|
||||
use std::cmp::Reverse;
|
||||
#[cfg(unix)]
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::fs;
|
||||
use std::fs::{DirEntry, FileType, Metadata};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
#[cfg(unix)]
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
|
||||
use time::{strftime, Timespec};
|
||||
#[cfg(unix)]
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
#[cfg(unix)]
|
||||
use uucore::libc::{mode_t, S_ISGID, S_ISUID, S_ISVTX, S_IWOTH, S_IXGRP, S_IXOTH, S_IXUSR};
|
||||
|
||||
static NAME: &str = "ls";
|
||||
static SUMMARY: &str = "";
|
||||
|
@ -60,12 +58,13 @@ static DEFAULT_COLORS: &str = "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do
|
|||
|
||||
#[cfg(unix)]
|
||||
lazy_static! {
|
||||
static ref LS_COLORS: String = std::env::var("LS_COLORS").unwrap_or(DEFAULT_COLORS.to_string());
|
||||
static ref LS_COLORS: String =
|
||||
std::env::var("LS_COLORS").unwrap_or_else(|_| DEFAULT_COLORS.to_string());
|
||||
static ref COLOR_MAP: HashMap<&'static str, &'static str> = {
|
||||
let codes = LS_COLORS.split(":");
|
||||
let codes = LS_COLORS.split(':');
|
||||
let mut map = HashMap::new();
|
||||
for c in codes {
|
||||
let p: Vec<_> = c.split("=").collect();
|
||||
let p: Vec<_> = c.split('=').collect();
|
||||
if p.len() == 2 {
|
||||
map.insert(p[0], p[1]);
|
||||
}
|
||||
|
@ -160,7 +159,12 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
directory. This is especially useful when listing very large directories, \
|
||||
since not doing any sorting can be noticeably faster.",
|
||||
)
|
||||
.optflagopt("", "color", "Color output based on file type.", "always|auto|never")
|
||||
.optflagopt(
|
||||
"",
|
||||
"color",
|
||||
"Color output based on file type.",
|
||||
"always|auto|never",
|
||||
)
|
||||
.parse(args);
|
||||
|
||||
list(matches);
|
||||
|
@ -171,7 +175,7 @@ fn list(options: getopts::Matches) {
|
|||
let locs: Vec<String> = if options.free.is_empty() {
|
||||
vec![String::from(".")]
|
||||
} else {
|
||||
options.free.iter().cloned().collect()
|
||||
options.free.to_vec()
|
||||
};
|
||||
|
||||
let mut files = Vec::<PathBuf>::new();
|
||||
|
@ -277,20 +281,17 @@ fn max(lhs: usize, rhs: usize) -> usize {
|
|||
fn should_display(entry: &DirEntry, options: &getopts::Matches) -> bool {
|
||||
let ffi_name = entry.file_name();
|
||||
let name = ffi_name.to_string_lossy();
|
||||
if !options.opt_present("a") && !options.opt_present("A") {
|
||||
if name.starts_with('.') {
|
||||
return false;
|
||||
}
|
||||
if !options.opt_present("a") && !options.opt_present("A") && name.starts_with('.') {
|
||||
return false;
|
||||
}
|
||||
if options.opt_present("B") && name.ends_with('~') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
true
|
||||
}
|
||||
|
||||
fn enter_directory(dir: &PathBuf, options: &getopts::Matches) {
|
||||
let mut entries =
|
||||
safe_unwrap!(fs::read_dir(dir).and_then(|e| e.collect::<Result<Vec<_>, _>>()));
|
||||
let mut entries: Vec<_> = safe_unwrap!(fs::read_dir(dir).and_then(Iterator::collect));
|
||||
|
||||
entries.retain(|e| should_display(e, options));
|
||||
|
||||
|
@ -316,7 +317,7 @@ fn enter_directory(dir: &PathBuf, options: &getopts::Matches) {
|
|||
|
||||
fn get_metadata(entry: &PathBuf, options: &getopts::Matches) -> std::io::Result<Metadata> {
|
||||
if options.opt_present("L") {
|
||||
entry.metadata().or(entry.symlink_metadata())
|
||||
entry.metadata().or_else(|_| entry.symlink_metadata())
|
||||
} else {
|
||||
entry.symlink_metadata()
|
||||
}
|
||||
|
@ -336,14 +337,14 @@ fn display_dir_entry_size(entry: &PathBuf, options: &getopts::Matches) -> (usize
|
|||
fn pad_left(string: String, count: usize) -> String {
|
||||
if count > string.len() {
|
||||
let pad = count - string.len();
|
||||
let pad = String::from_utf8(vec![' ' as u8; pad]).unwrap();
|
||||
let pad = String::from_utf8(vec![b' '; pad]).unwrap();
|
||||
format!("{}{}", pad, string)
|
||||
} else {
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
fn display_items(items: &Vec<PathBuf>, strip: Option<&Path>, options: &getopts::Matches) {
|
||||
fn display_items(items: &[PathBuf], strip: Option<&Path>, options: &getopts::Matches) {
|
||||
if options.opt_present("long") || options.opt_present("numeric-uid-gid") {
|
||||
let (mut max_links, mut max_size) = (1, 1);
|
||||
for item in items {
|
||||
|
@ -356,19 +357,17 @@ fn display_items(items: &Vec<PathBuf>, strip: Option<&Path>, options: &getopts::
|
|||
}
|
||||
} else {
|
||||
if !options.opt_present("1") {
|
||||
let names = items
|
||||
.iter()
|
||||
.filter_map(|i| {
|
||||
let md = get_metadata(i, options);
|
||||
match md {
|
||||
Err(e) => {
|
||||
let filename = get_file_name(i, strip);
|
||||
show_error!("{}: {}", filename, e);
|
||||
None
|
||||
}
|
||||
Ok(md) => Some(display_file_name(&i, strip, &md, options)),
|
||||
let names = items.iter().filter_map(|i| {
|
||||
let md = get_metadata(i, options);
|
||||
match md {
|
||||
Err(e) => {
|
||||
let filename = get_file_name(i, strip);
|
||||
show_error!("{}: {}", filename, e);
|
||||
None
|
||||
}
|
||||
});
|
||||
Ok(md) => Some(display_file_name(&i, strip, &md, options)),
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(size) = termsize::get() {
|
||||
let mut grid = Grid::new(GridOptions {
|
||||
|
@ -454,7 +453,7 @@ fn display_uname(metadata: &Metadata, options: &getopts::Matches) -> String {
|
|||
if options.opt_present("numeric-uid-gid") {
|
||||
metadata.uid().to_string()
|
||||
} else {
|
||||
entries::uid2usr(metadata.uid()).unwrap_or(metadata.uid().to_string())
|
||||
entries::uid2usr(metadata.uid()).unwrap_or_else(|_| metadata.uid().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,7 +462,7 @@ fn display_group(metadata: &Metadata, options: &getopts::Matches) -> String {
|
|||
if options.opt_present("numeric-uid-gid") {
|
||||
metadata.gid().to_string()
|
||||
} else {
|
||||
entries::gid2grp(metadata.gid()).unwrap_or(metadata.gid().to_string())
|
||||
entries::gid2grp(metadata.gid()).unwrap_or_else(|_| metadata.gid().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +510,7 @@ fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String
|
|||
if options.opt_present("human-readable") {
|
||||
match decimal_prefix(metadata.len() as f64) {
|
||||
Standalone(bytes) => bytes.to_string(),
|
||||
Prefixed(prefix, bytes) => format!("{:.2}{}", bytes, prefix).to_uppercase()
|
||||
Prefixed(prefix, bytes) => format!("{:.2}{}", bytes, prefix).to_uppercase(),
|
||||
}
|
||||
} else {
|
||||
metadata.len().to_string()
|
||||
|
@ -533,7 +532,7 @@ fn get_file_name(name: &Path, strip: Option<&Path>) -> String {
|
|||
Some(prefix) => name.strip_prefix(prefix).unwrap_or(name),
|
||||
None => name,
|
||||
};
|
||||
if name.as_os_str().len() == 0 {
|
||||
if name.as_os_str().is_empty() {
|
||||
name = Path::new(".");
|
||||
}
|
||||
name.to_string_lossy().into_owned()
|
||||
|
@ -595,12 +594,13 @@ fn color_name(name: String, typ: &str) -> String {
|
|||
|
||||
#[cfg(unix)]
|
||||
macro_rules! has {
|
||||
($mode:expr, $perm:expr) => (
|
||||
($mode:expr, $perm:expr) => {
|
||||
$mode & ($perm as mode_t) != 0
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn display_file_name(
|
||||
path: &Path,
|
||||
strip: Option<&Path>,
|
||||
|
@ -618,7 +618,7 @@ fn display_file_name(
|
|||
Some(val) => match val.as_ref() {
|
||||
"always" | "yes" | "force" => true,
|
||||
"auto" | "tty" | "if-tty" => stdout_isatty(),
|
||||
"never" | "no" | "none" | _ => false,
|
||||
/* "never" | "no" | "none" | */ _ => false,
|
||||
},
|
||||
};
|
||||
let classify = options.opt_present("classify");
|
||||
|
@ -697,7 +697,7 @@ fn display_file_name(
|
|||
|
||||
Cell {
|
||||
contents: name,
|
||||
width: width,
|
||||
width,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "mkdir"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_mkdir"
|
||||
|
@ -11,8 +12,8 @@ path = "mkdir.rs"
|
|||
[dependencies]
|
||||
getopts = "0.2.18"
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "mkdir"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -55,16 +55,15 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
// Translate a ~str in octal form to u16, default to 755
|
||||
// Not tested on Windows
|
||||
let mode_match = matches.opts_str(&["mode".to_owned()]);
|
||||
let mode: u16 = if mode_match.is_some() {
|
||||
let m = mode_match.unwrap();
|
||||
let res: Option<u16> = u16::from_str_radix(&m, 8).ok();
|
||||
if res.is_some() {
|
||||
res.unwrap()
|
||||
} else {
|
||||
crash!(1, "no mode given");
|
||||
let mode: u16 = match mode_match {
|
||||
Some(m) => {
|
||||
let res: Option<u16> = u16::from_str_radix(&m, 8).ok();
|
||||
match res {
|
||||
Some(r) => r,
|
||||
_ => crash!(1, "no mode given"),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
0o755 as u16
|
||||
_ => 0o755 as u16,
|
||||
};
|
||||
|
||||
let dirs = matches.free;
|
||||
|
@ -76,7 +75,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
|
||||
fn print_help(opts: &getopts::Options) {
|
||||
println!("{} {}", NAME, VERSION);
|
||||
println!("");
|
||||
println!();
|
||||
println!("Usage:");
|
||||
print!(
|
||||
"{}",
|
||||
|
@ -113,7 +112,11 @@ fn exec(dirs: Vec<String>, recursive: bool, mode: u16, verbose: bool) -> i32 {
|
|||
* Wrapper to catch errors, return 1 if failed
|
||||
*/
|
||||
fn mkdir(path: &Path, recursive: bool, mode: u16, verbose: bool) -> i32 {
|
||||
let create_dir = if recursive { fs::create_dir_all } else { fs::create_dir };
|
||||
let create_dir = if recursive {
|
||||
fs::create_dir_all
|
||||
} else {
|
||||
fs::create_dir
|
||||
};
|
||||
if let Err(e) = create_dir(path) {
|
||||
show_info!("{}: {}", path.display(), e.to_string());
|
||||
return 1;
|
||||
|
@ -125,17 +128,13 @@ fn mkdir(path: &Path, recursive: bool, mode: u16, verbose: bool) -> i32 {
|
|||
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
fn chmod(path: &Path, mode: u16) -> i32 {
|
||||
use fs::{Permissions, set_permissions};
|
||||
use std::os::unix::fs::{PermissionsExt};
|
||||
use fs::{set_permissions, Permissions};
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let mode = Permissions::from_mode(mode as u32);
|
||||
let mode = Permissions::from_mode(u32::from(mode));
|
||||
|
||||
if let Err(err) = set_permissions(path, mode) {
|
||||
show_error!(
|
||||
"{}: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
show_error!("{}: {}", path.display(), err);
|
||||
return 1;
|
||||
}
|
||||
0
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "mkfifo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_mkfifo"
|
||||
|
@ -11,8 +12,8 @@ path = "mkfifo.rs"
|
|||
[dependencies]
|
||||
getopts = "0.2.18"
|
||||
libc = "0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "mkfifo"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -76,10 +76,8 @@ Create a FIFO with the given name.",
|
|||
let mut exit_status = 0;
|
||||
for f in &matches.free {
|
||||
let err = unsafe {
|
||||
mkfifo(
|
||||
CString::new(f.as_bytes()).unwrap().as_ptr(),
|
||||
mode as libc::mode_t,
|
||||
)
|
||||
let name = CString::new(f.as_bytes()).unwrap();
|
||||
mkfifo(name.as_ptr(), mode as libc::mode_t)
|
||||
};
|
||||
if err == -1 {
|
||||
show_error!(
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
name = "mknod"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
build = "../../mkmain.rs"
|
||||
license = "MIT"
|
||||
build = "../#common/mkmain.rs"
|
||||
|
||||
[lib]
|
||||
name = "uu_mknod"
|
||||
|
@ -11,8 +12,8 @@ path = "mknod.rs"
|
|||
[dependencies]
|
||||
getopts = "0.2.18"
|
||||
libc = "^0.2.42"
|
||||
uucore = "0.0.1"
|
||||
uucore = "0.0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "mknod"
|
||||
path = "../../uumain.rs"
|
||||
path = "../#common/uumain.rs"
|
||||
|
|
|
@ -31,8 +31,7 @@ const MODE_RW_UGO: mode_t = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_
|
|||
#[inline(always)]
|
||||
fn makedev(maj: u64, min: u64) -> dev_t {
|
||||
// pick up from <sys/sysmacros.h>
|
||||
((min & 0xff) | ((maj & 0xfff) << 8) | (((min & !0xff)) << 12) | (((maj & !0xfff)) << 32))
|
||||
as dev_t
|
||||
((min & 0xff) | ((maj & 0xfff) << 8) | ((min & !0xff) << 12) | ((maj & !0xfff) << 32)) as dev_t
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -45,6 +44,7 @@ fn _makenod(path: CString, mode: mode_t, dev: dev_t) -> i32 {
|
|||
unsafe { libc::mknod(path.as_ptr(), mode, dev) }
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn uumain(args: Vec<String>) -> i32 {
|
||||
let mut opts = Options::new();
|
||||
|
||||
|
@ -130,7 +130,7 @@ for details about the options it supports.",
|
|||
// 'mknod /dev/rst0 character 18 0'.
|
||||
let ch = args[1]
|
||||
.chars()
|
||||
.nth(0)
|
||||
.next()
|
||||
.expect("Failed to get the first char");
|
||||
|
||||
if ch == 'p' {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue