mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge branch 'main' into fmt_implement_default_for_fmtoptions
This commit is contained in:
commit
a3b80e1bef
234 changed files with 4854 additions and 2994 deletions
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
github: uutils
|
25
.github/workflows/CICD.yml
vendored
25
.github/workflows/CICD.yml
vendored
|
@ -220,7 +220,7 @@ jobs:
|
|||
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
|
||||
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
|
||||
# * convert any warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message>
|
||||
S=$(cargo clippy --all-targets ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} -- -W clippy::manual_string_new -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::${fault_type} file=\2,line=\3,col=\4::${fault_prefix}: \`cargo clippy\`: \1 (file:'\2', line:\3)/p;" -e '}' ; fault=true ; }
|
||||
S=$(cargo clippy --all-targets ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_UTILITY_LIST_OPTIONS }} -- -W clippy::default_trait_access -W clippy::manual_string_new -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::${fault_type} file=\2,line=\3,col=\4::${fault_prefix}: \`cargo clippy\`: \1 (file:'\2', line:\3)/p;" -e '}' ; fault=true ; }
|
||||
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
|
||||
|
||||
style_spellcheck:
|
||||
|
@ -319,7 +319,7 @@ jobs:
|
|||
shell: bash
|
||||
run: |
|
||||
RUSTDOCFLAGS="-Dwarnings" cargo doc ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-deps --workspace --document-private-items
|
||||
- uses: DavidAnson/markdownlint-cli2-action@v10
|
||||
- uses: DavidAnson/markdownlint-cli2-action@v11
|
||||
with:
|
||||
command: fix
|
||||
globs: |
|
||||
|
@ -452,8 +452,20 @@ jobs:
|
|||
test -f /tmp/usr/local/share/man/man1/whoami.1
|
||||
# Check that the completion is present
|
||||
test -f /tmp/usr/local/share/zsh/site-functions/_install
|
||||
test -f /tmp/usr/local/share/bash-completion/completions/head
|
||||
test -f /tmp/usr/local/share/fish/vendor_completions.d/cat.fish
|
||||
env:
|
||||
RUST_BACKTRACE: "1"
|
||||
- name: "`make uninstall`"
|
||||
shell: bash
|
||||
run: |
|
||||
DESTDIR=/tmp/ make uninstall
|
||||
# Check that the manpage is not present
|
||||
! test -f /tmp/usr/local/share/man/man1/whoami.1
|
||||
# Check that the completion is not present
|
||||
! test -f /tmp/usr/local/share/zsh/site-functions/_install
|
||||
! test -f /tmp/usr/local/share/bash-completion/completions/head
|
||||
! test -f /tmp/usr/local/share/fish/vendor_completions.d/cat.fish
|
||||
|
||||
build_rust_stable:
|
||||
name: Build/stable
|
||||
|
@ -1048,6 +1060,15 @@ jobs:
|
|||
name: toybox-result.json
|
||||
path: ${{ steps.vars.outputs.TEST_SUMMARY_FILE }}
|
||||
|
||||
toml_format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check
|
||||
run: npx --yes @taplo/cli fmt --check
|
||||
|
||||
coverage:
|
||||
name: Code Coverage
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
|
|
74
.github/workflows/CheckScripts.yml
vendored
Normal file
74
.github/workflows/CheckScripts.yml
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
name: CheckScripts
|
||||
|
||||
# spell-checker:ignore ludeeus mfinelli
|
||||
|
||||
env:
|
||||
SCRIPT_DIR: 'util'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'util/**/*.sh'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'util/**/*.sh'
|
||||
|
||||
# End the current execution if there is a new changeset in the PR.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
jobs:
|
||||
shell_check:
|
||||
name: ShellScript/Check
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
env:
|
||||
SHELLCHECK_OPTS: -s bash
|
||||
with:
|
||||
severity: warning
|
||||
scandir: ${{ env.SCRIPT_DIR }}
|
||||
format: tty
|
||||
|
||||
shell_fmt:
|
||||
name: ShellScript/Format
|
||||
# no need to run in pr events
|
||||
# shfmt will be performed on main branch when the PR is merged
|
||||
if: github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ shell_check ]
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup shfmt
|
||||
uses: mfinelli/setup-shfmt@v2
|
||||
- name: Run shfmt
|
||||
shell: bash
|
||||
run: |
|
||||
# show differs first for every files that need to be formatted
|
||||
# fmt options: bash syntax, 4 spaces indent, indent for switch-case
|
||||
echo "## show the differences between formatted and original scripts..."
|
||||
find ${{ env.SCRIPT_DIR }} -name "*.sh" -print0 | xargs -0 shfmt -ln=bash -i 4 -ci -d || true
|
||||
# perform a shell format
|
||||
echo "## perform a shell format..."
|
||||
# ignore the error code because `-d` will always return false when the file has difference
|
||||
find ${{ env.SCRIPT_DIR }} -name "*.sh" -print0 | xargs -0 shfmt -ln=bash -i 4 -ci -w
|
||||
- name: Commit any changes
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
default_author: github_actions
|
||||
message: "style: auto format by CI (shfmt)"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
16
.github/workflows/FixPR.yml
vendored
16
.github/workflows/FixPR.yml
vendored
|
@ -31,12 +31,12 @@ jobs:
|
|||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
## VARs setup
|
||||
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
|
||||
# surface MSRV from CICD workflow
|
||||
RUST_MIN_SRV=$(grep -P "^\s+RUST_MIN_SRV:" .github/workflows/CICD.yml | grep -Po "(?<=\x22)\d+[.]\d+(?:[.]\d+)?(?=\x22)" )
|
||||
outputs RUST_MIN_SRV
|
||||
- uses: dtolnay/rust-toolchain@${{ steps.vars.outputs.RUST_MIN_SRV }}
|
||||
echo "RUST_MIN_SRV=${RUST_MIN_SRV}" >> $GITHUB_OUTPUT
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{ steps.vars.outputs.RUST_MIN_SRV }}
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Ensure updated 'Cargo.lock'
|
||||
shell: bash
|
||||
|
@ -67,7 +67,7 @@ jobs:
|
|||
- name: Commit any changes (to '${{ env.BRANCH_TARGET }}')
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
branch: ${{ env.BRANCH_TARGET }}
|
||||
new_branch: ${{ env.BRANCH_TARGET }}
|
||||
default_author: github_actions
|
||||
message: "maint ~ refresh 'Cargo.lock'"
|
||||
add: Cargo.lock
|
||||
|
@ -90,13 +90,11 @@ jobs:
|
|||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
## VARs setup
|
||||
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
|
||||
# target-specific options
|
||||
# * CARGO_FEATURES_OPTION
|
||||
CARGO_FEATURES_OPTION='' ;
|
||||
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
|
||||
outputs CARGO_FEATURES_OPTION
|
||||
echo "CARGO_FEATURES_OPTION=${CARGO_FEATURES_OPTION}" >> $GITHUB_OUTPUT
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: stable
|
||||
|
@ -114,7 +112,7 @@ jobs:
|
|||
- name: Commit any changes (to '${{ env.BRANCH_TARGET }}')
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
branch: ${{ env.BRANCH_TARGET }}
|
||||
new_branch: ${{ env.BRANCH_TARGET }}
|
||||
default_author: github_actions
|
||||
message: "maint ~ rustfmt (`cargo fmt`)"
|
||||
env:
|
||||
|
|
2
.github/workflows/GnuTests.yml
vendored
2
.github/workflows/GnuTests.yml
vendored
|
@ -205,7 +205,7 @@ jobs:
|
|||
path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}'
|
||||
# https://github.com/uutils/coreutils/issues/4294
|
||||
# https://github.com/uutils/coreutils/issues/4295
|
||||
IGNORE_INTERMITTENT='${path_UUTILS}/.github/workflows/ignore-intermittent.txt'
|
||||
IGNORE_INTERMITTENT="${path_UUTILS}/.github/workflows/ignore-intermittent.txt"
|
||||
|
||||
mkdir -p ${{ steps.vars.outputs.path_reference }}
|
||||
|
||||
|
|
4
.github/workflows/freebsd.yml
vendored
4
.github/workflows/freebsd.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
|||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
- name: Prepare, build and test
|
||||
uses: vmactions/freebsd-vm@v0.3.0
|
||||
uses: vmactions/freebsd-vm@v0.3.1
|
||||
with:
|
||||
usesh: true
|
||||
# We need jq to run show-utils.sh and bash to use inline shell string replacement
|
||||
|
@ -125,7 +125,7 @@ jobs:
|
|||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
- name: Prepare, build and test
|
||||
uses: vmactions/freebsd-vm@v0.3.0
|
||||
uses: vmactions/freebsd-vm@v0.3.1
|
||||
with:
|
||||
usesh: true
|
||||
# sync: sshfs
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,6 +5,7 @@ target/
|
|||
/busybox/
|
||||
/.vscode/
|
||||
/.vs/
|
||||
/public/
|
||||
*~
|
||||
.*.swp
|
||||
.*.swo
|
||||
|
|
1
.vscode/cSpell.json
vendored
1
.vscode/cSpell.json
vendored
|
@ -19,6 +19,7 @@
|
|||
// files to ignore (globs supported)
|
||||
"ignorePaths": [
|
||||
"Cargo.lock",
|
||||
"oranda.json",
|
||||
"target/**",
|
||||
"tests/**/fixtures/**",
|
||||
"src/uu/dd/test-resources/**",
|
||||
|
|
|
@ -356,6 +356,7 @@ The Coreutils have different implementations, with different levels of completio
|
|||
* [V lang](https://github.com/vlang/coreutils)
|
||||
* [SerenityOS](https://github.com/SerenityOS/serenity/tree/master/Userland/Utilities)
|
||||
* [Initial Unix](https://github.com/dspinellis/unix-history-repo)
|
||||
* [Perl Power Tools](https://metacpan.org/pod/PerlPowerTools)
|
||||
|
||||
However, when reimplementing the tools/options in Rust, don't read their source codes
|
||||
when they are using reciprocal licenses (ex: GNU GPL, GNU LGPL, etc).
|
||||
|
|
940
Cargo.lock
generated
940
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
676
Cargo.toml
676
Cargo.toml
|
@ -1,11 +1,11 @@
|
|||
# coreutils (uutils)
|
||||
# * see the repository LICENSE, README, and CONTRIBUTING files for more information
|
||||
|
||||
# spell-checker:ignore (libs) libselinux gethostid procfs bigdecimal kqueue fundu mangen humantime
|
||||
# spell-checker:ignore (libs) bigdecimal datetime fundu gethostid kqueue libselinux mangen memmap procfs uuhelp
|
||||
|
||||
[package]
|
||||
name = "coreutils"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust"
|
||||
|
@ -22,16 +22,16 @@ edition = "2021"
|
|||
build = "build.rs"
|
||||
|
||||
[features]
|
||||
default = [ "feat_common_core" ]
|
||||
default = ["feat_common_core"]
|
||||
## OS feature shortcodes
|
||||
macos = [ "feat_os_macos" ]
|
||||
unix = [ "feat_os_unix" ]
|
||||
windows = [ "feat_os_windows" ]
|
||||
macos = ["feat_os_macos"]
|
||||
unix = ["feat_os_unix"]
|
||||
windows = ["feat_os_windows"]
|
||||
## project-specific feature shortcodes
|
||||
nightly = []
|
||||
test_unimplemented = []
|
||||
# * only build `uudoc` when `--feature uudoc` is activated
|
||||
uudoc = ["zip", "dep:help_parser"]
|
||||
uudoc = ["zip", "dep:uuhelp_parser"]
|
||||
## features
|
||||
# "feat_acl" == enable support for ACLs (access control lists; by using`--features feat_acl`)
|
||||
# NOTE:
|
||||
|
@ -42,239 +42,237 @@ feat_acl = ["cp/feat_acl"]
|
|||
# NOTE:
|
||||
# * The selinux(-sys) crate requires `libselinux` headers and shared library to be accessible in the C toolchain at compile time.
|
||||
# * Running a uutils compiled with `feat_selinux` requires an SELinux enabled Kernel at run time.
|
||||
feat_selinux = ["cp/selinux", "id/selinux", "ls/selinux", "selinux", "feat_require_selinux"]
|
||||
feat_selinux = [
|
||||
"cp/selinux",
|
||||
"id/selinux",
|
||||
"ls/selinux",
|
||||
"selinux",
|
||||
"feat_require_selinux",
|
||||
]
|
||||
##
|
||||
## feature sets
|
||||
## (common/core and Tier1) feature sets
|
||||
# "feat_common_core" == baseline core set of utilities which can be built/run on most targets
|
||||
feat_common_core = [
|
||||
"base32",
|
||||
"base64",
|
||||
"basename",
|
||||
"basenc",
|
||||
"cat",
|
||||
"cksum",
|
||||
"comm",
|
||||
"cp",
|
||||
"csplit",
|
||||
"cut",
|
||||
"date",
|
||||
"df",
|
||||
"dir",
|
||||
"dircolors",
|
||||
"dirname",
|
||||
"dd",
|
||||
"du",
|
||||
"echo",
|
||||
"env",
|
||||
"expand",
|
||||
"expr",
|
||||
"factor",
|
||||
"false",
|
||||
"fmt",
|
||||
"fold",
|
||||
"hashsum",
|
||||
"head",
|
||||
"join",
|
||||
"link",
|
||||
"ln",
|
||||
"ls",
|
||||
"mkdir",
|
||||
"mktemp",
|
||||
"more",
|
||||
"mv",
|
||||
"nl",
|
||||
"numfmt",
|
||||
"od",
|
||||
"paste",
|
||||
"pr",
|
||||
"printenv",
|
||||
"printf",
|
||||
"ptx",
|
||||
"pwd",
|
||||
"readlink",
|
||||
"realpath",
|
||||
"relpath",
|
||||
"rm",
|
||||
"rmdir",
|
||||
"seq",
|
||||
"shred",
|
||||
"shuf",
|
||||
"sleep",
|
||||
"sort",
|
||||
"split",
|
||||
"sum",
|
||||
"tac",
|
||||
"tail",
|
||||
"tee",
|
||||
"test",
|
||||
"tr",
|
||||
"true",
|
||||
"truncate",
|
||||
"tsort",
|
||||
"touch",
|
||||
"unexpand",
|
||||
"uniq",
|
||||
"unlink",
|
||||
"vdir",
|
||||
"wc",
|
||||
"yes",
|
||||
"base32",
|
||||
"base64",
|
||||
"basename",
|
||||
"basenc",
|
||||
"cat",
|
||||
"cksum",
|
||||
"comm",
|
||||
"cp",
|
||||
"csplit",
|
||||
"cut",
|
||||
"date",
|
||||
"df",
|
||||
"dir",
|
||||
"dircolors",
|
||||
"dirname",
|
||||
"dd",
|
||||
"du",
|
||||
"echo",
|
||||
"env",
|
||||
"expand",
|
||||
"expr",
|
||||
"factor",
|
||||
"false",
|
||||
"fmt",
|
||||
"fold",
|
||||
"hashsum",
|
||||
"head",
|
||||
"join",
|
||||
"link",
|
||||
"ln",
|
||||
"ls",
|
||||
"mkdir",
|
||||
"mktemp",
|
||||
"more",
|
||||
"mv",
|
||||
"nl",
|
||||
"numfmt",
|
||||
"od",
|
||||
"paste",
|
||||
"pr",
|
||||
"printenv",
|
||||
"printf",
|
||||
"ptx",
|
||||
"pwd",
|
||||
"readlink",
|
||||
"realpath",
|
||||
"relpath",
|
||||
"rm",
|
||||
"rmdir",
|
||||
"seq",
|
||||
"shred",
|
||||
"shuf",
|
||||
"sleep",
|
||||
"sort",
|
||||
"split",
|
||||
"sum",
|
||||
"tac",
|
||||
"tail",
|
||||
"tee",
|
||||
"test",
|
||||
"tr",
|
||||
"true",
|
||||
"truncate",
|
||||
"tsort",
|
||||
"touch",
|
||||
"unexpand",
|
||||
"uniq",
|
||||
"unlink",
|
||||
"vdir",
|
||||
"wc",
|
||||
"yes",
|
||||
]
|
||||
# "feat_Tier1" == 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_Tier1 = [
|
||||
"feat_common_core",
|
||||
#
|
||||
"arch",
|
||||
"hostname",
|
||||
"nproc",
|
||||
"sync",
|
||||
"touch",
|
||||
"uname",
|
||||
"whoami",
|
||||
"feat_common_core",
|
||||
#
|
||||
"arch",
|
||||
"hostname",
|
||||
"nproc",
|
||||
"sync",
|
||||
"touch",
|
||||
"uname",
|
||||
"whoami",
|
||||
]
|
||||
## (primary platforms) feature sets
|
||||
# "feat_os_macos" == set of utilities which can be built/run on the MacOS platform
|
||||
feat_os_macos = [
|
||||
"feat_os_unix", ## == a modern/usual *nix platform
|
||||
#
|
||||
"feat_require_unix_hostid",
|
||||
"feat_os_unix", ## == a modern/usual *nix platform
|
||||
#
|
||||
"feat_require_unix_hostid",
|
||||
]
|
||||
# "feat_os_unix" == set of utilities which can be built/run on modern/usual *nix platforms
|
||||
feat_os_unix = [
|
||||
"feat_Tier1",
|
||||
#
|
||||
"feat_require_crate_cpp",
|
||||
"feat_require_unix",
|
||||
"feat_require_unix_utmpx",
|
||||
"feat_Tier1",
|
||||
#
|
||||
"feat_require_crate_cpp",
|
||||
"feat_require_unix",
|
||||
"feat_require_unix_utmpx",
|
||||
]
|
||||
# "feat_os_windows" == set of utilities which can be built/run on modern/usual windows platforms
|
||||
feat_os_windows = [
|
||||
"feat_Tier1", ## == "feat_os_windows_legacy" + "hostname"
|
||||
"feat_Tier1", ## == "feat_os_windows_legacy" + "hostname"
|
||||
]
|
||||
## (secondary platforms) feature sets
|
||||
# "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_Tier1",
|
||||
#
|
||||
"feat_require_unix",
|
||||
"feat_require_unix_hostid",
|
||||
"feat_require_unix_utmpx",
|
||||
"feat_Tier1",
|
||||
#
|
||||
"feat_require_unix",
|
||||
"feat_require_unix_hostid",
|
||||
"feat_require_unix_utmpx",
|
||||
]
|
||||
# "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_Tier1",
|
||||
#
|
||||
"feat_require_unix",
|
||||
"feat_require_unix_hostid",
|
||||
"feat_Tier1",
|
||||
#
|
||||
"feat_require_unix",
|
||||
"feat_require_unix_hostid",
|
||||
]
|
||||
feat_os_unix_android = [
|
||||
"feat_Tier1",
|
||||
#
|
||||
"feat_require_unix",
|
||||
"feat_Tier1",
|
||||
#
|
||||
"feat_require_unix",
|
||||
]
|
||||
## feature sets with requirements (restricting cross-platform availability)
|
||||
#
|
||||
# ** NOTE: these `feat_require_...` sets should be minimized as much as possible to encourage cross-platform availability of utilities
|
||||
#
|
||||
# "feat_require_crate_cpp" == set of utilities requiring the `cpp` crate (which fail to compile on several platforms; as of 2020-04-23)
|
||||
feat_require_crate_cpp = [
|
||||
"stdbuf",
|
||||
]
|
||||
feat_require_crate_cpp = ["stdbuf"]
|
||||
# "feat_require_unix" == set of utilities requiring support which is only available on unix platforms (as of 2020-04-23)
|
||||
feat_require_unix = [
|
||||
"chgrp",
|
||||
"chmod",
|
||||
"chown",
|
||||
"chroot",
|
||||
"groups",
|
||||
"id",
|
||||
"install",
|
||||
"kill",
|
||||
"logname",
|
||||
"mkfifo",
|
||||
"mknod",
|
||||
"nice",
|
||||
"nohup",
|
||||
"pathchk",
|
||||
"stat",
|
||||
"stty",
|
||||
"timeout",
|
||||
"tty",
|
||||
"chgrp",
|
||||
"chmod",
|
||||
"chown",
|
||||
"chroot",
|
||||
"groups",
|
||||
"id",
|
||||
"install",
|
||||
"kill",
|
||||
"logname",
|
||||
"mkfifo",
|
||||
"mknod",
|
||||
"nice",
|
||||
"nohup",
|
||||
"pathchk",
|
||||
"stat",
|
||||
"stty",
|
||||
"timeout",
|
||||
"tty",
|
||||
]
|
||||
# "feat_require_unix_utmpx" == set of utilities requiring unix utmp/utmpx support
|
||||
# * ref: <https://wiki.musl-libc.org/faq.html#Q:-Why-is-the-utmp/wtmp-functionality-only-implemented-as-stubs?>
|
||||
feat_require_unix_utmpx = [
|
||||
"pinky",
|
||||
"uptime",
|
||||
"users",
|
||||
"who",
|
||||
]
|
||||
feat_require_unix_utmpx = ["pinky", "uptime", "users", "who"]
|
||||
# "feat_require_unix_hostid" == set of utilities requiring gethostid in libc (only some unixes provide)
|
||||
feat_require_unix_hostid = [
|
||||
"hostid",
|
||||
]
|
||||
feat_require_unix_hostid = ["hostid"]
|
||||
# "feat_require_selinux" == set of utilities depending on SELinux.
|
||||
feat_require_selinux = [
|
||||
"chcon",
|
||||
"runcon",
|
||||
]
|
||||
feat_require_selinux = ["chcon", "runcon"]
|
||||
## (alternate/newer/smaller platforms) feature sets
|
||||
# "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuchsia" OS (refs: <https://fuchsia.dev>; <https://en.wikipedia.org/wiki/Google_Fuchsia>)
|
||||
feat_os_unix_fuchsia = [
|
||||
"feat_common_core",
|
||||
#
|
||||
"feat_require_crate_cpp",
|
||||
#
|
||||
"chgrp",
|
||||
"chmod",
|
||||
"chown",
|
||||
"du",
|
||||
"groups",
|
||||
"hostid",
|
||||
"install",
|
||||
"logname",
|
||||
"mkfifo",
|
||||
"mknod",
|
||||
"nice",
|
||||
"pathchk",
|
||||
"tty",
|
||||
"uname",
|
||||
"unlink",
|
||||
"feat_common_core",
|
||||
#
|
||||
"feat_require_crate_cpp",
|
||||
#
|
||||
"chgrp",
|
||||
"chmod",
|
||||
"chown",
|
||||
"du",
|
||||
"groups",
|
||||
"hostid",
|
||||
"install",
|
||||
"logname",
|
||||
"mkfifo",
|
||||
"mknod",
|
||||
"nice",
|
||||
"pathchk",
|
||||
"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",
|
||||
#
|
||||
"chmod",
|
||||
"uname",
|
||||
"feat_common_core",
|
||||
#
|
||||
"chmod",
|
||||
"uname",
|
||||
]
|
||||
# "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",
|
||||
"feat_common_core",
|
||||
#
|
||||
"arch",
|
||||
"nproc",
|
||||
"sync",
|
||||
"touch",
|
||||
"whoami",
|
||||
]
|
||||
##
|
||||
# * bypass/override ~ translate 'test' feature name to avoid dependency collision with rust core 'test' crate (o/w surfaces as compiler errors during testing)
|
||||
test = [ "uu_test" ]
|
||||
test = ["uu_test"]
|
||||
|
||||
[workspace.dependencies]
|
||||
bigdecimal = "0.3"
|
||||
bigdecimal = "0.4"
|
||||
binary-heap-plus = "0.5.0"
|
||||
bstr = "1.5"
|
||||
bstr = "1.6"
|
||||
bytecount = "0.6.3"
|
||||
byteorder = "1.4.3"
|
||||
chrono = { version="^0.4.26", default-features=false, features=["std", "alloc", "clock"]}
|
||||
chrono = { version = "^0.4.26", default-features = false, features = [
|
||||
"std",
|
||||
"alloc",
|
||||
"clock",
|
||||
] }
|
||||
clap = { version = "4.3", features = ["wrap_help", "cargo"] }
|
||||
clap_complete = "4.3"
|
||||
clap_mangen = "0.2"
|
||||
compare = "0.1.0"
|
||||
coz = { version = "0.1.3" }
|
||||
crossterm = ">=0.26.1"
|
||||
crossterm = ">=0.27.0"
|
||||
ctrlc = { version = "3.4", features = ["termination"] }
|
||||
exacl = "0.10.0"
|
||||
file_diff = "1.0.0"
|
||||
|
@ -282,189 +280,192 @@ filetime = "0.2"
|
|||
fnv = "1.0.7"
|
||||
fs_extra = "1.3.0"
|
||||
fts-sys = "0.2"
|
||||
fundu = "0.5.1"
|
||||
fundu = "2.0.0"
|
||||
gcd = "2.3"
|
||||
glob = "0.3.1"
|
||||
half = "2.2"
|
||||
humantime_to_duration = "0.2.1"
|
||||
indicatif = "0.17"
|
||||
is-terminal = "0.4.7"
|
||||
itertools = "0.10.5"
|
||||
libc = "0.2.144"
|
||||
lscolors = { version = "0.14.0", default-features=false, features = ["nu-ansi-term"] }
|
||||
itertools = "0.11.0"
|
||||
libc = "0.2.147"
|
||||
lscolors = { version = "0.15.0", default-features = false, features = [
|
||||
"nu-ansi-term",
|
||||
] }
|
||||
memchr = "2"
|
||||
nix = { version="0.26", default-features=false }
|
||||
memmap2 = "0.7"
|
||||
nix = { version = "0.26", default-features = false }
|
||||
nom = "7.1.3"
|
||||
notify = { version = "=6.0.0", features=["macos_kqueue"]}
|
||||
notify = { version = "=6.0.1", features = ["macos_kqueue"] }
|
||||
num-bigint = "0.4.3"
|
||||
num-traits = "0.2.15"
|
||||
num-traits = "0.2.16"
|
||||
number_prefix = "0.4"
|
||||
once_cell = "1.17.2"
|
||||
once_cell = "1.18.0"
|
||||
onig = { version = "~6.4", default-features = false }
|
||||
ouroboros = "0.15.6"
|
||||
phf = "0.11.1"
|
||||
phf_codegen = "0.11.1"
|
||||
platform-info = "2.0.1"
|
||||
parse_datetime = "0.4.0"
|
||||
phf = "0.11.2"
|
||||
phf_codegen = "0.11.2"
|
||||
platform-info = "2.0.2"
|
||||
quick-error = "2.0.1"
|
||||
rand = { version = "0.8", features = ["small_rng"] }
|
||||
rand_core = "0.6"
|
||||
rayon = "1.7"
|
||||
redox_syscall = "0.3"
|
||||
regex = "1.8.3"
|
||||
rstest = "0.17.0"
|
||||
rust-ini = "0.18.0"
|
||||
regex = "1.9.3"
|
||||
rstest = "0.18.1"
|
||||
rust-ini = "0.19.0"
|
||||
same-file = "1.0.6"
|
||||
self_cell = "1.0.1"
|
||||
selinux = "0.4"
|
||||
signal-hook = "0.3.15"
|
||||
smallvec = { version = "1.10", features = ["union"] }
|
||||
tempfile = "3.5.0"
|
||||
signal-hook = "0.3.17"
|
||||
smallvec = { version = "1.11", features = ["union"] }
|
||||
tempfile = "3.6.0"
|
||||
term_grid = "0.1.5"
|
||||
terminal_size = "0.2.6"
|
||||
textwrap = { version="0.16.0", features=["terminal_size"] }
|
||||
textwrap = { version = "0.16.0", features = ["terminal_size"] }
|
||||
thiserror = "1.0"
|
||||
time = { version="0.3" }
|
||||
time = { version = "0.3" }
|
||||
unicode-segmentation = "1.10.1"
|
||||
unicode-width = "0.1.10"
|
||||
utf-8 = "0.7.6"
|
||||
walkdir = "2.3"
|
||||
winapi-util = "0.1.5"
|
||||
windows-sys = { version="0.48.0", default-features=false }
|
||||
xattr = "1.0.0"
|
||||
zip = { version = "0.6.6", default_features=false, features=["deflate"] }
|
||||
windows-sys = { version = "0.48.0", default-features = false }
|
||||
xattr = "1.0.1"
|
||||
zip = { version = "0.6.6", default_features = false, features = ["deflate"] }
|
||||
|
||||
hex = "0.4.3"
|
||||
md-5 = "0.10.5"
|
||||
sha1 = "0.10.5"
|
||||
sha2 = "0.10.6"
|
||||
sha2 = "0.10.7"
|
||||
sha3 = "0.10.8"
|
||||
blake2b_simd = "1.0.1"
|
||||
blake3 = "1.3.3"
|
||||
blake3 = "1.4.0"
|
||||
sm3 = "0.4.2"
|
||||
digest = "0.10.7"
|
||||
|
||||
uucore = { version=">=0.0.18", package="uucore", path="src/uucore" }
|
||||
uucore_procs = { version=">=0.0.18", package="uucore_procs", path="src/uucore_procs" }
|
||||
uu_ls = { version=">=0.0.18", path="src/uu/ls" }
|
||||
uu_base32 = { version=">=0.0.18", path="src/uu/base32"}
|
||||
uucore = { version = ">=0.0.19", package = "uucore", path = "src/uucore" }
|
||||
uucore_procs = { version = ">=0.0.19", package = "uucore_procs", path = "src/uucore_procs" }
|
||||
uu_ls = { version = ">=0.0.18", path = "src/uu/ls" }
|
||||
uu_base32 = { version = ">=0.0.18", path = "src/uu/base32" }
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
once_cell = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap_complete = { workspace=true }
|
||||
clap_mangen = { workspace=true }
|
||||
phf = { workspace=true }
|
||||
selinux = { workspace=true, optional = true }
|
||||
textwrap = { workspace=true }
|
||||
zip = { workspace=true, optional = true }
|
||||
clap = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
clap_complete = { workspace = true }
|
||||
clap_mangen = { workspace = true }
|
||||
phf = { workspace = true }
|
||||
selinux = { workspace = true, optional = true }
|
||||
textwrap = { workspace = true }
|
||||
zip = { workspace = true, optional = true }
|
||||
|
||||
help_parser = { path="src/help_parser", optional = true }
|
||||
uuhelp_parser = { optional = true, version = ">=0.0.19", path = "src/uuhelp_parser" }
|
||||
|
||||
# * uutils
|
||||
uu_test = { optional=true, version="0.0.18", package="uu_test", path="src/uu/test" }
|
||||
uu_test = { optional = true, version = "0.0.20", package = "uu_test", path = "src/uu/test" }
|
||||
#
|
||||
arch = { optional=true, version="0.0.18", package="uu_arch", path="src/uu/arch" }
|
||||
base32 = { optional=true, version="0.0.18", package="uu_base32", path="src/uu/base32" }
|
||||
base64 = { optional=true, version="0.0.18", package="uu_base64", path="src/uu/base64" }
|
||||
basename = { optional=true, version="0.0.18", package="uu_basename", path="src/uu/basename" }
|
||||
basenc = { optional=true, version="0.0.18", package="uu_basenc", path="src/uu/basenc" }
|
||||
cat = { optional=true, version="0.0.18", package="uu_cat", path="src/uu/cat" }
|
||||
chcon = { optional=true, version="0.0.18", package="uu_chcon", path="src/uu/chcon" }
|
||||
chgrp = { optional=true, version="0.0.18", package="uu_chgrp", path="src/uu/chgrp" }
|
||||
chmod = { optional=true, version="0.0.18", package="uu_chmod", path="src/uu/chmod" }
|
||||
chown = { optional=true, version="0.0.18", package="uu_chown", path="src/uu/chown" }
|
||||
chroot = { optional=true, version="0.0.18", package="uu_chroot", path="src/uu/chroot" }
|
||||
cksum = { optional=true, version="0.0.18", package="uu_cksum", path="src/uu/cksum" }
|
||||
comm = { optional=true, version="0.0.18", package="uu_comm", path="src/uu/comm" }
|
||||
cp = { optional=true, version="0.0.18", package="uu_cp", path="src/uu/cp" }
|
||||
csplit = { optional=true, version="0.0.18", package="uu_csplit", path="src/uu/csplit" }
|
||||
cut = { optional=true, version="0.0.18", package="uu_cut", path="src/uu/cut" }
|
||||
date = { optional=true, version="0.0.18", package="uu_date", path="src/uu/date" }
|
||||
dd = { optional=true, version="0.0.18", package="uu_dd", path="src/uu/dd" }
|
||||
df = { optional=true, version="0.0.18", package="uu_df", path="src/uu/df" }
|
||||
dir = { optional=true, version="0.0.18", package="uu_dir", path="src/uu/dir" }
|
||||
dircolors= { optional=true, version="0.0.18", package="uu_dircolors", path="src/uu/dircolors" }
|
||||
dirname = { optional=true, version="0.0.18", package="uu_dirname", path="src/uu/dirname" }
|
||||
du = { optional=true, version="0.0.18", package="uu_du", path="src/uu/du" }
|
||||
echo = { optional=true, version="0.0.18", package="uu_echo", path="src/uu/echo" }
|
||||
env = { optional=true, version="0.0.18", package="uu_env", path="src/uu/env" }
|
||||
expand = { optional=true, version="0.0.18", package="uu_expand", path="src/uu/expand" }
|
||||
expr = { optional=true, version="0.0.18", package="uu_expr", path="src/uu/expr" }
|
||||
factor = { optional=true, version="0.0.18", package="uu_factor", path="src/uu/factor" }
|
||||
false = { optional=true, version="0.0.18", package="uu_false", path="src/uu/false" }
|
||||
fmt = { optional=true, version="0.0.18", package="uu_fmt", path="src/uu/fmt" }
|
||||
fold = { optional=true, version="0.0.18", package="uu_fold", path="src/uu/fold" }
|
||||
groups = { optional=true, version="0.0.18", package="uu_groups", path="src/uu/groups" }
|
||||
hashsum = { optional=true, version="0.0.18", package="uu_hashsum", path="src/uu/hashsum" }
|
||||
head = { optional=true, version="0.0.18", package="uu_head", path="src/uu/head" }
|
||||
hostid = { optional=true, version="0.0.18", package="uu_hostid", path="src/uu/hostid" }
|
||||
hostname = { optional=true, version="0.0.18", package="uu_hostname", path="src/uu/hostname" }
|
||||
id = { optional=true, version="0.0.18", package="uu_id", path="src/uu/id" }
|
||||
install = { optional=true, version="0.0.18", package="uu_install", path="src/uu/install" }
|
||||
join = { optional=true, version="0.0.18", package="uu_join", path="src/uu/join" }
|
||||
kill = { optional=true, version="0.0.18", package="uu_kill", path="src/uu/kill" }
|
||||
link = { optional=true, version="0.0.18", package="uu_link", path="src/uu/link" }
|
||||
ln = { optional=true, version="0.0.18", package="uu_ln", path="src/uu/ln" }
|
||||
ls = { optional=true, version="0.0.18", package="uu_ls", path="src/uu/ls" }
|
||||
logname = { optional=true, version="0.0.18", package="uu_logname", path="src/uu/logname" }
|
||||
mkdir = { optional=true, version="0.0.18", package="uu_mkdir", path="src/uu/mkdir" }
|
||||
mkfifo = { optional=true, version="0.0.18", package="uu_mkfifo", path="src/uu/mkfifo" }
|
||||
mknod = { optional=true, version="0.0.18", package="uu_mknod", path="src/uu/mknod" }
|
||||
mktemp = { optional=true, version="0.0.18", package="uu_mktemp", path="src/uu/mktemp" }
|
||||
more = { optional=true, version="0.0.18", package="uu_more", path="src/uu/more" }
|
||||
mv = { optional=true, version="0.0.18", package="uu_mv", path="src/uu/mv" }
|
||||
nice = { optional=true, version="0.0.18", package="uu_nice", path="src/uu/nice" }
|
||||
nl = { optional=true, version="0.0.18", package="uu_nl", path="src/uu/nl" }
|
||||
nohup = { optional=true, version="0.0.18", package="uu_nohup", path="src/uu/nohup" }
|
||||
nproc = { optional=true, version="0.0.18", package="uu_nproc", path="src/uu/nproc" }
|
||||
numfmt = { optional=true, version="0.0.18", package="uu_numfmt", path="src/uu/numfmt" }
|
||||
od = { optional=true, version="0.0.18", package="uu_od", path="src/uu/od" }
|
||||
paste = { optional=true, version="0.0.18", package="uu_paste", path="src/uu/paste" }
|
||||
pathchk = { optional=true, version="0.0.18", package="uu_pathchk", path="src/uu/pathchk" }
|
||||
pinky = { optional=true, version="0.0.18", package="uu_pinky", path="src/uu/pinky" }
|
||||
pr = { optional=true, version="0.0.18", package="uu_pr", path="src/uu/pr" }
|
||||
printenv = { optional=true, version="0.0.18", package="uu_printenv", path="src/uu/printenv" }
|
||||
printf = { optional=true, version="0.0.18", package="uu_printf", path="src/uu/printf" }
|
||||
ptx = { optional=true, version="0.0.18", package="uu_ptx", path="src/uu/ptx" }
|
||||
pwd = { optional=true, version="0.0.18", package="uu_pwd", path="src/uu/pwd" }
|
||||
readlink = { optional=true, version="0.0.18", package="uu_readlink", path="src/uu/readlink" }
|
||||
realpath = { optional=true, version="0.0.18", package="uu_realpath", path="src/uu/realpath" }
|
||||
relpath = { optional=true, version="0.0.18", package="uu_relpath", path="src/uu/relpath" }
|
||||
rm = { optional=true, version="0.0.18", package="uu_rm", path="src/uu/rm" }
|
||||
rmdir = { optional=true, version="0.0.18", package="uu_rmdir", path="src/uu/rmdir" }
|
||||
runcon = { optional=true, version="0.0.18", package="uu_runcon", path="src/uu/runcon" }
|
||||
seq = { optional=true, version="0.0.18", package="uu_seq", path="src/uu/seq" }
|
||||
shred = { optional=true, version="0.0.18", package="uu_shred", path="src/uu/shred" }
|
||||
shuf = { optional=true, version="0.0.18", package="uu_shuf", path="src/uu/shuf" }
|
||||
sleep = { optional=true, version="0.0.18", package="uu_sleep", path="src/uu/sleep" }
|
||||
sort = { optional=true, version="0.0.18", package="uu_sort", path="src/uu/sort" }
|
||||
split = { optional=true, version="0.0.18", package="uu_split", path="src/uu/split" }
|
||||
stat = { optional=true, version="0.0.18", package="uu_stat", path="src/uu/stat" }
|
||||
stdbuf = { optional=true, version="0.0.18", package="uu_stdbuf", path="src/uu/stdbuf" }
|
||||
stty = { optional=true, version="0.0.18", package="uu_stty", path="src/uu/stty" }
|
||||
sum = { optional=true, version="0.0.18", package="uu_sum", path="src/uu/sum" }
|
||||
sync = { optional=true, version="0.0.18", package="uu_sync", path="src/uu/sync" }
|
||||
tac = { optional=true, version="0.0.18", package="uu_tac", path="src/uu/tac" }
|
||||
tail = { optional=true, version="0.0.18", package="uu_tail", path="src/uu/tail" }
|
||||
tee = { optional=true, version="0.0.18", package="uu_tee", path="src/uu/tee" }
|
||||
timeout = { optional=true, version="0.0.18", package="uu_timeout", path="src/uu/timeout" }
|
||||
touch = { optional=true, version="0.0.18", package="uu_touch", path="src/uu/touch" }
|
||||
tr = { optional=true, version="0.0.18", package="uu_tr", path="src/uu/tr" }
|
||||
true = { optional=true, version="0.0.18", package="uu_true", path="src/uu/true" }
|
||||
truncate = { optional=true, version="0.0.18", package="uu_truncate", path="src/uu/truncate" }
|
||||
tsort = { optional=true, version="0.0.18", package="uu_tsort", path="src/uu/tsort" }
|
||||
tty = { optional=true, version="0.0.18", package="uu_tty", path="src/uu/tty" }
|
||||
uname = { optional=true, version="0.0.18", package="uu_uname", path="src/uu/uname" }
|
||||
unexpand = { optional=true, version="0.0.18", package="uu_unexpand", path="src/uu/unexpand" }
|
||||
uniq = { optional=true, version="0.0.18", package="uu_uniq", path="src/uu/uniq" }
|
||||
unlink = { optional=true, version="0.0.18", package="uu_unlink", path="src/uu/unlink" }
|
||||
uptime = { optional=true, version="0.0.18", package="uu_uptime", path="src/uu/uptime" }
|
||||
users = { optional=true, version="0.0.18", package="uu_users", path="src/uu/users" }
|
||||
vdir = { optional=true, version="0.0.18", package="uu_vdir", path="src/uu/vdir" }
|
||||
wc = { optional=true, version="0.0.18", package="uu_wc", path="src/uu/wc" }
|
||||
who = { optional=true, version="0.0.18", package="uu_who", path="src/uu/who" }
|
||||
whoami = { optional=true, version="0.0.18", package="uu_whoami", path="src/uu/whoami" }
|
||||
yes = { optional=true, version="0.0.18", package="uu_yes", path="src/uu/yes" }
|
||||
arch = { optional = true, version = "0.0.20", package = "uu_arch", path = "src/uu/arch" }
|
||||
base32 = { optional = true, version = "0.0.20", package = "uu_base32", path = "src/uu/base32" }
|
||||
base64 = { optional = true, version = "0.0.20", package = "uu_base64", path = "src/uu/base64" }
|
||||
basename = { optional = true, version = "0.0.20", package = "uu_basename", path = "src/uu/basename" }
|
||||
basenc = { optional = true, version = "0.0.20", package = "uu_basenc", path = "src/uu/basenc" }
|
||||
cat = { optional = true, version = "0.0.20", package = "uu_cat", path = "src/uu/cat" }
|
||||
chcon = { optional = true, version = "0.0.20", package = "uu_chcon", path = "src/uu/chcon" }
|
||||
chgrp = { optional = true, version = "0.0.20", package = "uu_chgrp", path = "src/uu/chgrp" }
|
||||
chmod = { optional = true, version = "0.0.20", package = "uu_chmod", path = "src/uu/chmod" }
|
||||
chown = { optional = true, version = "0.0.20", package = "uu_chown", path = "src/uu/chown" }
|
||||
chroot = { optional = true, version = "0.0.20", package = "uu_chroot", path = "src/uu/chroot" }
|
||||
cksum = { optional = true, version = "0.0.20", package = "uu_cksum", path = "src/uu/cksum" }
|
||||
comm = { optional = true, version = "0.0.20", package = "uu_comm", path = "src/uu/comm" }
|
||||
cp = { optional = true, version = "0.0.20", package = "uu_cp", path = "src/uu/cp" }
|
||||
csplit = { optional = true, version = "0.0.20", package = "uu_csplit", path = "src/uu/csplit" }
|
||||
cut = { optional = true, version = "0.0.20", package = "uu_cut", path = "src/uu/cut" }
|
||||
date = { optional = true, version = "0.0.20", package = "uu_date", path = "src/uu/date" }
|
||||
dd = { optional = true, version = "0.0.20", package = "uu_dd", path = "src/uu/dd" }
|
||||
df = { optional = true, version = "0.0.20", package = "uu_df", path = "src/uu/df" }
|
||||
dir = { optional = true, version = "0.0.20", package = "uu_dir", path = "src/uu/dir" }
|
||||
dircolors = { optional = true, version = "0.0.20", package = "uu_dircolors", path = "src/uu/dircolors" }
|
||||
dirname = { optional = true, version = "0.0.20", package = "uu_dirname", path = "src/uu/dirname" }
|
||||
du = { optional = true, version = "0.0.20", package = "uu_du", path = "src/uu/du" }
|
||||
echo = { optional = true, version = "0.0.20", package = "uu_echo", path = "src/uu/echo" }
|
||||
env = { optional = true, version = "0.0.20", package = "uu_env", path = "src/uu/env" }
|
||||
expand = { optional = true, version = "0.0.20", package = "uu_expand", path = "src/uu/expand" }
|
||||
expr = { optional = true, version = "0.0.20", package = "uu_expr", path = "src/uu/expr" }
|
||||
factor = { optional = true, version = "0.0.20", package = "uu_factor", path = "src/uu/factor" }
|
||||
false = { optional = true, version = "0.0.20", package = "uu_false", path = "src/uu/false" }
|
||||
fmt = { optional = true, version = "0.0.20", package = "uu_fmt", path = "src/uu/fmt" }
|
||||
fold = { optional = true, version = "0.0.20", package = "uu_fold", path = "src/uu/fold" }
|
||||
groups = { optional = true, version = "0.0.20", package = "uu_groups", path = "src/uu/groups" }
|
||||
hashsum = { optional = true, version = "0.0.20", package = "uu_hashsum", path = "src/uu/hashsum" }
|
||||
head = { optional = true, version = "0.0.20", package = "uu_head", path = "src/uu/head" }
|
||||
hostid = { optional = true, version = "0.0.20", package = "uu_hostid", path = "src/uu/hostid" }
|
||||
hostname = { optional = true, version = "0.0.20", package = "uu_hostname", path = "src/uu/hostname" }
|
||||
id = { optional = true, version = "0.0.20", package = "uu_id", path = "src/uu/id" }
|
||||
install = { optional = true, version = "0.0.20", package = "uu_install", path = "src/uu/install" }
|
||||
join = { optional = true, version = "0.0.20", package = "uu_join", path = "src/uu/join" }
|
||||
kill = { optional = true, version = "0.0.20", package = "uu_kill", path = "src/uu/kill" }
|
||||
link = { optional = true, version = "0.0.20", package = "uu_link", path = "src/uu/link" }
|
||||
ln = { optional = true, version = "0.0.20", package = "uu_ln", path = "src/uu/ln" }
|
||||
ls = { optional = true, version = "0.0.20", package = "uu_ls", path = "src/uu/ls" }
|
||||
logname = { optional = true, version = "0.0.20", package = "uu_logname", path = "src/uu/logname" }
|
||||
mkdir = { optional = true, version = "0.0.20", package = "uu_mkdir", path = "src/uu/mkdir" }
|
||||
mkfifo = { optional = true, version = "0.0.20", package = "uu_mkfifo", path = "src/uu/mkfifo" }
|
||||
mknod = { optional = true, version = "0.0.20", package = "uu_mknod", path = "src/uu/mknod" }
|
||||
mktemp = { optional = true, version = "0.0.20", package = "uu_mktemp", path = "src/uu/mktemp" }
|
||||
more = { optional = true, version = "0.0.20", package = "uu_more", path = "src/uu/more" }
|
||||
mv = { optional = true, version = "0.0.20", package = "uu_mv", path = "src/uu/mv" }
|
||||
nice = { optional = true, version = "0.0.20", package = "uu_nice", path = "src/uu/nice" }
|
||||
nl = { optional = true, version = "0.0.20", package = "uu_nl", path = "src/uu/nl" }
|
||||
nohup = { optional = true, version = "0.0.20", package = "uu_nohup", path = "src/uu/nohup" }
|
||||
nproc = { optional = true, version = "0.0.20", package = "uu_nproc", path = "src/uu/nproc" }
|
||||
numfmt = { optional = true, version = "0.0.20", package = "uu_numfmt", path = "src/uu/numfmt" }
|
||||
od = { optional = true, version = "0.0.20", package = "uu_od", path = "src/uu/od" }
|
||||
paste = { optional = true, version = "0.0.20", package = "uu_paste", path = "src/uu/paste" }
|
||||
pathchk = { optional = true, version = "0.0.20", package = "uu_pathchk", path = "src/uu/pathchk" }
|
||||
pinky = { optional = true, version = "0.0.20", package = "uu_pinky", path = "src/uu/pinky" }
|
||||
pr = { optional = true, version = "0.0.20", package = "uu_pr", path = "src/uu/pr" }
|
||||
printenv = { optional = true, version = "0.0.20", package = "uu_printenv", path = "src/uu/printenv" }
|
||||
printf = { optional = true, version = "0.0.20", package = "uu_printf", path = "src/uu/printf" }
|
||||
ptx = { optional = true, version = "0.0.20", package = "uu_ptx", path = "src/uu/ptx" }
|
||||
pwd = { optional = true, version = "0.0.20", package = "uu_pwd", path = "src/uu/pwd" }
|
||||
readlink = { optional = true, version = "0.0.20", package = "uu_readlink", path = "src/uu/readlink" }
|
||||
realpath = { optional = true, version = "0.0.20", package = "uu_realpath", path = "src/uu/realpath" }
|
||||
relpath = { optional = true, version = "0.0.20", package = "uu_relpath", path = "src/uu/relpath" }
|
||||
rm = { optional = true, version = "0.0.20", package = "uu_rm", path = "src/uu/rm" }
|
||||
rmdir = { optional = true, version = "0.0.20", package = "uu_rmdir", path = "src/uu/rmdir" }
|
||||
runcon = { optional = true, version = "0.0.20", package = "uu_runcon", path = "src/uu/runcon" }
|
||||
seq = { optional = true, version = "0.0.20", package = "uu_seq", path = "src/uu/seq" }
|
||||
shred = { optional = true, version = "0.0.20", package = "uu_shred", path = "src/uu/shred" }
|
||||
shuf = { optional = true, version = "0.0.20", package = "uu_shuf", path = "src/uu/shuf" }
|
||||
sleep = { optional = true, version = "0.0.20", package = "uu_sleep", path = "src/uu/sleep" }
|
||||
sort = { optional = true, version = "0.0.20", package = "uu_sort", path = "src/uu/sort" }
|
||||
split = { optional = true, version = "0.0.20", package = "uu_split", path = "src/uu/split" }
|
||||
stat = { optional = true, version = "0.0.20", package = "uu_stat", path = "src/uu/stat" }
|
||||
stdbuf = { optional = true, version = "0.0.20", package = "uu_stdbuf", path = "src/uu/stdbuf" }
|
||||
stty = { optional = true, version = "0.0.20", package = "uu_stty", path = "src/uu/stty" }
|
||||
sum = { optional = true, version = "0.0.20", package = "uu_sum", path = "src/uu/sum" }
|
||||
sync = { optional = true, version = "0.0.20", package = "uu_sync", path = "src/uu/sync" }
|
||||
tac = { optional = true, version = "0.0.20", package = "uu_tac", path = "src/uu/tac" }
|
||||
tail = { optional = true, version = "0.0.20", package = "uu_tail", path = "src/uu/tail" }
|
||||
tee = { optional = true, version = "0.0.20", package = "uu_tee", path = "src/uu/tee" }
|
||||
timeout = { optional = true, version = "0.0.20", package = "uu_timeout", path = "src/uu/timeout" }
|
||||
touch = { optional = true, version = "0.0.20", package = "uu_touch", path = "src/uu/touch" }
|
||||
tr = { optional = true, version = "0.0.20", package = "uu_tr", path = "src/uu/tr" }
|
||||
true = { optional = true, version = "0.0.20", package = "uu_true", path = "src/uu/true" }
|
||||
truncate = { optional = true, version = "0.0.20", package = "uu_truncate", path = "src/uu/truncate" }
|
||||
tsort = { optional = true, version = "0.0.20", package = "uu_tsort", path = "src/uu/tsort" }
|
||||
tty = { optional = true, version = "0.0.20", package = "uu_tty", path = "src/uu/tty" }
|
||||
uname = { optional = true, version = "0.0.20", package = "uu_uname", path = "src/uu/uname" }
|
||||
unexpand = { optional = true, version = "0.0.20", package = "uu_unexpand", path = "src/uu/unexpand" }
|
||||
uniq = { optional = true, version = "0.0.20", package = "uu_uniq", path = "src/uu/uniq" }
|
||||
unlink = { optional = true, version = "0.0.20", package = "uu_unlink", path = "src/uu/unlink" }
|
||||
uptime = { optional = true, version = "0.0.20", package = "uu_uptime", path = "src/uu/uptime" }
|
||||
users = { optional = true, version = "0.0.20", package = "uu_users", path = "src/uu/users" }
|
||||
vdir = { optional = true, version = "0.0.20", package = "uu_vdir", path = "src/uu/vdir" }
|
||||
wc = { optional = true, version = "0.0.20", package = "uu_wc", path = "src/uu/wc" }
|
||||
who = { optional = true, version = "0.0.20", package = "uu_who", path = "src/uu/who" }
|
||||
whoami = { optional = true, version = "0.0.20", package = "uu_whoami", path = "src/uu/whoami" }
|
||||
yes = { optional = true, version = "0.0.20", package = "uu_yes", path = "src/uu/yes" }
|
||||
|
||||
# this breaks clippy linting with: "tests/by-util/test_factor_benches.rs: No such file or directory (os error 2)"
|
||||
# factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" }
|
||||
|
@ -475,35 +476,34 @@ yes = { optional=true, version="0.0.18", package="uu_yes", path="src/uu/yes
|
|||
#pin_cc = { version="1.0.61, < 1.0.62", package="cc" } ## cc v1.0.62 has compiler errors for MinRustV v1.32.0, requires 1.34 (for `std::str::split_ascii_whitespace()`)
|
||||
|
||||
[dev-dependencies]
|
||||
chrono = { workspace=true }
|
||||
chrono = { workspace = true }
|
||||
conv = "0.3"
|
||||
filetime = { workspace=true }
|
||||
glob = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
filetime = { workspace = true }
|
||||
glob = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
pretty_assertions = "1"
|
||||
rand = { workspace=true }
|
||||
regex = { workspace=true }
|
||||
sha1 = { version="0.10", features=["std"] }
|
||||
tempfile = { workspace=true }
|
||||
time = { workspace=true, features=["local-offset"] }
|
||||
rand = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
sha1 = { version = "0.10", features = ["std"] }
|
||||
tempfile = { workspace = true }
|
||||
time = { workspace = true, features = ["local-offset"] }
|
||||
unindent = "0.2"
|
||||
uucore = { workspace=true, features=["entries", "process", "signals"] }
|
||||
walkdir = { workspace=true }
|
||||
is-terminal = { workspace=true }
|
||||
uucore = { workspace = true, features = ["entries", "process", "signals"] }
|
||||
walkdir = { workspace = true }
|
||||
is-terminal = { workspace = true }
|
||||
hex-literal = "0.4.1"
|
||||
rstest = "0.17.0"
|
||||
rstest = { workspace = true }
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies]
|
||||
procfs = { version = "0.15", default-features = false }
|
||||
rlimit = "0.9.1"
|
||||
rlimit = "0.10.1"
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
nix = { workspace=true, features=["process", "signal", "user"] }
|
||||
rust-users = { version="0.11", package="users" }
|
||||
nix = { workspace = true, features = ["process", "signal", "user"] }
|
||||
rand_pcg = "0.3"
|
||||
|
||||
[build-dependencies]
|
||||
phf_codegen = { workspace=true }
|
||||
phf_codegen = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "coreutils"
|
||||
|
|
32
GNUmakefile
32
GNUmakefile
|
@ -1,4 +1,4 @@
|
|||
# spell-checker:ignore (misc) testsuite runtest findstring (targets) busytest toybox distclean pkgs nextest ; (vars/env) BINDIR BUILDDIR CARGOFLAGS DESTDIR DOCSDIR INSTALLDIR INSTALLEES MULTICALL DATAROOTDIR TESTDIR
|
||||
# spell-checker:ignore (misc) testsuite runtest findstring (targets) busytest toybox distclean pkgs nextest ; (vars/env) BINDIR BUILDDIR CARGOFLAGS DESTDIR DOCSDIR INSTALLDIR INSTALLEES MULTICALL DATAROOTDIR TESTDIR manpages
|
||||
|
||||
# Config options
|
||||
PROFILE ?= debug
|
||||
|
@ -337,7 +337,21 @@ clean:
|
|||
distclean: clean
|
||||
$(CARGO) clean $(CARGOFLAGS) && $(CARGO) update $(CARGOFLAGS)
|
||||
|
||||
install: build
|
||||
manpages: build-coreutils
|
||||
mkdir -p $(BUILDDIR)/man/
|
||||
$(foreach prog, $(INSTALLEES), \
|
||||
$(BUILDDIR)/coreutils manpage $(prog) > $(BUILDDIR)/man/$(PROG_PREFIX)$(prog).1; \
|
||||
)
|
||||
|
||||
completions: build-coreutils
|
||||
mkdir -p $(BUILDDIR)/completions/zsh $(BUILDDIR)/completions/bash $(BUILDDIR)/completions/fish
|
||||
$(foreach prog, $(INSTALLEES), \
|
||||
$(BUILDDIR)/coreutils completion $(prog) zsh > $(BUILDDIR)/completions/zsh/_$(PROG_PREFIX)$(prog); \
|
||||
$(BUILDDIR)/coreutils completion $(prog) bash > $(BUILDDIR)/completions/bash/$(PROG_PREFIX)$(prog); \
|
||||
$(BUILDDIR)/coreutils completion $(prog) fish > $(BUILDDIR)/completions/fish/$(PROG_PREFIX)$(prog).fish; \
|
||||
)
|
||||
|
||||
install: build manpages completions
|
||||
mkdir -p $(INSTALLDIR_BIN)
|
||||
ifeq (${MULTICALL}, y)
|
||||
$(INSTALL) $(BUILDDIR)/coreutils $(INSTALLDIR_BIN)/$(PROG_PREFIX)coreutils
|
||||
|
@ -349,15 +363,18 @@ else
|
|||
$(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog);)
|
||||
$(if $(findstring test,$(INSTALLEES)), $(INSTALL) $(BUILDDIR)/test $(INSTALLDIR_BIN)/$(PROG_PREFIX)[)
|
||||
endif
|
||||
mkdir -p $(DESTDIR)$(DATAROOTDIR)/man/man1
|
||||
$(foreach prog, $(INSTALLEES), \
|
||||
$(INSTALL) $(BUILDDIR)/man/$(PROG_PREFIX)$(prog).1 $(DESTDIR)$(DATAROOTDIR)/man/man1/; \
|
||||
)
|
||||
|
||||
mkdir -p $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions
|
||||
mkdir -p $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions
|
||||
mkdir -p $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d
|
||||
mkdir -p $(DESTDIR)$(DATAROOTDIR)/man/man1
|
||||
$(foreach prog, $(INSTALLEES), \
|
||||
$(BUILDDIR)/coreutils completion $(prog) zsh > $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions/_$(PROG_PREFIX)$(prog); \
|
||||
$(BUILDDIR)/coreutils completion $(prog) bash > $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/$(PROG_PREFIX)$(prog); \
|
||||
$(BUILDDIR)/coreutils completion $(prog) fish > $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/$(PROG_PREFIX)$(prog).fish; \
|
||||
$(BUILDDIR)/coreutils manpage $(prog) > $(DESTDIR)$(DATAROOTDIR)/man/man1/$(PROG_PREFIX)$(prog).1; \
|
||||
$(INSTALL) $(BUILDDIR)/completions/zsh/_$(PROG_PREFIX)$(prog) $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions/; \
|
||||
$(INSTALL) $(BUILDDIR)/completions/bash/$(PROG_PREFIX)$(prog) $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/; \
|
||||
$(INSTALL) $(BUILDDIR)/completions/fish/$(PROG_PREFIX)$(prog).fish $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/; \
|
||||
)
|
||||
|
||||
uninstall:
|
||||
|
@ -369,5 +386,6 @@ endif
|
|||
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions/_$(PROG_PREFIX),$(PROGS))
|
||||
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/$(PROG_PREFIX),$(PROGS))
|
||||
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS)))
|
||||
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/man/man1/$(PROG_PREFIX),$(addsuffix .1,$(PROGS)))
|
||||
|
||||
.PHONY: all build build-coreutils build-pkgs test distclean clean busytest install uninstall
|
||||
|
|
162
Makefile.toml
162
Makefile.toml
|
@ -20,15 +20,12 @@ run_task = "_init"
|
|||
|
||||
[tasks._init]
|
||||
private = true
|
||||
dependencies = [
|
||||
"_init-vars",
|
||||
]
|
||||
dependencies = ["_init-vars"]
|
||||
|
||||
[tasks._init-vars]
|
||||
private = true
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
'''
|
||||
script = ['''
|
||||
# reset build/test flags
|
||||
set_env CARGO_MAKE_CARGO_BUILD_TEST_FLAGS ""
|
||||
# determine features
|
||||
|
@ -90,54 +87,36 @@ for arg in "${args_utils_list}"
|
|||
end
|
||||
args_utils = trim "${args_utils}"
|
||||
set_env CARGO_MAKE_TASK_BUILD_UTILS_ARGS "${args_utils}"
|
||||
'''
|
||||
]
|
||||
''']
|
||||
|
||||
### tasks
|
||||
|
||||
[tasks.default]
|
||||
description = "## *DEFAULT* Build (debug-mode) and test project"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"action-build-debug",
|
||||
"test-terse",
|
||||
]
|
||||
dependencies = ["action-build-debug", "test-terse"]
|
||||
|
||||
##
|
||||
|
||||
[tasks.build]
|
||||
description = "## Build (release-mode) project"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-build",
|
||||
"action-build-release",
|
||||
"core::post-build",
|
||||
]
|
||||
dependencies = ["core::pre-build", "action-build-release", "core::post-build"]
|
||||
|
||||
[tasks.build-debug]
|
||||
description = "## Build (debug-mode) project"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"action-build-debug",
|
||||
]
|
||||
dependencies = ["action-build-debug"]
|
||||
|
||||
[tasks.build-examples]
|
||||
description = "## Build (release-mode) project example(s); usage: `cargo make (build-examples | examples) [EXAMPLE]...`"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-build",
|
||||
"action-build-examples",
|
||||
"core::post-build",
|
||||
]
|
||||
dependencies = ["core::pre-build", "action-build-examples", "core::post-build"]
|
||||
|
||||
[tasks.build-features]
|
||||
description = "## Build (with features; release-mode) project; usage: `cargo make (build-features | features) FEATURE...`"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-build",
|
||||
"action-build-features",
|
||||
"core::post-build",
|
||||
]
|
||||
dependencies = ["core::pre-build", "action-build-features", "core::post-build"]
|
||||
|
||||
[tasks.build-release]
|
||||
alias = "build"
|
||||
|
@ -148,9 +127,7 @@ alias = "build-debug"
|
|||
[tasks.example]
|
||||
description = "hidden singular-form alias for 'examples'"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"examples",
|
||||
]
|
||||
dependencies = ["examples"]
|
||||
|
||||
[tasks.examples]
|
||||
alias = "build-examples"
|
||||
|
@ -161,17 +138,12 @@ alias = "build-features"
|
|||
[tasks.format]
|
||||
description = "## Format code files (with `cargo fmt`; includes tests)"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"action-format",
|
||||
"action-format-tests",
|
||||
]
|
||||
dependencies = ["action-format", "action-format-tests"]
|
||||
|
||||
[tasks.help]
|
||||
description = "## Display help"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"action-display-help",
|
||||
]
|
||||
dependencies = ["action-display-help"]
|
||||
|
||||
[tasks.install]
|
||||
description = "## Install project binary (to $HOME/.cargo/bin)"
|
||||
|
@ -182,10 +154,7 @@ args = ["install", "--path", "."]
|
|||
[tasks.lint]
|
||||
description = "## Display lint report"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"action-clippy",
|
||||
"action-fmt_report",
|
||||
]
|
||||
dependencies = ["action-clippy", "action-fmt_report"]
|
||||
|
||||
[tasks.release]
|
||||
alias = "build"
|
||||
|
@ -193,48 +162,32 @@ alias = "build"
|
|||
[tasks.test]
|
||||
description = "## Run project tests"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-test",
|
||||
"core::test",
|
||||
"core::post-test",
|
||||
]
|
||||
dependencies = ["core::pre-test", "core::test", "core::post-test"]
|
||||
|
||||
[tasks.test-terse]
|
||||
description = "## Run project tests (with terse/summary output)"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-test",
|
||||
"action-test_quiet",
|
||||
"core::post-test",
|
||||
]
|
||||
dependencies = ["core::pre-test", "action-test_quiet", "core::post-test"]
|
||||
|
||||
[tasks.test-util]
|
||||
description = "## Test (individual) utilities; usage: `cargo make (test-util | test-uutil) [UTIL_NAME...]`"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"action-test-utils",
|
||||
]
|
||||
dependencies = ["action-test-utils"]
|
||||
|
||||
[tasks.test-utils]
|
||||
description = "hidden plural-form alias for 'test-util'"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"test-util",
|
||||
]
|
||||
dependencies = ["test-util"]
|
||||
|
||||
[tasks.test-uutil]
|
||||
description = "hidden alias for 'test-util'"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"test-util",
|
||||
]
|
||||
dependencies = ["test-util"]
|
||||
|
||||
[tasks.test-uutils]
|
||||
description = "hidden alias for 'test-util'"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"test-util",
|
||||
]
|
||||
dependencies = ["test-util"]
|
||||
|
||||
[tasks.uninstall]
|
||||
description = "## Remove project binary (from $HOME/.cargo/bin)"
|
||||
|
@ -246,63 +199,66 @@ args = ["uninstall"]
|
|||
description = "## Build (individual; release-mode) utilities; usage: `cargo make (util | uutil) [UTIL_NAME...]`"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"core::pre-build",
|
||||
"action-determine-utils",
|
||||
"action-build-utils",
|
||||
"core::post-build",
|
||||
"core::pre-build",
|
||||
"action-determine-utils",
|
||||
"action-build-utils",
|
||||
"core::post-build",
|
||||
]
|
||||
|
||||
[tasks.utils]
|
||||
description = "hidden plural-form alias for 'util'"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"util",
|
||||
]
|
||||
dependencies = ["util"]
|
||||
|
||||
[tasks.uutil]
|
||||
description = "hidden alias for 'util'"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"util",
|
||||
]
|
||||
dependencies = ["util"]
|
||||
|
||||
[tasks.uutils]
|
||||
description = "hidden plural-form alias for 'util'"
|
||||
category = "[project]"
|
||||
dependencies = [
|
||||
"util",
|
||||
]
|
||||
dependencies = ["util"]
|
||||
|
||||
### actions
|
||||
|
||||
[tasks.action-build-release]
|
||||
description = "`cargo build --release`"
|
||||
command = "cargo"
|
||||
args = ["build", "--release", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )" ]
|
||||
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, )" ]
|
||||
args = ["build", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )"]
|
||||
|
||||
[tasks.action-build-examples]
|
||||
description = "`cargo build (--examples|(--example EXAMPLE)...)`"
|
||||
command = "cargo"
|
||||
args = ["build", "--release", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )", "${CARGO_MAKE_TASK_BUILD_EXAMPLES_ARGS}" ]
|
||||
args = [
|
||||
"build",
|
||||
"--release",
|
||||
"@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )",
|
||||
"${CARGO_MAKE_TASK_BUILD_EXAMPLES_ARGS}",
|
||||
]
|
||||
|
||||
[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}" ]
|
||||
args = [
|
||||
"build",
|
||||
"--release",
|
||||
"--no-default-features",
|
||||
"--features",
|
||||
"${CARGO_MAKE_TASK_BUILD_FEATURES_ARGS}",
|
||||
]
|
||||
|
||||
[tasks.action-build-utils]
|
||||
description = "Build individual utilities"
|
||||
dependencies = [
|
||||
"action-determine-utils",
|
||||
]
|
||||
dependencies = ["action-determine-utils"]
|
||||
command = "cargo"
|
||||
# args = ["build", "@@remove-empty(CARGO_MAKE_TASK_BUILD_UTILS_ARGS)" ]
|
||||
args = ["build", "--release", "@@split(CARGO_MAKE_TASK_BUILD_UTILS_ARGS, )" ]
|
||||
args = ["build", "--release", "@@split(CARGO_MAKE_TASK_BUILD_UTILS_ARGS, )"]
|
||||
|
||||
[tasks.action-clippy]
|
||||
description = "`cargo clippy` lint report"
|
||||
|
@ -311,8 +267,7 @@ args = ["clippy", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )"]
|
|||
|
||||
[tasks.action-determine-utils]
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
'''
|
||||
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
|
||||
|
@ -335,13 +290,11 @@ if is_empty "${package_options}"
|
|||
package_options = trim "${package_options}"
|
||||
end_if
|
||||
set_env CARGO_MAKE_TASK_BUILD_UTILS_ARGS "${package_options}"
|
||||
'''
|
||||
]
|
||||
''']
|
||||
|
||||
[tasks.action-determine-tests]
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
'''
|
||||
script = ['''
|
||||
test_files = glob_array tests/**/*.rs
|
||||
for file in ${test_files}
|
||||
file = replace "${file}" "\\" "/"
|
||||
|
@ -354,8 +307,7 @@ for file in ${test_files}
|
|||
end_if
|
||||
end
|
||||
set_env CARGO_MAKE_VAR_TESTS "${tests}"
|
||||
'''
|
||||
]
|
||||
''']
|
||||
|
||||
[tasks.action-format]
|
||||
description = "`cargo fmt`"
|
||||
|
@ -364,9 +316,7 @@ args = ["fmt"]
|
|||
|
||||
[tasks.action-format-tests]
|
||||
description = "`cargo fmt` tests"
|
||||
dependencies = [
|
||||
"action-determine-tests",
|
||||
]
|
||||
dependencies = ["action-determine-tests"]
|
||||
command = "cargo"
|
||||
args = ["fmt", "--", "@@split(CARGO_MAKE_VAR_TESTS, )"]
|
||||
|
||||
|
@ -381,16 +331,18 @@ args = ["fmt", "--", "--check"]
|
|||
[tasks.action-spellcheck-codespell]
|
||||
description = "`codespell` spellcheck repository"
|
||||
command = "codespell" # (from `pip install codespell`)
|
||||
args = [".", "--skip=*/.git,./target,./tests/fixtures", "--ignore-words-list=mut,od"]
|
||||
args = [
|
||||
".",
|
||||
"--skip=*/.git,./target,./tests/fixtures",
|
||||
"--ignore-words-list=mut,od",
|
||||
]
|
||||
|
||||
[tasks.action-test-utils]
|
||||
description = "Build individual utilities"
|
||||
dependencies = [
|
||||
"action-determine-utils",
|
||||
]
|
||||
dependencies = ["action-determine-utils"]
|
||||
command = "cargo"
|
||||
# args = ["build", "@@remove-empty(CARGO_MAKE_TASK_BUILD_UTILS_ARGS)" ]
|
||||
args = ["test", "@@split(CARGO_MAKE_TASK_BUILD_UTILS_ARGS, )" ]
|
||||
args = ["test", "@@split(CARGO_MAKE_TASK_BUILD_UTILS_ARGS, )"]
|
||||
|
||||
[tasks.action-test_quiet]
|
||||
description = "Test (in `--quiet` mode)"
|
||||
|
@ -399,8 +351,7 @@ args = ["test", "--quiet", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )"]
|
|||
|
||||
[tasks.action-display-help]
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
'''
|
||||
script = ['''
|
||||
echo ""
|
||||
echo "usage: `cargo make TARGET [ARGS...]`"
|
||||
echo ""
|
||||
|
@ -432,5 +383,4 @@ script = [
|
|||
end_if
|
||||
end
|
||||
echo ""
|
||||
'''
|
||||
]
|
||||
''']
|
||||
|
|
13
README.md
13
README.md
|
@ -1,6 +1,7 @@
|
|||
<!-- markdownlint-disable MD033 MD041 MD002 -->
|
||||
<!-- markdownlint-disable commands-show-output no-duplicate-heading -->
|
||||
<!-- spell-checker:ignore markdownlint ; (options) DESTDIR UTILNAME manpages reimplementation -->
|
||||
<!-- spell-checker:ignore markdownlint ; (options) DESTDIR UTILNAME manpages reimplementation oranda -->
|
||||
<div class="oranda-hide">
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
@ -19,11 +20,14 @@
|
|||
|
||||
---
|
||||
|
||||
</div>
|
||||
|
||||
uutils coreutils is a cross-platform reimplementation of the GNU coreutils in
|
||||
[Rust](http://www.rust-lang.org). While all programs have been implemented, some
|
||||
options might be missing or different behavior might be experienced.
|
||||
|
||||
<div class="oranda-hide">
|
||||
|
||||
To install it:
|
||||
|
||||
```shell
|
||||
|
@ -31,6 +35,8 @@ cargo install coreutils
|
|||
~/.cargo/bin/coreutils
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<!-- markdownlint-disable-next-line MD026 -->
|
||||
|
||||
## Goals
|
||||
|
@ -42,6 +48,8 @@ uutils aims to work on as many platforms as possible, to be able to use the same
|
|||
utils on Linux, Mac, Windows and other platforms. This ensures, for example,
|
||||
that scripts can be easily transferred between platforms.
|
||||
|
||||
<div class="oranda-hide">
|
||||
|
||||
## Documentation
|
||||
|
||||
uutils has both user and developer documentation available:
|
||||
|
@ -52,6 +60,7 @@ uutils has both user and developer documentation available:
|
|||
Both can also be generated locally, the instructions for that can be found in
|
||||
the [coreutils docs](https://github.com/uutils/uutils.github.io) repository.
|
||||
|
||||
|
||||
<!-- ANCHOR: build (this mark is needed for mdbook) -->
|
||||
|
||||
## Requirements
|
||||
|
@ -301,6 +310,8 @@ See <https://github.com/uutils/coreutils/issues/3336> for the main meta bugs
|
|||
|
||||

|
||||
|
||||
</div> <!-- close oranda-hide div -->
|
||||
|
||||
## Contributing
|
||||
|
||||
To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md).
|
||||
|
|
4
build.rs
4
build.rs
|
@ -38,14 +38,14 @@ pub fn main() {
|
|||
let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap();
|
||||
|
||||
mf.write_all(
|
||||
"type UtilityMap<T> = phf::Map<&'static str, (fn(T) -> i32, fn() -> Command)>;\n\
|
||||
"type UtilityMap<T> = phf::OrderedMap<&'static str, (fn(T) -> i32, fn() -> Command)>;\n\
|
||||
\n\
|
||||
fn util_map<T: uucore::Args>() -> UtilityMap<T> {\n"
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut phf_map = phf_codegen::Map::<&str>::new();
|
||||
let mut phf_map = phf_codegen::OrderedMap::<&str>::new();
|
||||
for krate in &crates {
|
||||
let map_value = format!("({krate}::uumain, {krate}::uu_app)");
|
||||
match krate.as_ref() {
|
||||
|
|
73
deny.toml
73
deny.toml
|
@ -11,7 +11,7 @@ unmaintained = "warn"
|
|||
yanked = "warn"
|
||||
notice = "warn"
|
||||
ignore = [
|
||||
#"RUSTSEC-0000-0000",
|
||||
#"RUSTSEC-0000-0000",
|
||||
]
|
||||
|
||||
# This section is considered when running `cargo deny check licenses`
|
||||
|
@ -20,15 +20,14 @@ ignore = [
|
|||
[licenses]
|
||||
unlicensed = "deny"
|
||||
allow = [
|
||||
"MIT",
|
||||
"Apache-2.0",
|
||||
"ISC",
|
||||
"BSD-2-Clause",
|
||||
"BSD-2-Clause-FreeBSD",
|
||||
"BSD-3-Clause",
|
||||
"CC0-1.0",
|
||||
"MPL-2.0", # XXX considered copyleft?
|
||||
"Unicode-DFS-2016",
|
||||
"MIT",
|
||||
"Apache-2.0",
|
||||
"ISC",
|
||||
"BSD-2-Clause",
|
||||
"BSD-2-Clause-FreeBSD",
|
||||
"BSD-3-Clause",
|
||||
"CC0-1.0",
|
||||
"Unicode-DFS-2016",
|
||||
]
|
||||
copyleft = "deny"
|
||||
allow-osi-fsf-free = "neither"
|
||||
|
@ -59,29 +58,37 @@ highlight = "all"
|
|||
# introduces it.
|
||||
# spell-checker: disable
|
||||
skip = [
|
||||
# is-terminal
|
||||
{ name = "hermit-abi", version = "0.3.1" },
|
||||
# is-terminal
|
||||
{ name = "rustix", version = "0.36.14" },
|
||||
# is-terminal (via rustix)
|
||||
{ name = "io-lifetimes", version = "1.0.5" },
|
||||
# is-terminal
|
||||
{ name = "linux-raw-sys", version = "0.1.4" },
|
||||
# is-terminal
|
||||
{ name = "windows-sys", version = "0.45.0" },
|
||||
{ name = "windows-targets", version = "0.42.2" },
|
||||
{ name = "windows_aarch64_gnullvm", version = "0.42.2" },
|
||||
{ name = "windows_aarch64_msvc", version = "0.42.2" },
|
||||
{ name = "windows_i686_gnu", version = "0.42.2" },
|
||||
{ name = "windows_i686_msvc", version = "0.42.2" },
|
||||
{ name = "windows_x86_64_gnu", version = "0.42.2" },
|
||||
{ name = "windows_x86_64_gnullvm", version = "0.42.2" },
|
||||
{ name = "windows_x86_64_msvc", version = "0.42.2" },
|
||||
|
||||
# tempfile
|
||||
{ name = "redox_syscall", version = "0.3.5" },
|
||||
# cpp_macros
|
||||
{ name = "aho-corasick", version = "0.7.19" },
|
||||
# procfs
|
||||
{ name = "rustix", version = "0.36.15" },
|
||||
# rustix
|
||||
{ name = "linux-raw-sys", version = "0.1.4" },
|
||||
{ name = "linux-raw-sys", version = "0.3.8" },
|
||||
# tempfile
|
||||
{ name = "rustix", version = "0.37.23" },
|
||||
# various crates
|
||||
{ name = "windows-sys", version = "0.45.0" },
|
||||
# windows-sys
|
||||
{ name = "windows-targets", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_aarch64_gnullvm", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_aarch64_msvc", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_i686_gnu", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_i686_msvc", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_x86_64_gnu", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_x86_64_gnullvm", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_x86_64_msvc", version = "0.42.2" },
|
||||
# cpp_macros
|
||||
{ name = "aho-corasick", version = "0.7.20" },
|
||||
# various crates
|
||||
{ name = "syn", version = "1.0.109" },
|
||||
# various crates
|
||||
{ name = "bitflags", version = "1.3.2" },
|
||||
]
|
||||
# spell-checker: enable
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ src = "src"
|
|||
title = "uutils Documentation"
|
||||
|
||||
[output.html]
|
||||
git-repository-url = "https://github.com/rust-lang/cargo/tree/master/src/doc/src"
|
||||
git-repository-url = "https://github.com/uutils/coreutils/tree/main/docs/src"
|
||||
|
||||
[preprocessor.toc]
|
||||
command = "mdbook-toc"
|
||||
renderer = ["html"]
|
||||
renderer = ["html"]
|
||||
|
|
|
@ -61,7 +61,20 @@ feature is adopted from [FreeBSD](https://www.freebsd.org/cgi/man.cgi?cut).
|
|||
|
||||
## `fmt`
|
||||
|
||||
`fmt` has additional flags for prefixes: `-P/--skip-prefix`, `-x/--exact-prefix`, and
|
||||
`-X/--exact-skip-prefix`. With `-m/--preserve-headers`, an attempt is made to detect and preserve
|
||||
mail headers in the input. `-q/--quick` breaks lines more quickly. And `-T/--tab-width` defines the
|
||||
`fmt` has additional flags for prefixes: `-P`/`--skip-prefix`, `-x`/`--exact-prefix`, and
|
||||
`-X`/`--exact-skip-prefix`. With `-m`/`--preserve-headers`, an attempt is made to detect and preserve
|
||||
mail headers in the input. `-q`/`--quick` breaks lines more quickly. And `-T`/`--tab-width` defines the
|
||||
number of spaces representing a tab when determining the line length.
|
||||
|
||||
## `seq`
|
||||
|
||||
`seq` provides `-t`/`--terminator` to set the terminator character.
|
||||
|
||||
## `ls`
|
||||
|
||||
GNU `ls` provides two ways to use a long listing format: `-l` and `--format=long`. We support a
|
||||
third way: `--long`.
|
||||
|
||||
## `du`
|
||||
|
||||
`du` allows `birth` and `creation` as values for the `--time` argument to show the creation time.
|
||||
|
|
|
@ -37,7 +37,7 @@ apk update uutils-coreutils
|
|||
|
||||
### Arch
|
||||
|
||||
[](https://archlinux.org/packages/community/x86_64/uutils-coreutils/)
|
||||
[](https://archlinux.org/packages/extra/x86_64/uutils-coreutils/)
|
||||
|
||||
```shell
|
||||
pacman -S uutils-coreutils
|
||||
|
|
4
docs/src/oranda.css
Normal file
4
docs/src/oranda.css
Normal file
|
@ -0,0 +1,4 @@
|
|||
.logo {
|
||||
display: block;
|
||||
height: 170px;
|
||||
}
|
13
oranda.json
Normal file
13
oranda.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"project": {
|
||||
"name": "uutils coreutils"
|
||||
},
|
||||
"components": {
|
||||
"changelog": true
|
||||
},
|
||||
"styles": {
|
||||
"theme": "light",
|
||||
"logo": "docs/src/logo.svg",
|
||||
"additional_css": ["docs/src/oranda.css"]
|
||||
}
|
||||
}
|
|
@ -212,8 +212,15 @@ fn gen_manpage<T: uucore::Args>(
|
|||
|
||||
fn gen_coreutils_app<T: uucore::Args>(util_map: &UtilityMap<T>) -> Command {
|
||||
let mut command = Command::new("coreutils");
|
||||
for (_, (_, sub_app)) in util_map {
|
||||
command = command.subcommand(sub_app());
|
||||
for (name, (_, sub_app)) in util_map {
|
||||
// Recreate a small subcommand with only the relevant info
|
||||
// (name & short description)
|
||||
let about = sub_app()
|
||||
.get_about()
|
||||
.expect("Could not get the 'about'")
|
||||
.to_string();
|
||||
let sub_app = Command::new(name).about(about);
|
||||
command = command.subcommand(sub_app);
|
||||
}
|
||||
command
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
// spell-checker:ignore tldr
|
||||
// spell-checker:ignore tldr uuhelp
|
||||
|
||||
use clap::Command;
|
||||
use std::collections::HashMap;
|
||||
|
@ -178,7 +178,7 @@ impl<'a, 'b> MDWriter<'a, 'b> {
|
|||
|
||||
fn usage(&mut self) -> io::Result<()> {
|
||||
if let Some(markdown) = &self.markdown {
|
||||
let usage = help_parser::parse_usage(markdown);
|
||||
let usage = uuhelp_parser::parse_usage(markdown);
|
||||
let usage = usage.replace("{}", self.name);
|
||||
|
||||
writeln!(self.w, "\n```")?;
|
||||
|
@ -191,7 +191,7 @@ impl<'a, 'b> MDWriter<'a, 'b> {
|
|||
|
||||
fn about(&mut self) -> io::Result<()> {
|
||||
if let Some(markdown) = &self.markdown {
|
||||
writeln!(self.w, "{}", help_parser::parse_about(markdown))
|
||||
writeln!(self.w, "{}", uuhelp_parser::parse_about(markdown))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ impl<'a, 'b> MDWriter<'a, 'b> {
|
|||
|
||||
fn after_help(&mut self) -> io::Result<()> {
|
||||
if let Some(markdown) = &self.markdown {
|
||||
if let Some(after_help) = help_parser::parse_section("after help", markdown) {
|
||||
if let Some(after_help) = uuhelp_parser::parse_section("after help", markdown) {
|
||||
return writeln!(self.w, "\n\n{after_help}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[package]
|
||||
name = "help_parser"
|
||||
version = "0.0.18"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_arch"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "arch ~ (uutils) display machine architecture"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/arch.rs"
|
||||
|
||||
[dependencies]
|
||||
platform-info = { workspace=true }
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
platform-info = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "arch"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_base32"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "base32 ~ (uutils) decode/encode input (base32-encoding)"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/base32.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features = ["encoding"] }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["encoding"] }
|
||||
|
||||
[[bin]]
|
||||
name = "base32"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_base64"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "base64 ~ (uutils) decode/encode input (base64-encoding)"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/base64.rs"
|
||||
|
||||
[dependencies]
|
||||
uucore = { workspace=true, features = ["encoding"] }
|
||||
uu_base32 = { workspace=true }
|
||||
uucore = { workspace = true, features = ["encoding"] }
|
||||
uu_base32 = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "base64"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_basename"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "basename ~ (uutils) display PATHNAME with leading directory components removed"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/basename.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "basename"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_basenc"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "basenc ~ (uutils) decode/encode input"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/basenc.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features = ["encoding"] }
|
||||
uu_base32 = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["encoding"] }
|
||||
uu_base32 = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "basenc"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_cat"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "cat ~ (uutils) concatenate and display input"
|
||||
|
@ -15,13 +15,13 @@ edition = "2021"
|
|||
path = "src/cat.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
is-terminal = { workspace = true }
|
||||
uucore = { workspace=true, features=["fs", "pipes"] }
|
||||
uucore = { workspace = true, features = ["fs", "pipes"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = { workspace=true }
|
||||
nix = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "cat"
|
||||
|
|
|
@ -290,7 +290,6 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::SHOW_NONPRINTING_TABS)
|
||||
.short('t')
|
||||
.long(options::SHOW_NONPRINTING_TABS)
|
||||
.help("equivalent to -vT")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chcon"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chcon ~ (uutils) change file security context"
|
||||
|
@ -14,12 +14,12 @@ edition = "2021"
|
|||
path = "src/chcon.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["entries", "fs", "perms"] }
|
||||
selinux = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "fs", "perms"] }
|
||||
selinux = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
libc = { workspace=true }
|
||||
fts-sys = { workspace=true }
|
||||
libc = { workspace = true }
|
||||
fts-sys = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "chcon"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chgrp"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chgrp ~ (uutils) change the group ownership of FILE"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/chgrp.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["entries", "fs", "perms"] }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "fs", "perms"] }
|
||||
|
||||
[[bin]]
|
||||
name = "chgrp"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chmod"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chmod ~ (uutils) change mode of FILE"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/chmod.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
uucore = { workspace=true, features=["fs", "mode"] }
|
||||
clap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
uucore = { workspace = true, features = ["fs", "mode"] }
|
||||
|
||||
[[bin]]
|
||||
name = "chmod"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chown"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chown ~ (uutils) change the ownership of FILE"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/chown.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["entries", "fs", "perms"] }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "fs", "perms"] }
|
||||
|
||||
[[bin]]
|
||||
name = "chown"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chroot"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chroot ~ (uutils) run COMMAND under a new root directory"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/chroot.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["entries", "fs"] }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "fs"] }
|
||||
|
||||
[[bin]]
|
||||
name = "chroot"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_cksum"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "cksum ~ (uutils) display CRC and size of input"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/cksum.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["sum"] }
|
||||
hex = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["sum"] }
|
||||
hex = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "cksum"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_comm"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "comm ~ (uutils) compare sorted inputs"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/comm.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "comm"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
[package]
|
||||
name = "uu_cp"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = [
|
||||
"Jordy Dickinson <jordy.dickinson@gmail.com>",
|
||||
"Joshua S. Miller <jsmiller@uchicago.edu>",
|
||||
"uutils developers",
|
||||
"Jordy Dickinson <jordy.dickinson@gmail.com>",
|
||||
"Joshua S. Miller <jsmiller@uchicago.edu>",
|
||||
"uutils developers",
|
||||
]
|
||||
license = "MIT"
|
||||
description = "cp ~ (uutils) copy SOURCE to DESTINATION"
|
||||
|
@ -19,18 +19,18 @@ edition = "2021"
|
|||
path = "src/cp.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
filetime = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
quick-error = { workspace=true }
|
||||
selinux = { workspace=true, optional=true }
|
||||
uucore = { workspace=true, features=["entries", "fs", "perms", "mode"] }
|
||||
walkdir = { workspace=true }
|
||||
indicatif = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
filetime = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
quick-error = { workspace = true }
|
||||
selinux = { workspace = true, optional = true }
|
||||
uucore = { workspace = true, features = ["entries", "fs", "perms", "mode"] }
|
||||
walkdir = { workspace = true }
|
||||
indicatif = { workspace = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
xattr = { workspace=true }
|
||||
exacl = { workspace=true, optional=true }
|
||||
xattr = { workspace = true }
|
||||
exacl = { workspace = true, optional = true }
|
||||
|
||||
[[bin]]
|
||||
name = "cp"
|
||||
|
|
|
@ -43,7 +43,8 @@ use uucore::fs::{
|
|||
};
|
||||
use uucore::update_control::{self, UpdateMode};
|
||||
use uucore::{
|
||||
crash, format_usage, help_about, help_section, help_usage, prompt_yes, show_error, show_warning,
|
||||
crash, format_usage, help_about, help_section, help_usage, prompt_yes, show_error,
|
||||
show_warning, util_name,
|
||||
};
|
||||
|
||||
use crate::copydir::copy_directory;
|
||||
|
@ -229,10 +230,79 @@ pub struct Options {
|
|||
backup_suffix: String,
|
||||
target_dir: Option<PathBuf>,
|
||||
update: UpdateMode,
|
||||
debug: bool,
|
||||
verbose: bool,
|
||||
progress_bar: bool,
|
||||
}
|
||||
|
||||
/// Enum representing various debug states of the offload and reflink actions.
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)] // All of them are used on Linux
|
||||
enum OffloadReflinkDebug {
|
||||
Unknown,
|
||||
No,
|
||||
Yes,
|
||||
Avoided,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
/// Enum representing various debug states of the sparse detection.
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)] // silent for now until we use them
|
||||
enum SparseDebug {
|
||||
Unknown,
|
||||
No,
|
||||
Zeros,
|
||||
SeekHole,
|
||||
SeekHoleZeros,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
/// Struct that contains the debug state for each action in a file copy operation.
|
||||
#[derive(Debug)]
|
||||
struct CopyDebug {
|
||||
offload: OffloadReflinkDebug,
|
||||
reflink: OffloadReflinkDebug,
|
||||
sparse_detection: SparseDebug,
|
||||
}
|
||||
|
||||
impl OffloadReflinkDebug {
|
||||
fn to_string(&self) -> &'static str {
|
||||
match self {
|
||||
Self::No => "no",
|
||||
Self::Yes => "yes",
|
||||
Self::Avoided => "avoided",
|
||||
Self::Unsupported => "unsupported",
|
||||
Self::Unknown => "unknown",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SparseDebug {
|
||||
fn to_string(&self) -> &'static str {
|
||||
match self {
|
||||
Self::No => "no",
|
||||
Self::Zeros => "zeros",
|
||||
Self::SeekHole => "SEEK_HOLE",
|
||||
Self::SeekHoleZeros => "SEEK_HOLE + zeros",
|
||||
Self::Unsupported => "unsupported",
|
||||
Self::Unknown => "unknown",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This function prints the debug information of a file copy operation if
|
||||
/// no hard link or symbolic link is required, and data copy is required.
|
||||
/// It prints the debug information of the offload, reflink, and sparse detection actions.
|
||||
fn show_debug(copy_debug: &CopyDebug) {
|
||||
println!(
|
||||
"copy offload: {}, reflink: {}, sparse detection: {}",
|
||||
copy_debug.offload.to_string(),
|
||||
copy_debug.reflink.to_string(),
|
||||
copy_debug.sparse_detection.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
const ABOUT: &str = help_about!("cp.md");
|
||||
const USAGE: &str = help_usage!("cp.md");
|
||||
const AFTER_HELP: &str = help_section!("after help", "cp.md");
|
||||
|
@ -269,6 +339,7 @@ mod options {
|
|||
pub const STRIP_TRAILING_SLASHES: &str = "strip-trailing-slashes";
|
||||
pub const SYMBOLIC_LINK: &str = "symbolic-link";
|
||||
pub const TARGET_DIRECTORY: &str = "target-directory";
|
||||
pub const DEBUG: &str = "debug";
|
||||
pub const VERBOSE: &str = "verbose";
|
||||
}
|
||||
|
||||
|
@ -312,6 +383,7 @@ pub fn uu_app() -> Command {
|
|||
backup_control::BACKUP_CONTROL_LONG_HELP
|
||||
))
|
||||
.infer_long_args(true)
|
||||
.args_override_self(true)
|
||||
.arg(
|
||||
Arg::new(options::TARGET_DIRECTORY)
|
||||
.short('t')
|
||||
|
@ -369,6 +441,12 @@ pub fn uu_app() -> Command {
|
|||
.help("remove any trailing slashes from each SOURCE argument")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DEBUG)
|
||||
.long(options::DEBUG)
|
||||
.help("explain how a file is copied. Implies -v")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::VERBOSE)
|
||||
.short('v')
|
||||
|
@ -438,6 +516,7 @@ pub fn uu_app() -> Command {
|
|||
PRESERVABLE_ATTRIBUTES,
|
||||
))
|
||||
.num_args(0..)
|
||||
.require_equals(true)
|
||||
.value_name("ATTR_LIST")
|
||||
.overrides_with_all([
|
||||
options::ARCHIVE,
|
||||
|
@ -839,7 +918,8 @@ impl Options {
|
|||
one_file_system: matches.get_flag(options::ONE_FILE_SYSTEM),
|
||||
parents: matches.get_flag(options::PARENTS),
|
||||
update: update_mode,
|
||||
verbose: matches.get_flag(options::VERBOSE),
|
||||
debug: matches.get_flag(options::DEBUG),
|
||||
verbose: matches.get_flag(options::VERBOSE) || matches.get_flag(options::DEBUG),
|
||||
strip_trailing_slashes: matches.get_flag(options::STRIP_TRAILING_SLASHES),
|
||||
reflink_mode: {
|
||||
if let Some(reflink) = matches.get_one::<String>(options::REFLINK) {
|
||||
|
@ -1025,23 +1105,21 @@ fn preserve_hardlinks(
|
|||
}
|
||||
|
||||
/// When handling errors, we don't always want to show them to the user. This function handles that.
|
||||
/// If the error is printed, returns true, false otherwise.
|
||||
fn show_error_if_needed(error: &Error) -> bool {
|
||||
fn show_error_if_needed(error: &Error) {
|
||||
match error {
|
||||
// When using --no-clobber, we don't want to show
|
||||
// an error message
|
||||
Error::NotAllFilesCopied => (),
|
||||
Error::NotAllFilesCopied => {
|
||||
// Need to return an error code
|
||||
}
|
||||
Error::Skipped => {
|
||||
// touch a b && echo "n"|cp -i a b && echo $?
|
||||
// should return an error from GNU 9.2
|
||||
return true;
|
||||
}
|
||||
_ => {
|
||||
show_error!("{}", error);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Copy all `sources` to `target`. Returns an
|
||||
|
@ -1098,9 +1176,8 @@ fn copy(sources: &[Source], target: &TargetSlice, options: &Options) -> CopyResu
|
|||
options,
|
||||
&mut symlinked_files,
|
||||
) {
|
||||
if show_error_if_needed(&error) {
|
||||
non_fatal_errors = true;
|
||||
}
|
||||
show_error_if_needed(&error);
|
||||
non_fatal_errors = true;
|
||||
}
|
||||
}
|
||||
seen_sources.insert(source);
|
||||
|
@ -1177,13 +1254,23 @@ fn copy_source(
|
|||
}
|
||||
|
||||
impl OverwriteMode {
|
||||
fn verify(&self, path: &Path) -> CopyResult<()> {
|
||||
fn verify(&self, path: &Path, verbose: bool) -> CopyResult<()> {
|
||||
match *self {
|
||||
Self::NoClobber => Err(Error::NotAllFilesCopied),
|
||||
Self::NoClobber => {
|
||||
if verbose {
|
||||
println!("skipped {}", path.quote());
|
||||
} else {
|
||||
eprintln!("{}: not replacing {}", util_name(), path.quote());
|
||||
}
|
||||
Err(Error::NotAllFilesCopied)
|
||||
}
|
||||
Self::Interactive(_) => {
|
||||
if prompt_yes!("overwrite {}?", path.quote()) {
|
||||
Ok(())
|
||||
} else {
|
||||
if verbose {
|
||||
println!("skipped {}", path.quote());
|
||||
}
|
||||
Err(Error::Skipped)
|
||||
}
|
||||
}
|
||||
|
@ -1391,7 +1478,7 @@ fn handle_existing_dest(
|
|||
return Err(format!("{} and {} are the same file", source.quote(), dest.quote()).into());
|
||||
}
|
||||
|
||||
options.overwrite.verify(dest)?;
|
||||
options.overwrite.verify(dest, options.verbose)?;
|
||||
|
||||
let backup_path = backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
|
||||
if let Some(backup_path) = backup_path {
|
||||
|
@ -1749,11 +1836,11 @@ fn copy_helper(
|
|||
File::create(dest).context(dest.display().to_string())?;
|
||||
} else if source_is_fifo && options.recursive && !options.copy_contents {
|
||||
#[cfg(unix)]
|
||||
copy_fifo(dest, options.overwrite)?;
|
||||
copy_fifo(dest, options.overwrite, options.verbose)?;
|
||||
} else if source_is_symlink {
|
||||
copy_link(source, dest, symlinked_files)?;
|
||||
} else {
|
||||
copy_on_write(
|
||||
let copy_debug = copy_on_write(
|
||||
source,
|
||||
dest,
|
||||
options.reflink_mode,
|
||||
|
@ -1762,6 +1849,10 @@ fn copy_helper(
|
|||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))]
|
||||
source_is_fifo,
|
||||
)?;
|
||||
|
||||
if !options.attributes_only && options.debug {
|
||||
show_debug(©_debug);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1770,9 +1861,9 @@ fn copy_helper(
|
|||
// "Copies" a FIFO by creating a new one. This workaround is because Rust's
|
||||
// built-in fs::copy does not handle FIFOs (see rust-lang/rust/issues/79390).
|
||||
#[cfg(unix)]
|
||||
fn copy_fifo(dest: &Path, overwrite: OverwriteMode) -> CopyResult<()> {
|
||||
fn copy_fifo(dest: &Path, overwrite: OverwriteMode, verbose: bool) -> CopyResult<()> {
|
||||
if dest.exists() {
|
||||
overwrite.verify(dest)?;
|
||||
overwrite.verify(dest, verbose)?;
|
||||
fs::remove_file(dest)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ use quick_error::ResultExt;
|
|||
|
||||
use uucore::mode::get_umask;
|
||||
|
||||
use crate::{CopyResult, ReflinkMode, SparseMode};
|
||||
use crate::{CopyDebug, CopyResult, OffloadReflinkDebug, ReflinkMode, SparseDebug, SparseMode};
|
||||
|
||||
// From /usr/include/linux/fs.h:
|
||||
// #define FICLONE _IOW(0x94, 9, int)
|
||||
|
@ -145,24 +145,51 @@ pub(crate) fn copy_on_write(
|
|||
sparse_mode: SparseMode,
|
||||
context: &str,
|
||||
source_is_fifo: bool,
|
||||
) -> CopyResult<()> {
|
||||
) -> CopyResult<CopyDebug> {
|
||||
let mut copy_debug = CopyDebug {
|
||||
offload: OffloadReflinkDebug::Unknown,
|
||||
reflink: OffloadReflinkDebug::Unsupported,
|
||||
sparse_detection: SparseDebug::No,
|
||||
};
|
||||
|
||||
let result = match (reflink_mode, sparse_mode) {
|
||||
(ReflinkMode::Never, SparseMode::Always) => sparse_copy(source, dest),
|
||||
(ReflinkMode::Never, _) => std::fs::copy(source, dest).map(|_| ()),
|
||||
(ReflinkMode::Auto, SparseMode::Always) => sparse_copy(source, dest),
|
||||
(ReflinkMode::Never, SparseMode::Always) => {
|
||||
copy_debug.sparse_detection = SparseDebug::Zeros;
|
||||
copy_debug.offload = OffloadReflinkDebug::Avoided;
|
||||
copy_debug.reflink = OffloadReflinkDebug::No;
|
||||
sparse_copy(source, dest)
|
||||
}
|
||||
(ReflinkMode::Never, _) => {
|
||||
copy_debug.sparse_detection = SparseDebug::No;
|
||||
copy_debug.reflink = OffloadReflinkDebug::No;
|
||||
std::fs::copy(source, dest).map(|_| ())
|
||||
}
|
||||
(ReflinkMode::Auto, SparseMode::Always) => {
|
||||
copy_debug.offload = OffloadReflinkDebug::Avoided;
|
||||
copy_debug.sparse_detection = SparseDebug::Zeros;
|
||||
copy_debug.reflink = OffloadReflinkDebug::Unsupported;
|
||||
sparse_copy(source, dest)
|
||||
}
|
||||
|
||||
(ReflinkMode::Auto, _) => {
|
||||
copy_debug.sparse_detection = SparseDebug::No;
|
||||
copy_debug.reflink = OffloadReflinkDebug::Unsupported;
|
||||
if source_is_fifo {
|
||||
copy_fifo_contents(source, dest).map(|_| ())
|
||||
} else {
|
||||
clone(source, dest, CloneFallback::FSCopy)
|
||||
}
|
||||
}
|
||||
(ReflinkMode::Always, SparseMode::Auto) => clone(source, dest, CloneFallback::Error),
|
||||
(ReflinkMode::Always, SparseMode::Auto) => {
|
||||
copy_debug.sparse_detection = SparseDebug::No;
|
||||
copy_debug.reflink = OffloadReflinkDebug::Yes;
|
||||
|
||||
clone(source, dest, CloneFallback::Error)
|
||||
}
|
||||
(ReflinkMode::Always, _) => {
|
||||
return Err("`--reflink=always` can be used only with --sparse=auto".into())
|
||||
}
|
||||
};
|
||||
result.context(context)?;
|
||||
Ok(())
|
||||
Ok(copy_debug)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::path::Path;
|
|||
|
||||
use quick_error::ResultExt;
|
||||
|
||||
use crate::{CopyResult, ReflinkMode, SparseMode};
|
||||
use crate::{CopyDebug, CopyResult, OffloadReflinkDebug, ReflinkMode, SparseDebug, SparseMode};
|
||||
|
||||
/// Copies `source` to `dest` using copy-on-write if possible.
|
||||
///
|
||||
|
@ -24,10 +24,15 @@ pub(crate) fn copy_on_write(
|
|||
sparse_mode: SparseMode,
|
||||
context: &str,
|
||||
source_is_fifo: bool,
|
||||
) -> CopyResult<()> {
|
||||
) -> CopyResult<CopyDebug> {
|
||||
if sparse_mode != SparseMode::Auto {
|
||||
return Err("--sparse is only supported on linux".to_string().into());
|
||||
}
|
||||
let mut copy_debug = CopyDebug {
|
||||
offload: OffloadReflinkDebug::Unknown,
|
||||
reflink: OffloadReflinkDebug::Unsupported,
|
||||
sparse_detection: SparseDebug::Unsupported,
|
||||
};
|
||||
|
||||
// Extract paths in a form suitable to be passed to a syscall.
|
||||
// The unwrap() is safe because they come from the command-line and so contain non nul
|
||||
|
@ -72,6 +77,7 @@ pub(crate) fn copy_on_write(
|
|||
return Err(format!("failed to clone {source:?} from {dest:?}: {error}").into())
|
||||
}
|
||||
_ => {
|
||||
copy_debug.reflink = OffloadReflinkDebug::Yes;
|
||||
if source_is_fifo {
|
||||
let mut src_file = File::open(source)?;
|
||||
let mut dst_file = File::create(dest)?;
|
||||
|
@ -83,5 +89,5 @@ pub(crate) fn copy_on_write(
|
|||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(copy_debug)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::path::Path;
|
|||
|
||||
use quick_error::ResultExt;
|
||||
|
||||
use crate::{CopyResult, ReflinkMode, SparseMode};
|
||||
use crate::{CopyDebug, CopyResult, OffloadReflinkDebug, ReflinkMode, SparseDebug, SparseMode};
|
||||
|
||||
/// Copies `source` to `dest` for systems without copy-on-write
|
||||
pub(crate) fn copy_on_write(
|
||||
|
@ -17,7 +17,7 @@ pub(crate) fn copy_on_write(
|
|||
reflink_mode: ReflinkMode,
|
||||
sparse_mode: SparseMode,
|
||||
context: &str,
|
||||
) -> CopyResult<()> {
|
||||
) -> CopyResult<CopyDebug> {
|
||||
if reflink_mode != ReflinkMode::Never {
|
||||
return Err("--reflink is only supported on linux and macOS"
|
||||
.to_string()
|
||||
|
@ -26,8 +26,12 @@ pub(crate) fn copy_on_write(
|
|||
if sparse_mode != SparseMode::Auto {
|
||||
return Err("--sparse is only supported on linux".to_string().into());
|
||||
}
|
||||
|
||||
let copy_debug = CopyDebug {
|
||||
offload: OffloadReflinkDebug::Unsupported,
|
||||
reflink: OffloadReflinkDebug::Unsupported,
|
||||
sparse_detection: SparseDebug::Unsupported,
|
||||
};
|
||||
fs::copy(source, dest).context(context)?;
|
||||
|
||||
Ok(())
|
||||
Ok(copy_debug)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_csplit"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "csplit ~ (uutils) Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output"
|
||||
|
@ -15,10 +15,10 @@ edition = "2021"
|
|||
path = "src/csplit.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
regex = { workspace=true }
|
||||
uucore = { workspace=true, features=["entries", "fs"] }
|
||||
regex = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "fs"] }
|
||||
|
||||
[[bin]]
|
||||
name = "csplit"
|
||||
|
|
|
@ -127,7 +127,7 @@ where
|
|||
I: Iterator<Item = (usize, io::Result<String>)>,
|
||||
{
|
||||
// split the file based on patterns
|
||||
for pattern in patterns.into_iter() {
|
||||
for pattern in patterns {
|
||||
let pattern_as_str = pattern.to_string();
|
||||
let is_skip = matches!(pattern, patterns::Pattern::SkipToMatch(_, _, _));
|
||||
match pattern {
|
||||
|
@ -552,6 +552,109 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let args = args.collect_ignore();
|
||||
|
||||
let matches = uu_app().try_get_matches_from(args)?;
|
||||
|
||||
// get the file to split
|
||||
let file_name = matches.get_one::<String>(options::FILE).unwrap();
|
||||
|
||||
// get the patterns to split on
|
||||
let patterns: Vec<String> = matches
|
||||
.get_many::<String>(options::PATTERN)
|
||||
.unwrap()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let patterns = patterns::get_patterns(&patterns[..])?;
|
||||
let options = CsplitOptions::new(&matches);
|
||||
if file_name == "-" {
|
||||
let stdin = io::stdin();
|
||||
Ok(csplit(&options, patterns, stdin.lock())?)
|
||||
} else {
|
||||
let file = File::open(file_name)
|
||||
.map_err_context(|| format!("cannot access {}", file_name.quote()))?;
|
||||
let file_metadata = file
|
||||
.metadata()
|
||||
.map_err_context(|| format!("cannot access {}", file_name.quote()))?;
|
||||
if !file_metadata.is_file() {
|
||||
return Err(CsplitError::NotRegularFile(file_name.to_string()).into());
|
||||
}
|
||||
Ok(csplit(&options, patterns, BufReader::new(file))?)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
Command::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.infer_long_args(true)
|
||||
.arg(
|
||||
Arg::new(options::SUFFIX_FORMAT)
|
||||
.short('b')
|
||||
.long(options::SUFFIX_FORMAT)
|
||||
.value_name("FORMAT")
|
||||
.help("use sprintf FORMAT instead of %02d"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PREFIX)
|
||||
.short('f')
|
||||
.long(options::PREFIX)
|
||||
.value_name("PREFIX")
|
||||
.help("use PREFIX instead of 'xx'"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::KEEP_FILES)
|
||||
.short('k')
|
||||
.long(options::KEEP_FILES)
|
||||
.help("do not remove output files on errors")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SUPPRESS_MATCHED)
|
||||
.long(options::SUPPRESS_MATCHED)
|
||||
.help("suppress the lines matching PATTERN")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DIGITS)
|
||||
.short('n')
|
||||
.long(options::DIGITS)
|
||||
.value_name("DIGITS")
|
||||
.help("use specified number of digits instead of 2"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::QUIET)
|
||||
.short('s')
|
||||
.long(options::QUIET)
|
||||
.visible_alias("silent")
|
||||
.help("do not print counts of output file sizes")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ELIDE_EMPTY_FILES)
|
||||
.short('z')
|
||||
.long(options::ELIDE_EMPTY_FILES)
|
||||
.help("remove empty output files")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FILE)
|
||||
.hide(true)
|
||||
.required(true)
|
||||
.value_hint(clap::ValueHint::FilePath),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PATTERN)
|
||||
.hide(true)
|
||||
.action(clap::ArgAction::Append)
|
||||
.required(true),
|
||||
)
|
||||
.after_help(AFTER_HELP)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -714,106 +817,3 @@ mod tests {
|
|||
assert!(input_splitter.next().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let args = args.collect_ignore();
|
||||
|
||||
let matches = uu_app().try_get_matches_from(args)?;
|
||||
|
||||
// get the file to split
|
||||
let file_name = matches.get_one::<String>(options::FILE).unwrap();
|
||||
|
||||
// get the patterns to split on
|
||||
let patterns: Vec<String> = matches
|
||||
.get_many::<String>(options::PATTERN)
|
||||
.unwrap()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let patterns = patterns::get_patterns(&patterns[..])?;
|
||||
let options = CsplitOptions::new(&matches);
|
||||
if file_name == "-" {
|
||||
let stdin = io::stdin();
|
||||
Ok(csplit(&options, patterns, stdin.lock())?)
|
||||
} else {
|
||||
let file = File::open(file_name)
|
||||
.map_err_context(|| format!("cannot access {}", file_name.quote()))?;
|
||||
let file_metadata = file
|
||||
.metadata()
|
||||
.map_err_context(|| format!("cannot access {}", file_name.quote()))?;
|
||||
if !file_metadata.is_file() {
|
||||
return Err(CsplitError::NotRegularFile(file_name.to_string()).into());
|
||||
}
|
||||
Ok(csplit(&options, patterns, BufReader::new(file))?)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
Command::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.infer_long_args(true)
|
||||
.arg(
|
||||
Arg::new(options::SUFFIX_FORMAT)
|
||||
.short('b')
|
||||
.long(options::SUFFIX_FORMAT)
|
||||
.value_name("FORMAT")
|
||||
.help("use sprintf FORMAT instead of %02d"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PREFIX)
|
||||
.short('f')
|
||||
.long(options::PREFIX)
|
||||
.value_name("PREFIX")
|
||||
.help("use PREFIX instead of 'xx'"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::KEEP_FILES)
|
||||
.short('k')
|
||||
.long(options::KEEP_FILES)
|
||||
.help("do not remove output files on errors")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SUPPRESS_MATCHED)
|
||||
.long(options::SUPPRESS_MATCHED)
|
||||
.help("suppress the lines matching PATTERN")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DIGITS)
|
||||
.short('n')
|
||||
.long(options::DIGITS)
|
||||
.value_name("DIGITS")
|
||||
.help("use specified number of digits instead of 2"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::QUIET)
|
||||
.short('s')
|
||||
.long(options::QUIET)
|
||||
.visible_alias("silent")
|
||||
.help("do not print counts of output file sizes")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ELIDE_EMPTY_FILES)
|
||||
.short('z')
|
||||
.long(options::ELIDE_EMPTY_FILES)
|
||||
.help("remove empty output files")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FILE)
|
||||
.hide(true)
|
||||
.required(true)
|
||||
.value_hint(clap::ValueHint::FilePath),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PATTERN)
|
||||
.hide(true)
|
||||
.action(clap::ArgAction::Append)
|
||||
.required(true),
|
||||
)
|
||||
.after_help(AFTER_HELP)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_cut"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "cut ~ (uutils) display byte/field columns of input lines"
|
||||
|
@ -15,11 +15,11 @@ edition = "2021"
|
|||
path = "src/cut.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
memchr = { workspace=true }
|
||||
bstr = { workspace=true }
|
||||
is-terminal = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
bstr = { workspace = true }
|
||||
is-terminal = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "cut"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# spell-checker:ignore humantime
|
||||
# spell-checker:ignore datetime
|
||||
[package]
|
||||
name = "uu_date"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "date ~ (uutils) display or set the current time"
|
||||
|
@ -16,18 +16,19 @@ edition = "2021"
|
|||
path = "src/date.rs"
|
||||
|
||||
[dependencies]
|
||||
chrono = { workspace=true }
|
||||
#/ TODO: check if we can avoid chrono+time
|
||||
time = { workspace=true }
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
humantime_to_duration = { workspace=true }
|
||||
chrono = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
parse_datetime = { workspace = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = { workspace=true }
|
||||
libc = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { workspace=true, features = ["Win32_Foundation", "Win32_System_SystemInformation"] }
|
||||
windows-sys = { workspace = true, features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_System_SystemInformation",
|
||||
] }
|
||||
|
||||
[[bin]]
|
||||
name = "date"
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes humantime
|
||||
// spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes
|
||||
|
||||
use chrono::format::{Item, StrftimeItems};
|
||||
use chrono::{DateTime, Duration as ChronoDuration, FixedOffset, Local, Offset, Utc};
|
||||
use chrono::{DateTime, Duration, FixedOffset, Local, Offset, Utc};
|
||||
#[cfg(windows)]
|
||||
use chrono::{Datelike, Timelike};
|
||||
use clap::{crate_version, Arg, ArgAction, Command};
|
||||
|
@ -18,7 +18,6 @@ use libc::{clock_settime, timespec, CLOCK_REALTIME};
|
|||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::path::PathBuf;
|
||||
use time::Duration;
|
||||
use uucore::display::Quotable;
|
||||
#[cfg(not(any(target_os = "redox")))]
|
||||
use uucore::error::FromIo;
|
||||
|
@ -27,14 +26,13 @@ use uucore::{format_usage, help_about, help_usage, show};
|
|||
#[cfg(windows)]
|
||||
use windows_sys::Win32::{Foundation::SYSTEMTIME, System::SystemInformation::SetSystemTime};
|
||||
|
||||
use uucore::shortcut_value_parser::ShortcutValueParser;
|
||||
|
||||
// Options
|
||||
const DATE: &str = "date";
|
||||
const HOURS: &str = "hours";
|
||||
const MINUTES: &str = "minutes";
|
||||
const SECONDS: &str = "seconds";
|
||||
const HOUR: &str = "hour";
|
||||
const MINUTE: &str = "minute";
|
||||
const SECOND: &str = "second";
|
||||
const NS: &str = "ns";
|
||||
|
||||
const ABOUT: &str = help_about!("date.md");
|
||||
|
@ -111,9 +109,9 @@ enum Iso8601Format {
|
|||
impl<'a> From<&'a str> for Iso8601Format {
|
||||
fn from(s: &str) -> Self {
|
||||
match s {
|
||||
HOURS | HOUR => Self::Hours,
|
||||
MINUTES | MINUTE => Self::Minutes,
|
||||
SECONDS | SECOND => Self::Seconds,
|
||||
HOURS => Self::Hours,
|
||||
MINUTES => Self::Minutes,
|
||||
SECONDS => Self::Seconds,
|
||||
NS => Self::Ns,
|
||||
DATE => Self::Date,
|
||||
// Note: This is caught by clap via `possible_values`
|
||||
|
@ -132,7 +130,7 @@ impl<'a> From<&'a str> for Rfc3339Format {
|
|||
fn from(s: &str) -> Self {
|
||||
match s {
|
||||
DATE => Self::Date,
|
||||
SECONDS | SECOND => Self::Seconds,
|
||||
SECONDS => Self::Seconds,
|
||||
NS => Self::Ns,
|
||||
// Should be caught by clap
|
||||
_ => panic!("Invalid format: {s}"),
|
||||
|
@ -171,7 +169,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
};
|
||||
|
||||
let date_source = if let Some(date) = matches.get_one::<String>(OPT_DATE) {
|
||||
if let Ok(duration) = humantime_to_duration::from_str(date.as_str()) {
|
||||
if let Ok(duration) = parse_datetime::from_str(date.as_str()) {
|
||||
DateSource::Human(duration)
|
||||
} else {
|
||||
DateSource::Custom(date.into())
|
||||
|
@ -226,13 +224,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let iter = std::iter::once(date);
|
||||
Box::new(iter)
|
||||
}
|
||||
DateSource::Human(ref input) => {
|
||||
// Get the current DateTime<FixedOffset> and convert the input time::Duration to chrono::Duration
|
||||
// for things like "1 year ago"
|
||||
DateSource::Human(relative_time) => {
|
||||
// Get the current DateTime<FixedOffset> for things like "1 year ago"
|
||||
let current_time = DateTime::<FixedOffset>::from(Local::now());
|
||||
let input_chrono = ChronoDuration::seconds(input.as_seconds_f32() as i64)
|
||||
+ ChronoDuration::nanoseconds(input.subsec_nanoseconds() as i64);
|
||||
let iter = std::iter::once(Ok(current_time + input_chrono));
|
||||
let iter = std::iter::once(Ok(current_time + relative_time));
|
||||
Box::new(iter)
|
||||
}
|
||||
DateSource::File(ref path) => {
|
||||
|
@ -321,7 +316,9 @@ pub fn uu_app() -> Command {
|
|||
.short('I')
|
||||
.long(OPT_ISO_8601)
|
||||
.value_name("FMT")
|
||||
.value_parser([DATE, HOUR, HOURS, MINUTE, MINUTES, SECOND, SECONDS, NS])
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
DATE, HOURS, MINUTES, SECONDS, NS,
|
||||
]))
|
||||
.num_args(0..=1)
|
||||
.default_missing_value(OPT_DATE)
|
||||
.help(ISO_8601_HELP_STRING),
|
||||
|
@ -337,7 +334,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_RFC_3339)
|
||||
.long(OPT_RFC_3339)
|
||||
.value_name("FMT")
|
||||
.value_parser([DATE, SECOND, SECONDS, NS])
|
||||
.value_parser(ShortcutValueParser::new([DATE, SECONDS, NS]))
|
||||
.help(RFC_3339_HELP_STRING),
|
||||
)
|
||||
.arg(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_dd"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "dd ~ (uutils) copy and convert files"
|
||||
|
@ -15,16 +15,16 @@ edition = "2021"
|
|||
path = "src/dd.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
gcd = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
uucore = { workspace=true, features=["memo"] }
|
||||
clap = { workspace = true }
|
||||
gcd = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
uucore = { workspace = true, features = ["memo"] }
|
||||
|
||||
[target.'cfg(any(target_os = "linux"))'.dependencies]
|
||||
nix = { workspace=true, features = ["fs"] }
|
||||
nix = { workspace = true, features = ["fs"] }
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
|
||||
signal-hook = { workspace=true }
|
||||
signal-hook = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "dd"
|
||||
|
|
|
@ -13,7 +13,7 @@ Copy, and optionally convert, a file system resource
|
|||
|
||||
### Operands
|
||||
|
||||
- `Bs=BYTES` : read and write up to BYTES bytes at a time (default: 512);
|
||||
- `bs=BYTES` : read and write up to BYTES bytes at a time (default: 512);
|
||||
overwrites `ibs` and `obs`.
|
||||
- `cbs=BYTES` : the 'conversion block size' in bytes. Applies to the
|
||||
`conv=block`, and `conv=unblock` operations.
|
||||
|
@ -114,7 +114,7 @@ Copy, and optionally convert, a file system resource
|
|||
|
||||
### General Flags
|
||||
|
||||
- `Direct` : use direct I/O for data.
|
||||
- `direct` : use direct I/O for data.
|
||||
- `directory` : fail unless the given input (if used as an iflag) or
|
||||
output (if used as an oflag) is a directory.
|
||||
- `dsync` : use synchronized I/O for data.
|
||||
|
|
|
@ -36,9 +36,12 @@ use std::os::unix::{
|
|||
io::{AsRawFd, FromRawFd},
|
||||
};
|
||||
use std::path::Path;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering::Relaxed},
|
||||
mpsc, Arc,
|
||||
};
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use clap::{crate_version, Arg, Command};
|
||||
use gcd::Gcd;
|
||||
|
@ -75,6 +78,45 @@ struct Settings {
|
|||
status: Option<StatusLevel>,
|
||||
}
|
||||
|
||||
/// A timer which triggers on a given interval
|
||||
///
|
||||
/// After being constructed with [`Alarm::with_interval`], [`Alarm::is_triggered`]
|
||||
/// will return true once per the given [`Duration`].
|
||||
///
|
||||
/// Can be cloned, but the trigger status is shared across all instances so only
|
||||
/// the first caller each interval will yield true.
|
||||
///
|
||||
/// When all instances are dropped the background thread will exit on the next interval.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Alarm {
|
||||
interval: Duration,
|
||||
trigger: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Alarm {
|
||||
pub fn with_interval(interval: Duration) -> Self {
|
||||
let trigger = Arc::new(AtomicBool::default());
|
||||
|
||||
let weak_trigger = Arc::downgrade(&trigger);
|
||||
thread::spawn(move || {
|
||||
while let Some(trigger) = weak_trigger.upgrade() {
|
||||
thread::sleep(interval);
|
||||
trigger.store(true, Relaxed);
|
||||
}
|
||||
});
|
||||
|
||||
Self { interval, trigger }
|
||||
}
|
||||
|
||||
pub fn is_triggered(&self) -> bool {
|
||||
self.trigger.swap(false, Relaxed)
|
||||
}
|
||||
|
||||
pub fn get_interval(&self) -> Duration {
|
||||
self.interval
|
||||
}
|
||||
}
|
||||
|
||||
/// A number in blocks or bytes
|
||||
///
|
||||
/// Some values (seek, skip, iseek, oseek) can have values either in blocks or in bytes.
|
||||
|
@ -760,7 +802,7 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
|||
// of its report includes the throughput in bytes per second,
|
||||
// which requires knowing how long the process has been
|
||||
// running.
|
||||
let start = time::Instant::now();
|
||||
let start = Instant::now();
|
||||
|
||||
// A good buffer size for reading.
|
||||
//
|
||||
|
@ -780,7 +822,6 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
|||
// information.
|
||||
let (prog_tx, rx) = mpsc::channel();
|
||||
let output_thread = thread::spawn(gen_prog_updater(rx, i.settings.status));
|
||||
let mut progress_as_secs = 0;
|
||||
|
||||
// Optimization: if no blocks are to be written, then don't
|
||||
// bother allocating any buffers.
|
||||
|
@ -813,6 +854,12 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
|||
// This is the max size needed.
|
||||
let mut buf = vec![BUF_INIT_BYTE; bsize];
|
||||
|
||||
// Spawn a timer thread to provide a scheduled signal indicating when we
|
||||
// should send an update of our progress to the reporting thread.
|
||||
//
|
||||
// This avoids the need to query the OS monotonic clock for every block.
|
||||
let alarm = Alarm::with_interval(Duration::from_secs(1));
|
||||
|
||||
// Index in the input file where we are reading bytes and in
|
||||
// the output file where we are writing bytes.
|
||||
//
|
||||
|
@ -871,9 +918,8 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
|||
// error.
|
||||
rstat += rstat_update;
|
||||
wstat += wstat_update;
|
||||
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false);
|
||||
if prog_update.duration.as_secs() >= progress_as_secs {
|
||||
progress_as_secs = prog_update.duration.as_secs() + 1;
|
||||
if alarm.is_triggered() {
|
||||
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false);
|
||||
prog_tx.send(prog_update).unwrap_or(());
|
||||
}
|
||||
}
|
||||
|
@ -885,7 +931,7 @@ fn finalize<T>(
|
|||
output: &mut Output,
|
||||
rstat: ReadStat,
|
||||
wstat: WriteStat,
|
||||
start: time::Instant,
|
||||
start: Instant,
|
||||
prog_tx: &mpsc::Sender<ProgUpdate>,
|
||||
output_thread: thread::JoinHandle<T>,
|
||||
) -> std::io::Result<()> {
|
||||
|
|
|
@ -498,7 +498,7 @@ mod tests {
|
|||
|
||||
fn prog_update_write(n: u128) -> ProgUpdate {
|
||||
ProgUpdate {
|
||||
read_stat: Default::default(),
|
||||
read_stat: ReadStat::default(),
|
||||
write_stat: WriteStat {
|
||||
bytes_total: n,
|
||||
..Default::default()
|
||||
|
@ -510,8 +510,8 @@ mod tests {
|
|||
|
||||
fn prog_update_duration(duration: Duration) -> ProgUpdate {
|
||||
ProgUpdate {
|
||||
read_stat: Default::default(),
|
||||
write_stat: Default::default(),
|
||||
read_stat: ReadStat::default(),
|
||||
write_stat: WriteStat::default(),
|
||||
duration,
|
||||
complete: false,
|
||||
}
|
||||
|
@ -557,8 +557,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_prog_update_write_prog_line() {
|
||||
let prog_update = ProgUpdate {
|
||||
read_stat: Default::default(),
|
||||
write_stat: Default::default(),
|
||||
read_stat: ReadStat::default(),
|
||||
write_stat: WriteStat::default(),
|
||||
duration: Duration::new(1, 0), // one second
|
||||
complete: false,
|
||||
};
|
||||
|
@ -613,8 +613,8 @@ mod tests {
|
|||
#[test]
|
||||
fn write_transfer_stats() {
|
||||
let prog_update = ProgUpdate {
|
||||
read_stat: Default::default(),
|
||||
write_stat: Default::default(),
|
||||
read_stat: ReadStat::default(),
|
||||
write_stat: WriteStat::default(),
|
||||
duration: Duration::new(1, 0), // one second
|
||||
complete: false,
|
||||
};
|
||||
|
@ -634,8 +634,8 @@ mod tests {
|
|||
fn write_final_transfer_stats() {
|
||||
// Tests the formatting of the final statistics written after a progress line.
|
||||
let prog_update = ProgUpdate {
|
||||
read_stat: Default::default(),
|
||||
write_stat: Default::default(),
|
||||
read_stat: ReadStat::default(),
|
||||
write_stat: WriteStat::default(),
|
||||
duration: Duration::new(1, 0), // one second
|
||||
complete: false,
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_df"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "df ~ (uutils) display file system information"
|
||||
|
@ -15,9 +15,12 @@ edition = "2021"
|
|||
path = "src/df.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["libc", "fsext"] }
|
||||
unicode-width = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["libc", "fsext"] }
|
||||
unicode-width = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
||||
[[bin]]
|
||||
name = "df"
|
||||
|
|
|
@ -746,7 +746,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_remote_included() {
|
||||
let opt = Default::default();
|
||||
let opt = Options::default();
|
||||
let m = mount_info("ext4", "/mnt/foo", true, false);
|
||||
assert!(is_included(&m, &opt));
|
||||
}
|
||||
|
@ -773,7 +773,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_dummy_excluded() {
|
||||
let opt = Default::default();
|
||||
let opt = Options::default();
|
||||
let m = mount_info("ext4", "/mnt/foo", false, true);
|
||||
assert!(!is_included(&m, &opt));
|
||||
}
|
||||
|
@ -864,11 +864,11 @@ mod tests {
|
|||
|
||||
mod filter_mount_list {
|
||||
|
||||
use crate::filter_mount_list;
|
||||
use crate::{filter_mount_list, Options};
|
||||
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
let opt = Default::default();
|
||||
let opt = Options::default();
|
||||
let mount_infos = vec![];
|
||||
assert!(filter_mount_list(mount_infos, &opt).is_empty());
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ pub(crate) struct Filesystem {
|
|||
/// This function returns the element of `mounts` on which `path` is
|
||||
/// mounted. If there are no matches, this function returns
|
||||
/// [`None`]. If there are two or more matches, then the single
|
||||
/// [`MountInfo`] with the longest mount directory is returned.
|
||||
/// [`MountInfo`] with the device name corresponding to the entered path.
|
||||
///
|
||||
/// If `canonicalize` is `true`, then the `path` is canonicalized
|
||||
/// before checking whether it matches any mount directories.
|
||||
|
@ -68,9 +68,19 @@ where
|
|||
path.as_ref().to_path_buf()
|
||||
};
|
||||
|
||||
// Find the potential mount point that matches entered path
|
||||
let maybe_mount_point = mounts
|
||||
.iter()
|
||||
.find(|mi| mi.dev_name.eq(&path.to_string_lossy()));
|
||||
// Create pair MountInfo, canonicalized device name
|
||||
// TODO Abstract from accessing real filesystem to
|
||||
// make code more testable
|
||||
.map(|m| (m, std::fs::canonicalize(&m.dev_name)))
|
||||
// Ignore non existing paths
|
||||
.filter(|m| m.1.is_ok())
|
||||
.map(|m| (m.0, m.1.ok().unwrap()))
|
||||
// Try to find canonicalized device name corresponding to entered path
|
||||
.find(|m| m.1.eq(&path))
|
||||
.map(|m| m.0);
|
||||
|
||||
maybe_mount_point.or_else(|| {
|
||||
mounts
|
||||
|
@ -148,12 +158,12 @@ mod tests {
|
|||
// Create a fake `MountInfo` with the given directory name.
|
||||
fn mount_info(mount_dir: &str) -> MountInfo {
|
||||
MountInfo {
|
||||
dev_id: Default::default(),
|
||||
dev_name: Default::default(),
|
||||
fs_type: Default::default(),
|
||||
dev_id: String::default(),
|
||||
dev_name: String::default(),
|
||||
fs_type: String::default(),
|
||||
mount_dir: String::from(mount_dir),
|
||||
mount_option: Default::default(),
|
||||
mount_root: Default::default(),
|
||||
mount_option: String::default(),
|
||||
mount_root: String::default(),
|
||||
remote: Default::default(),
|
||||
dummy: Default::default(),
|
||||
}
|
||||
|
@ -211,10 +221,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_dev_name_match() {
|
||||
let tmp = tempfile::TempDir::new().expect("Failed to create temp dir");
|
||||
let dev_name = std::fs::canonicalize(tmp.path())
|
||||
.expect("Failed to canonicalize tmp path")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
let mut mount_info = mount_info("/foo");
|
||||
mount_info.dev_name = "/dev/sda2".to_string();
|
||||
mount_info.dev_name = dev_name.clone();
|
||||
let mounts = [mount_info];
|
||||
let actual = mount_info_from_path(&mounts, "/dev/sda2", false).unwrap();
|
||||
let actual = mount_info_from_path(&mounts, dev_name, false).unwrap();
|
||||
assert!(mount_info_eq(actual, &mounts[0]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -513,7 +513,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_default_header() {
|
||||
let options = Default::default();
|
||||
let options = Options::default();
|
||||
assert_eq!(
|
||||
Header::get_headers(&options),
|
||||
vec!(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_dir"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "shortcut to ls -C -b"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/dir.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true, features = ["env"] }
|
||||
uucore = { workspace=true, features=["entries", "fs"] }
|
||||
uu_ls = { workspace=true }
|
||||
clap = { workspace = true, features = ["env"] }
|
||||
uucore = { workspace = true, features = ["entries", "fs"] }
|
||||
uu_ls = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "dir"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_dircolors"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "dircolors ~ (uutils) display commands to set LS_COLORS"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/dircolors.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "dircolors"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_dirname"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "dirname ~ (uutils) display parent directory of PATHNAME"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/dirname.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "dirname"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_du"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "du ~ (uutils) display disk usage"
|
||||
|
@ -15,14 +15,17 @@ edition = "2021"
|
|||
path = "src/du.rs"
|
||||
|
||||
[dependencies]
|
||||
chrono = { workspace=true }
|
||||
chrono = { workspace = true }
|
||||
# For the --exclude & --exclude-from options
|
||||
glob = { workspace=true }
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
glob = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows-sys = { workspace=true, features = ["Win32_Storage_FileSystem", "Win32_Foundation"] }
|
||||
windows-sys = { workspace = true, features = [
|
||||
"Win32_Storage_FileSystem",
|
||||
"Win32_Foundation",
|
||||
] }
|
||||
|
||||
[[bin]]
|
||||
name = "du"
|
||||
|
|
|
@ -145,7 +145,7 @@ impl Stat {
|
|||
return Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
is_dir: metadata.is_dir(),
|
||||
size: metadata.len(),
|
||||
size: if path.is_dir() { 0 } else { metadata.len() },
|
||||
blocks: metadata.blocks(),
|
||||
inodes: 1,
|
||||
inode: Some(file_info),
|
||||
|
@ -162,7 +162,7 @@ impl Stat {
|
|||
Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
is_dir: metadata.is_dir(),
|
||||
size: metadata.len(),
|
||||
size: if path.is_dir() { 0 } else { metadata.len() },
|
||||
blocks: size_on_disk / 1024 * 2,
|
||||
inode: file_info,
|
||||
inodes: 1,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_echo"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "echo ~ (uutils) display TEXT"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/echo.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "echo"
|
||||
|
|
10
src/uu/env/Cargo.toml
vendored
10
src/uu/env/Cargo.toml
vendored
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_env"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND"
|
||||
|
@ -15,12 +15,12 @@ edition = "2021"
|
|||
path = "src/env.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
rust-ini = { workspace=true }
|
||||
uucore = { workspace=true, features=["signals"]}
|
||||
clap = { workspace = true }
|
||||
rust-ini = { workspace = true }
|
||||
uucore = { workspace = true, features = ["signals"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = { workspace=true, features = ["signal"] }
|
||||
nix = { workspace = true, features = ["signal"] }
|
||||
|
||||
|
||||
[[bin]]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_expand"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "expand ~ (uutils) convert input tabs to spaces"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/expand.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
unicode-width = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "expand"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_expr"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "expr ~ (uutils) display the value of EXPRESSION"
|
||||
|
@ -15,11 +15,11 @@ edition = "2021"
|
|||
path = "src/expr.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
num-bigint = { workspace=true }
|
||||
num-traits = { workspace=true }
|
||||
onig = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
num-bigint = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
onig = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "expr"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_factor"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "factor ~ (uutils) display the prime factors of each NUMBER"
|
||||
|
@ -12,15 +12,15 @@ categories = ["command-line-utilities"]
|
|||
edition = "2021"
|
||||
|
||||
[build-dependencies]
|
||||
num-traits = { workspace=true } # used in src/numerics.rs, which is included by build.rs
|
||||
num-traits = { workspace = true } # used in src/numerics.rs, which is included by build.rs
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
coz = { workspace=true, optional = true }
|
||||
num-traits = { workspace=true }
|
||||
rand = { workspace=true }
|
||||
smallvec = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
coz = { workspace = true, optional = true }
|
||||
num-traits = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "1.0.3"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_false"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "false ~ (uutils) do nothing and fail"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/false.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "false"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_fmt"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "fmt ~ (uutils) reformat each paragraph of input"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/fmt.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
unicode-width = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "fmt"
|
||||
|
|
|
@ -598,7 +598,7 @@ impl<'a> Iterator for WordSplit<'a> {
|
|||
self.prev_punct && (before_tab.is_some() || word_start_relative > 1);
|
||||
|
||||
// now record whether this word ends in punctuation
|
||||
self.prev_punct = match self.string[..self.position].chars().rev().next() {
|
||||
self.prev_punct = match self.string[..self.position].chars().next_back() {
|
||||
Some(ch) => WordSplit::is_punctuation(ch),
|
||||
_ => panic!("fatal: expected word not to be empty"),
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_fold"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "fold ~ (uutils) wrap each line of input"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/fold.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "fold"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_groups"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "groups ~ (uutils) display group memberships for USERNAME"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/groups.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["entries", "process"] }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "process"] }
|
||||
|
||||
[[bin]]
|
||||
name = "groups"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_hashsum"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "hashsum ~ (uutils) display or check input digests"
|
||||
|
@ -15,11 +15,11 @@ edition = "2021"
|
|||
path = "src/hashsum.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["sum"] }
|
||||
memchr = { workspace=true }
|
||||
regex = { workspace=true }
|
||||
hex = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["sum"] }
|
||||
memchr = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "hashsum"
|
||||
|
|
|
@ -306,7 +306,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
|||
// if there is no program name for some reason, default to "hashsum"
|
||||
let program = args.next().unwrap_or_else(|| OsString::from(NAME));
|
||||
let binary_name = Path::new(&program)
|
||||
.file_name()
|
||||
.file_stem()
|
||||
.unwrap_or_else(|| OsStr::new(NAME))
|
||||
.to_string_lossy();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_head"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "head ~ (uutils) display the first lines of input"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/head.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
memchr = { workspace=true }
|
||||
uucore = { workspace=true, features=["ringbuffer", "lines"] }
|
||||
clap = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
uucore = { workspace = true, features = ["ringbuffer", "lines"] }
|
||||
|
||||
[[bin]]
|
||||
name = "head"
|
||||
|
|
|
@ -575,7 +575,7 @@ mod tests {
|
|||
}
|
||||
#[test]
|
||||
fn test_options_correct_defaults() {
|
||||
let opts: HeadOptions = Default::default();
|
||||
let opts = HeadOptions::default();
|
||||
|
||||
assert!(!opts.verbose);
|
||||
assert!(!opts.quiet);
|
||||
|
@ -622,12 +622,10 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_arg_iterate_bad_encoding() {
|
||||
#[allow(clippy::invalid_utf8_in_unchecked)]
|
||||
let invalid = unsafe { std::str::from_utf8_unchecked(b"\x80\x81") };
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
let invalid = OsString::from_vec(vec![b'\x80', b'\x81']);
|
||||
// this arises from a conversion from OsString to &str
|
||||
assert!(
|
||||
arg_iterate(vec![OsString::from("head"), OsString::from(invalid)].into_iter()).is_err()
|
||||
);
|
||||
assert!(arg_iterate(vec![OsString::from("head"), invalid].into_iter()).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn read_early_exit() {
|
||||
|
|
|
@ -114,7 +114,13 @@ pub fn parse_num(src: &str) -> Result<(u64, bool), ParseSizeError> {
|
|||
return Err(ParseSizeError::ParseFailure(src.to_string()));
|
||||
}
|
||||
|
||||
parse_size(size_string).map(|n| (n, all_but_last))
|
||||
// remove leading zeros so that size is interpreted as decimal, not octal
|
||||
let trimmed_string = size_string.trim_start_matches('0');
|
||||
if trimmed_string.is_empty() {
|
||||
Ok((0, all_but_last))
|
||||
} else {
|
||||
parse_size(trimmed_string).map(|n| (n, all_but_last))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_hostid"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "hostid ~ (uutils) display the numeric identifier of the current host"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/hostid.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "hostid"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_hostname"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "hostname ~ (uutils) display or set the host name of the current host"
|
||||
|
@ -15,12 +15,15 @@ edition = "2021"
|
|||
path = "src/hostname.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
hostname = { version = "0.3", features = ["set"] }
|
||||
uucore = { workspace=true, features=["wide"] }
|
||||
uucore = { workspace = true, features = ["wide"] }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows-sys = { workspace=true, features = ["Win32_Networking_WinSock", "Win32_Foundation"] }
|
||||
windows-sys = { workspace = true, features = [
|
||||
"Win32_Networking_WinSock",
|
||||
"Win32_Foundation",
|
||||
] }
|
||||
|
||||
[[bin]]
|
||||
name = "hostname"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_id"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "id ~ (uutils) display user and group information for USER"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/id.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["entries", "process"] }
|
||||
selinux = { workspace=true, optional=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "process"] }
|
||||
selinux = { workspace = true, optional = true }
|
||||
|
||||
[[bin]]
|
||||
name = "id"
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
[package]
|
||||
name = "uu_install"
|
||||
version = "0.0.18"
|
||||
authors = [
|
||||
"Ben Eills <ben@beneills.com>",
|
||||
"uutils developers",
|
||||
]
|
||||
version = "0.0.20"
|
||||
authors = ["Ben Eills <ben@beneills.com>", "uutils developers"]
|
||||
license = "MIT"
|
||||
description = "install ~ (uutils) copy files from SOURCE to DESTINATION (with specified attributes)"
|
||||
|
||||
|
@ -18,14 +15,11 @@ edition = "2021"
|
|||
path = "src/install.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
filetime = { workspace=true }
|
||||
file_diff = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
uucore = { workspace=true, features=["fs", "mode", "perms", "entries"] }
|
||||
|
||||
[dev-dependencies]
|
||||
time = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
filetime = { workspace = true }
|
||||
file_diff = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
uucore = { workspace = true, features = ["fs", "mode", "perms", "entries"] }
|
||||
|
||||
[[bin]]
|
||||
name = "install"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_join"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "join ~ (uutils) merge lines from inputs with matching join fields"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/join.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
memchr = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "join"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_kill"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "kill ~ (uutils) send a signal to a process"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/kill.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
nix = { workspace=true, features = ["signal"] }
|
||||
uucore = { workspace=true, features=["signals"] }
|
||||
clap = { workspace = true }
|
||||
nix = { workspace = true, features = ["signal"] }
|
||||
uucore = { workspace = true, features = ["signals"] }
|
||||
|
||||
[[bin]]
|
||||
name = "kill"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_link"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "link ~ (uutils) create a hard (file system) link to FILE"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/link.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "link"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_ln"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "ln ~ (uutils) create a (file system) link to TARGET"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/ln.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["fs"] }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["fs"] }
|
||||
|
||||
[[bin]]
|
||||
name = "ln"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_logname"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "logname ~ (uutils) display the login name of the current user"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/logname.rs"
|
||||
|
||||
[dependencies]
|
||||
libc = { workspace=true }
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
libc = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "logname"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_ls"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "ls ~ (uutils) display directory contents"
|
||||
|
@ -15,18 +15,18 @@ edition = "2021"
|
|||
path = "src/ls.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true, features = ["env"] }
|
||||
chrono = { workspace=true }
|
||||
unicode-width = { workspace=true }
|
||||
number_prefix = { workspace=true }
|
||||
term_grid = { workspace=true }
|
||||
terminal_size = { workspace=true }
|
||||
glob = { workspace=true }
|
||||
lscolors = { workspace=true }
|
||||
uucore = { workspace=true, features = ["entries", "fs"] }
|
||||
once_cell = { workspace=true }
|
||||
is-terminal = { workspace=true }
|
||||
selinux = { workspace=true, optional = true }
|
||||
clap = { workspace = true, features = ["env"] }
|
||||
chrono = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
number_prefix = { workspace = true }
|
||||
term_grid = { workspace = true }
|
||||
terminal_size = { workspace = true }
|
||||
glob = { workspace = true }
|
||||
lscolors = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "fs"] }
|
||||
once_cell = { workspace = true }
|
||||
is-terminal = { workspace = true }
|
||||
selinux = { workspace = true, optional = true }
|
||||
|
||||
[[bin]]
|
||||
name = "ls"
|
||||
|
|
|
@ -17,6 +17,8 @@ use lscolors::LsColors;
|
|||
use number_prefix::NumberPrefix;
|
||||
use once_cell::unsync::OnceCell;
|
||||
use std::collections::HashSet;
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
use std::{
|
||||
|
@ -294,6 +296,7 @@ enum Sort {
|
|||
Time,
|
||||
Version,
|
||||
Extension,
|
||||
Width,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
@ -496,6 +499,7 @@ fn extract_sort(options: &clap::ArgMatches) -> Sort {
|
|||
"size" => Sort::Size,
|
||||
"version" => Sort::Version,
|
||||
"extension" => Sort::Extension,
|
||||
"width" => Sort::Width,
|
||||
// below should never happen as clap already restricts the values.
|
||||
_ => unreachable!("Invalid field for --sort"),
|
||||
}
|
||||
|
@ -655,6 +659,19 @@ fn extract_indicator_style(options: &clap::ArgMatches) -> IndicatorStyle {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_width(s: &str) -> Result<u16, LsError> {
|
||||
let radix = match s.starts_with('0') && s.len() > 1 {
|
||||
true => 8,
|
||||
false => 10,
|
||||
};
|
||||
match u16::from_str_radix(s, radix) {
|
||||
Ok(x) => Ok(x),
|
||||
Err(e) => match e.kind() {
|
||||
IntErrorKind::PosOverflow => Ok(u16::MAX),
|
||||
_ => Err(LsError::InvalidLineWidth(s.into())),
|
||||
},
|
||||
}
|
||||
}
|
||||
impl Config {
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn from(options: &clap::ArgMatches) -> UResult<Self> {
|
||||
|
@ -793,20 +810,7 @@ impl Config {
|
|||
};
|
||||
|
||||
let width = match options.get_one::<String>(options::WIDTH) {
|
||||
Some(x) => {
|
||||
if x.starts_with('0') && x.len() > 1 {
|
||||
// Read number as octal
|
||||
match u16::from_str_radix(x, 8) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return Err(LsError::InvalidLineWidth(x.into()).into()),
|
||||
}
|
||||
} else {
|
||||
match x.parse::<u16>() {
|
||||
Ok(u) => u,
|
||||
Err(_) => return Err(LsError::InvalidLineWidth(x.into()).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(x) => parse_width(x)?,
|
||||
None => match terminal_size::terminal_size() {
|
||||
Some((width, _)) => width.0,
|
||||
None => match std::env::var_os("COLUMNS") {
|
||||
|
@ -1200,6 +1204,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::quoting::LITERAL)
|
||||
.short('N')
|
||||
.long(options::quoting::LITERAL)
|
||||
.alias("l")
|
||||
.help("Use literal quoting style. Equivalent to `--quoting-style=literal`")
|
||||
.overrides_with_all([
|
||||
options::QUOTING_STYLE,
|
||||
|
@ -1322,9 +1327,9 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::SORT)
|
||||
.long(options::SORT)
|
||||
.help("Sort by <field>: name, none (-U), time (-t), size (-S) or extension (-X)")
|
||||
.help("Sort by <field>: name, none (-U), time (-t), size (-S), extension (-X) or width")
|
||||
.value_name("field")
|
||||
.value_parser(["name", "none", "time", "size", "version", "extension"])
|
||||
.value_parser(["name", "none", "time", "size", "version", "extension", "width"])
|
||||
.require_equals(true)
|
||||
.overrides_with_all([
|
||||
options::SORT,
|
||||
|
@ -1929,14 +1934,22 @@ fn sort_entries(entries: &mut [PathData], config: &Config, out: &mut BufWriter<S
|
|||
Sort::Size => entries.sort_by_key(|k| Reverse(k.md(out).map(|md| md.len()).unwrap_or(0))),
|
||||
// The default sort in GNU ls is case insensitive
|
||||
Sort::Name => entries.sort_by(|a, b| a.display_name.cmp(&b.display_name)),
|
||||
Sort::Version => entries
|
||||
.sort_by(|a, b| version_cmp(&a.p_buf.to_string_lossy(), &b.p_buf.to_string_lossy())),
|
||||
Sort::Version => entries.sort_by(|a, b| {
|
||||
version_cmp(&a.p_buf.to_string_lossy(), &b.p_buf.to_string_lossy())
|
||||
.then(a.p_buf.to_string_lossy().cmp(&b.p_buf.to_string_lossy()))
|
||||
}),
|
||||
Sort::Extension => entries.sort_by(|a, b| {
|
||||
a.p_buf
|
||||
.extension()
|
||||
.cmp(&b.p_buf.extension())
|
||||
.then(a.p_buf.file_stem().cmp(&b.p_buf.file_stem()))
|
||||
}),
|
||||
Sort::Width => entries.sort_by(|a, b| {
|
||||
a.display_name
|
||||
.len()
|
||||
.cmp(&b.display_name.len())
|
||||
.then(a.display_name.cmp(&b.display_name))
|
||||
}),
|
||||
Sort::None => {}
|
||||
}
|
||||
|
||||
|
@ -3000,6 +3013,20 @@ fn display_inode(metadata: &Metadata) -> String {
|
|||
#[allow(unused_variables)]
|
||||
fn get_security_context(config: &Config, p_buf: &Path, must_dereference: bool) -> String {
|
||||
let substitute_string = "?".to_string();
|
||||
// If we must dereference, ensure that the symlink is actually valid even if the system
|
||||
// does not support SELinux.
|
||||
// Conforms to the GNU coreutils where a dangling symlink results in exit code 1.
|
||||
if must_dereference {
|
||||
match get_metadata(p_buf, must_dereference) {
|
||||
Err(err) => {
|
||||
// The Path couldn't be dereferenced, so return early and set exit code 1
|
||||
// to indicate a minor error
|
||||
show!(LsError::IOErrorContext(err, p_buf.to_path_buf(), false));
|
||||
return substitute_string;
|
||||
}
|
||||
Ok(md) => (),
|
||||
}
|
||||
}
|
||||
if config.selinux_supported {
|
||||
#[cfg(feature = "selinux")]
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mkdir"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mkdir ~ (uutils) create DIRECTORY"
|
||||
|
@ -15,8 +15,8 @@ edition = "2021"
|
|||
path = "src/mkdir.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true, features=["fs", "mode"] }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["fs", "mode"] }
|
||||
|
||||
[[bin]]
|
||||
name = "mkdir"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mkfifo"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mkfifo ~ (uutils) create FIFOs (named pipes)"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/mkfifo.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "mkfifo"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mknod"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mknod ~ (uutils) create special file NAME of TYPE"
|
||||
|
@ -16,9 +16,9 @@ name = "uu_mknod"
|
|||
path = "src/mknod.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
uucore = { workspace=true, features=["mode"] }
|
||||
clap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
uucore = { workspace = true, features = ["mode"] }
|
||||
|
||||
[[bin]]
|
||||
name = "mknod"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mktemp"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mktemp ~ (uutils) create and display a temporary file or directory from TEMPLATE"
|
||||
|
@ -15,10 +15,10 @@ edition = "2021"
|
|||
path = "src/mktemp.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
rand = { workspace=true }
|
||||
tempfile = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "mktemp"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
// spell-checker:ignore (paths) GPGHome findxs
|
||||
|
||||
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
|
||||
use clap::{builder::ValueParser, crate_version, Arg, ArgAction, ArgMatches, Command};
|
||||
use uucore::display::{println_verbatim, Quotable};
|
||||
use uucore::error::{FromIo, UError, UResult, UUsageError};
|
||||
use uucore::{format_usage, help_about, help_usage};
|
||||
|
@ -38,6 +38,7 @@ static OPT_DRY_RUN: &str = "dry-run";
|
|||
static OPT_QUIET: &str = "quiet";
|
||||
static OPT_SUFFIX: &str = "suffix";
|
||||
static OPT_TMPDIR: &str = "tmpdir";
|
||||
static OPT_P: &str = "p";
|
||||
static OPT_T: &str = "t";
|
||||
|
||||
static ARG_TEMPLATE: &str = "template";
|
||||
|
@ -130,7 +131,7 @@ struct Options {
|
|||
/// The directory in which to create the temporary file.
|
||||
///
|
||||
/// If `None`, the file will be created in the current directory.
|
||||
tmpdir: Option<String>,
|
||||
tmpdir: Option<PathBuf>,
|
||||
|
||||
/// The suffix to append to the temporary file, if any.
|
||||
suffix: Option<String>,
|
||||
|
@ -142,72 +143,32 @@ struct Options {
|
|||
template: String,
|
||||
}
|
||||
|
||||
/// Decide whether the argument to `--tmpdir` should actually be the template.
|
||||
///
|
||||
/// This function is required to work around a limitation of `clap`,
|
||||
/// the command-line argument parsing library. In case the command
|
||||
/// line is
|
||||
///
|
||||
/// ```sh
|
||||
/// mktemp --tmpdir XXX
|
||||
/// ```
|
||||
///
|
||||
/// the program should behave like
|
||||
///
|
||||
/// ```sh
|
||||
/// mktemp --tmpdir=${TMPDIR:-/tmp} XXX
|
||||
/// ```
|
||||
///
|
||||
/// However, `clap` thinks that `XXX` is the value of the `--tmpdir`
|
||||
/// option. This function returns `true` in this case and `false`
|
||||
/// in all other cases.
|
||||
fn is_tmpdir_argument_actually_the_template(matches: &ArgMatches) -> bool {
|
||||
if !matches.contains_id(ARG_TEMPLATE) {
|
||||
if let Some(tmpdir) = matches.get_one::<String>(OPT_TMPDIR) {
|
||||
if !Path::new(tmpdir).is_dir() && tmpdir.contains("XXX") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
impl Options {
|
||||
fn from(matches: &ArgMatches) -> Self {
|
||||
// Special case to work around a limitation of `clap`; see
|
||||
// `is_tmpdir_argument_actually_the_template()` for more
|
||||
// information.
|
||||
//
|
||||
// Fixed in clap 3
|
||||
// See https://github.com/clap-rs/clap/pull/1587
|
||||
let (tmpdir, template) = if is_tmpdir_argument_actually_the_template(matches) {
|
||||
let tmpdir = Some(env::temp_dir().display().to_string());
|
||||
let template = matches.get_one::<String>(OPT_TMPDIR).unwrap().to_string();
|
||||
(tmpdir, template)
|
||||
} else {
|
||||
let tmpdir = matches
|
||||
.get_one::<PathBuf>(OPT_TMPDIR)
|
||||
.or_else(|| matches.get_one::<PathBuf>(OPT_P))
|
||||
.cloned();
|
||||
let (tmpdir, template) = match matches.get_one::<String>(ARG_TEMPLATE) {
|
||||
// If no template argument is given, `--tmpdir` is implied.
|
||||
match matches.get_one::<String>(ARG_TEMPLATE) {
|
||||
None => {
|
||||
let tmpdir = match matches.get_one::<String>(OPT_TMPDIR) {
|
||||
None => Some(env::temp_dir().display().to_string()),
|
||||
Some(tmpdir) => Some(tmpdir.to_string()),
|
||||
};
|
||||
let template = DEFAULT_TEMPLATE;
|
||||
(tmpdir, template.to_string())
|
||||
}
|
||||
Some(template) => {
|
||||
let tmpdir = if env::var(TMPDIR_ENV_VAR).is_ok() && matches.get_flag(OPT_T) {
|
||||
env::var(TMPDIR_ENV_VAR).ok()
|
||||
} else if matches.contains_id(OPT_TMPDIR) {
|
||||
matches.get_one::<String>(OPT_TMPDIR).map(String::from)
|
||||
} else if matches.get_flag(OPT_T) {
|
||||
// mktemp -t foo.xxx should export in TMPDIR
|
||||
Some(env::temp_dir().display().to_string())
|
||||
} else {
|
||||
matches.get_one::<String>(OPT_TMPDIR).map(String::from)
|
||||
};
|
||||
(tmpdir, template.to_string())
|
||||
}
|
||||
None => {
|
||||
let tmpdir = Some(tmpdir.unwrap_or_else(env::temp_dir));
|
||||
let template = DEFAULT_TEMPLATE;
|
||||
(tmpdir, template.to_string())
|
||||
}
|
||||
Some(template) => {
|
||||
let tmpdir = if env::var(TMPDIR_ENV_VAR).is_ok() && matches.get_flag(OPT_T) {
|
||||
env::var_os(TMPDIR_ENV_VAR).map(|t| t.into())
|
||||
} else if tmpdir.is_some() {
|
||||
tmpdir
|
||||
} else if matches.get_flag(OPT_T) || matches.contains_id(OPT_TMPDIR) {
|
||||
// If --tmpdir is given without an argument, or -t is given
|
||||
// export in TMPDIR
|
||||
Some(env::temp_dir())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
(tmpdir, template.to_string())
|
||||
}
|
||||
};
|
||||
Self {
|
||||
|
@ -372,7 +333,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
|
||||
if env::var("POSIXLY_CORRECT").is_ok() {
|
||||
// If POSIXLY_CORRECT was set, template MUST be the last argument.
|
||||
if is_tmpdir_argument_actually_the_template(&matches) || matches.contains_id(ARG_TEMPLATE) {
|
||||
if matches.contains_id(ARG_TEMPLATE) {
|
||||
// Template argument was provided, check if was the last one.
|
||||
if args.last().unwrap() != &options.template {
|
||||
return Err(Box::new(MkTempError::TooManyTemplates));
|
||||
|
@ -444,8 +405,16 @@ pub fn uu_app() -> Command {
|
|||
.value_name("SUFFIX"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_TMPDIR)
|
||||
Arg::new(OPT_P)
|
||||
.short('p')
|
||||
.help("short form of --tmpdir")
|
||||
.value_name("DIR")
|
||||
.num_args(1)
|
||||
.value_parser(ValueParser::path_buf())
|
||||
.value_hint(clap::ValueHint::DirPath),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_TMPDIR)
|
||||
.long(OPT_TMPDIR)
|
||||
.help(
|
||||
"interpret TEMPLATE relative to DIR; if DIR is not specified, use \
|
||||
|
@ -457,6 +426,10 @@ pub fn uu_app() -> Command {
|
|||
// Allows use of default argument just by setting --tmpdir. Else,
|
||||
// use provided input to generate tmpdir
|
||||
.num_args(0..=1)
|
||||
// Require an equals to avoid ambiguity if no tmpdir is supplied
|
||||
.require_equals(true)
|
||||
.overrides_with(OPT_P)
|
||||
.value_parser(ValueParser::path_buf())
|
||||
.value_hint(clap::ValueHint::DirPath),
|
||||
)
|
||||
.arg(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_more"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "more ~ (uutils) input perusal filter"
|
||||
|
@ -15,15 +15,15 @@ edition = "2021"
|
|||
path = "src/more.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
crossterm = { workspace=true }
|
||||
is-terminal = { workspace=true }
|
||||
unicode-width = { workspace=true }
|
||||
unicode-segmentation = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
crossterm = { workspace = true }
|
||||
is-terminal = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
unicode-segmentation = { workspace = true }
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "fuchsia")))'.dependencies]
|
||||
nix = { workspace=true }
|
||||
nix = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "more"
|
||||
|
|
|
@ -14,10 +14,10 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
|
||||
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
|
||||
use clap::{crate_version, value_parser, Arg, ArgAction, ArgMatches, Command};
|
||||
use crossterm::event::KeyEventKind;
|
||||
use crossterm::{
|
||||
cursor::MoveTo,
|
||||
cursor::{MoveTo, MoveUp},
|
||||
event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
|
||||
execute, queue,
|
||||
style::Attribute,
|
||||
|
@ -50,19 +50,37 @@ pub mod options {
|
|||
pub const FILES: &str = "files";
|
||||
}
|
||||
|
||||
const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";
|
||||
const MULTI_FILE_TOP_PROMPT: &str = "\r::::::::::::::\n\r{}\n\r::::::::::::::\n";
|
||||
|
||||
struct Options {
|
||||
silent: bool,
|
||||
clean_print: bool,
|
||||
from_line: usize,
|
||||
lines: Option<u16>,
|
||||
print_over: bool,
|
||||
silent: bool,
|
||||
squeeze: bool,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
fn from(matches: &ArgMatches) -> Self {
|
||||
let lines = match (
|
||||
matches.get_one::<u16>(options::LINES).copied(),
|
||||
matches.get_one::<u16>(options::NUMBER).copied(),
|
||||
) {
|
||||
// We add 1 to the number of lines to display because the last line
|
||||
// is used for the banner
|
||||
(Some(number), _) if number > 0 => Some(number + 1),
|
||||
(None, Some(number)) if number > 0 => Some(number + 1),
|
||||
(_, _) => None,
|
||||
};
|
||||
let from_line = match matches.get_one::<usize>(options::FROM_LINE).copied() {
|
||||
Some(number) if number > 1 => number - 1,
|
||||
_ => 0,
|
||||
};
|
||||
Self {
|
||||
clean_print: matches.get_flag(options::CLEAN_PRINT),
|
||||
from_line,
|
||||
lines,
|
||||
print_over: matches.get_flag(options::PRINT_OVER),
|
||||
silent: matches.get_flag(options::SILENT),
|
||||
squeeze: matches.get_flag(options::SQUEEZE),
|
||||
|
@ -78,7 +96,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
let options = Options::from(&matches);
|
||||
let mut options = Options::from(&matches);
|
||||
|
||||
let mut buff = String::new();
|
||||
|
||||
|
@ -103,9 +121,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
format!("cannot open {}: No such file or directory", file.quote()),
|
||||
));
|
||||
}
|
||||
if length > 1 {
|
||||
buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", file.to_str().unwrap()));
|
||||
}
|
||||
let opened_file = match File::open(file) {
|
||||
Err(why) => {
|
||||
terminal::disable_raw_mode().unwrap();
|
||||
|
@ -118,14 +133,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
};
|
||||
let mut reader = BufReader::new(opened_file);
|
||||
reader.read_to_string(&mut buff).unwrap();
|
||||
more(&buff, &mut stdout, next_file.copied(), &options)?;
|
||||
more(
|
||||
&buff,
|
||||
&mut stdout,
|
||||
length > 1,
|
||||
file.to_str(),
|
||||
next_file.copied(),
|
||||
&mut options,
|
||||
)?;
|
||||
buff.clear();
|
||||
}
|
||||
reset_term(&mut stdout);
|
||||
} else if !std::io::stdin().is_terminal() {
|
||||
stdin().read_to_string(&mut buff).unwrap();
|
||||
let mut stdout = setup_term();
|
||||
more(&buff, &mut stdout, None, &options)?;
|
||||
more(&buff, &mut stdout, false, None, None, &mut options)?;
|
||||
reset_term(&mut stdout);
|
||||
} else {
|
||||
return Err(UUsageError::new(1, "bad usage"));
|
||||
|
@ -167,6 +189,38 @@ pub fn uu_app() -> Command {
|
|||
.help("Squeeze multiple blank lines into one")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PLAIN)
|
||||
.short('u')
|
||||
.long(options::PLAIN)
|
||||
.action(ArgAction::SetTrue)
|
||||
.hide(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FROM_LINE)
|
||||
.short('F')
|
||||
.long(options::FROM_LINE)
|
||||
.num_args(1)
|
||||
.value_name("number")
|
||||
.value_parser(value_parser!(usize))
|
||||
.help("Display file beginning from line number"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::LINES)
|
||||
.short('n')
|
||||
.long(options::LINES)
|
||||
.value_name("number")
|
||||
.num_args(1)
|
||||
.value_parser(value_parser!(u16).range(0..))
|
||||
.help("The number of lines per screen full"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NUMBER)
|
||||
.long(options::NUMBER)
|
||||
.num_args(1)
|
||||
.value_parser(value_parser!(u16).range(0..))
|
||||
.help("Same as --lines"),
|
||||
)
|
||||
// The commented arguments below are unimplemented:
|
||||
/*
|
||||
.arg(
|
||||
|
@ -181,37 +235,6 @@ pub fn uu_app() -> Command {
|
|||
.long(options::NO_PAUSE)
|
||||
.help("Suppress pause after form feed"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PLAIN)
|
||||
.short('u')
|
||||
.long(options::PLAIN)
|
||||
.help("Suppress underlining and bold"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::LINES)
|
||||
.short('n')
|
||||
.long(options::LINES)
|
||||
.value_name("number")
|
||||
.takes_value(true)
|
||||
.help("The number of lines per screen full"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NUMBER)
|
||||
.allow_hyphen_values(true)
|
||||
.long(options::NUMBER)
|
||||
.required(false)
|
||||
.takes_value(true)
|
||||
.help("Same as --lines"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FROM_LINE)
|
||||
.short('F')
|
||||
.allow_hyphen_values(true)
|
||||
.required(false)
|
||||
.takes_value(true)
|
||||
.value_name("number")
|
||||
.help("Display file beginning from line number"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PATTERN)
|
||||
.short('P')
|
||||
|
@ -260,15 +283,36 @@ fn reset_term(_: &mut usize) {}
|
|||
fn more(
|
||||
buff: &str,
|
||||
stdout: &mut Stdout,
|
||||
multiple_file: bool,
|
||||
file: Option<&str>,
|
||||
next_file: Option<&str>,
|
||||
options: &Options,
|
||||
options: &mut Options,
|
||||
) -> UResult<()> {
|
||||
let (cols, rows) = terminal::size().unwrap();
|
||||
let (cols, mut rows) = terminal::size().unwrap();
|
||||
if let Some(number) = options.lines {
|
||||
rows = number;
|
||||
}
|
||||
|
||||
let lines = break_buff(buff, usize::from(cols));
|
||||
|
||||
let mut pager = Pager::new(rows, lines, next_file, options);
|
||||
|
||||
if multiple_file {
|
||||
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
|
||||
stdout.write_all(
|
||||
MULTI_FILE_TOP_PROMPT
|
||||
.replace("{}", file.unwrap_or_default())
|
||||
.as_bytes(),
|
||||
)?;
|
||||
pager.content_rows -= 3;
|
||||
}
|
||||
pager.draw(stdout, None);
|
||||
if pager.should_close() {
|
||||
if multiple_file {
|
||||
options.from_line = 0;
|
||||
pager.content_rows += 3;
|
||||
}
|
||||
|
||||
if pager.should_close() && next_file.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -327,6 +371,7 @@ fn more(
|
|||
..
|
||||
}) => {
|
||||
pager.page_up();
|
||||
paging_add_back_message(options, stdout)?;
|
||||
}
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Char('j'),
|
||||
|
@ -347,7 +392,7 @@ fn more(
|
|||
pager.prev_line();
|
||||
}
|
||||
Event::Resize(col, row) => {
|
||||
pager.page_resize(col, row);
|
||||
pager.page_resize(col, row, options.lines);
|
||||
}
|
||||
Event::Key(KeyEvent {
|
||||
code: KeyCode::Char(k),
|
||||
|
@ -388,7 +433,7 @@ impl<'a> Pager<'a> {
|
|||
fn new(rows: u16, lines: Vec<String>, next_file: Option<&'a str>, options: &Options) -> Self {
|
||||
let line_count = lines.len();
|
||||
Self {
|
||||
upper_mark: 0,
|
||||
upper_mark: options.from_line,
|
||||
content_rows: rows.saturating_sub(1),
|
||||
lines,
|
||||
next_file,
|
||||
|
@ -447,15 +492,17 @@ impl<'a> Pager<'a> {
|
|||
}
|
||||
|
||||
// TODO: Deal with column size changes.
|
||||
fn page_resize(&mut self, _: u16, row: u16) {
|
||||
self.content_rows = row.saturating_sub(1);
|
||||
fn page_resize(&mut self, _: u16, row: u16, option_line: Option<u16>) {
|
||||
if option_line.is_none() {
|
||||
self.content_rows = row.saturating_sub(1);
|
||||
};
|
||||
}
|
||||
|
||||
fn draw(&mut self, stdout: &mut std::io::Stdout, wrong_key: Option<char>) {
|
||||
self.draw_lines(stdout);
|
||||
let lower_mark = self
|
||||
.line_count
|
||||
.min(self.upper_mark.saturating_add(self.content_rows.into()));
|
||||
self.draw_lines(stdout);
|
||||
self.draw_prompt(stdout, lower_mark, wrong_key);
|
||||
stdout.flush().unwrap();
|
||||
}
|
||||
|
@ -515,7 +562,6 @@ impl<'a> Pager<'a> {
|
|||
};
|
||||
|
||||
let status = format!("--More--({status_inner})");
|
||||
|
||||
let banner = match (self.silent, wrong_key) {
|
||||
(true, Some(key)) => format!(
|
||||
"{status} [Unknown key: '{key}'. Press 'h' for instructions. (unimplemented)]"
|
||||
|
@ -536,6 +582,14 @@ impl<'a> Pager<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn paging_add_back_message(options: &Options, stdout: &mut std::io::Stdout) -> UResult<()> {
|
||||
if options.lines.is_some() {
|
||||
execute!(stdout, MoveUp(1))?;
|
||||
stdout.write_all("\n\r...back 1 page\n".as_bytes())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Break the lines on the cols of the terminal
|
||||
fn break_buff(buff: &str, cols: usize) -> Vec<String> {
|
||||
let mut lines = Vec::with_capacity(buff.lines().count());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mv"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mv ~ (uutils) move (rename) SOURCE to DESTINATION"
|
||||
|
@ -15,10 +15,10 @@ edition = "2021"
|
|||
path = "src/mv.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
fs_extra = { workspace=true }
|
||||
indicatif = { workspace=true }
|
||||
uucore = { workspace=true, features=["fs"] }
|
||||
clap = { workspace = true }
|
||||
fs_extra = { workspace = true }
|
||||
indicatif = { workspace = true }
|
||||
uucore = { workspace = true, features = ["fs"] }
|
||||
|
||||
[[bin]]
|
||||
name = "mv"
|
||||
|
|
|
@ -22,10 +22,10 @@ use std::os::unix;
|
|||
#[cfg(windows)]
|
||||
use std::os::windows;
|
||||
use std::path::{Path, PathBuf};
|
||||
use uucore::backup_control::{self, BackupMode};
|
||||
use uucore::backup_control::{self, source_is_target_backup, BackupMode};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{set_exit_code, FromIo, UError, UResult, USimpleError, UUsageError};
|
||||
use uucore::fs::are_hardlinks_to_same_file;
|
||||
use uucore::fs::{are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file};
|
||||
use uucore::update_control::{self, UpdateMode};
|
||||
use uucore::{format_usage, help_about, help_section, help_usage, prompt_yes, show};
|
||||
|
||||
|
@ -251,12 +251,25 @@ fn parse_paths(files: &[OsString], b: &Behavior) -> Vec<PathBuf> {
|
|||
}
|
||||
|
||||
fn handle_two_paths(source: &Path, target: &Path, b: &Behavior) -> UResult<()> {
|
||||
if b.backup == BackupMode::SimpleBackup && source_is_target_backup(source, target, &b.suffix) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!(
|
||||
"backing up {} might destroy source; {} not moved",
|
||||
target.quote(),
|
||||
source.quote()
|
||||
),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
if source.symlink_metadata().is_err() {
|
||||
return Err(MvError::NoSuchFile(source.quote().to_string()).into());
|
||||
}
|
||||
|
||||
if (source.eq(target) || are_hardlinks_to_same_file(source, target))
|
||||
&& b.backup != BackupMode::SimpleBackup
|
||||
if (source.eq(target)
|
||||
|| are_hardlinks_to_same_file(source, target)
|
||||
|| are_hardlinks_or_one_way_symlink_to_same_file(source, target))
|
||||
&& b.backup == BackupMode::NoBackup
|
||||
{
|
||||
if source.eq(Path::new(".")) || source.ends_with("/.") || source.is_file() {
|
||||
return Err(
|
||||
|
@ -387,7 +400,7 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
|
|||
}
|
||||
|
||||
match rename(sourcepath, &targetpath, b, multi_progress.as_ref()) {
|
||||
Err(e) if e.to_string() == "" => set_exit_code(1),
|
||||
Err(e) if e.to_string().is_empty() => set_exit_code(1),
|
||||
Err(e) => {
|
||||
let e = e.map_err_context(|| {
|
||||
format!(
|
||||
|
@ -420,9 +433,7 @@ fn rename(
|
|||
let mut backup_path = None;
|
||||
|
||||
if to.exists() {
|
||||
if (b.update == UpdateMode::ReplaceIfOlder || b.update == UpdateMode::ReplaceNone)
|
||||
&& b.overwrite == OverwriteMode::Interactive
|
||||
{
|
||||
if b.update == UpdateMode::ReplaceIfOlder && b.overwrite == OverwriteMode::Interactive {
|
||||
// `mv -i --update old new` when `new` exists doesn't move anything
|
||||
// and exit with 0
|
||||
return Ok(());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_nice"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "nice ~ (uutils) run PROGRAM with modified scheduling priority"
|
||||
|
@ -15,10 +15,10 @@ edition = "2021"
|
|||
path = "src/nice.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
libc = { workspace=true }
|
||||
nix = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
nix = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "nice"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_nl"
|
||||
version = "0.0.18"
|
||||
version = "0.0.20"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "nl ~ (uutils) display input with added line numbers"
|
||||
|
@ -15,9 +15,9 @@ edition = "2021"
|
|||
path = "src/nl.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace=true }
|
||||
regex = { workspace=true }
|
||||
uucore = { workspace=true }
|
||||
clap = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "nl"
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
#nl
|
||||
# nl
|
||||
|
||||
```
|
||||
nl [OPTION]... [FILE]...
|
||||
```
|
||||
|
||||
Number lines of files
|
||||
|
||||
## After Help
|
||||
|
||||
`STYLE` is one of:
|
||||
|
||||
* `a` number all lines
|
||||
* `t` number only nonempty lines
|
||||
* `n` number no lines
|
||||
* `pBRE` number only lines that contain a match for the basic regular
|
||||
expression, `BRE`
|
||||
|
||||
`FORMAT` is one of:
|
||||
|
||||
* `ln` left justified, no leading zeros
|
||||
* `rn` right justified, no leading zeros
|
||||
* `rz` right justified, leading zeros
|
||||
|
|
|
@ -5,17 +5,15 @@ use crate::options;
|
|||
// parse_style parses a style string into a NumberingStyle.
|
||||
fn parse_style(chars: &[char]) -> Result<crate::NumberingStyle, String> {
|
||||
if chars.len() == 1 && chars[0] == 'a' {
|
||||
Ok(crate::NumberingStyle::NumberForAll)
|
||||
Ok(crate::NumberingStyle::All)
|
||||
} else if chars.len() == 1 && chars[0] == 't' {
|
||||
Ok(crate::NumberingStyle::NumberForNonEmpty)
|
||||
Ok(crate::NumberingStyle::NonEmpty)
|
||||
} else if chars.len() == 1 && chars[0] == 'n' {
|
||||
Ok(crate::NumberingStyle::NumberForNone)
|
||||
Ok(crate::NumberingStyle::None)
|
||||
} else if chars.len() > 1 && chars[0] == 'p' {
|
||||
let s: String = chars[1..].iter().cloned().collect();
|
||||
match regex::Regex::new(&s) {
|
||||
Ok(re) => Ok(crate::NumberingStyle::NumberForRegularExpression(Box::new(
|
||||
re,
|
||||
))),
|
||||
Ok(re) => Ok(crate::NumberingStyle::Regex(Box::new(re))),
|
||||
Err(_) => Err(String::from("Illegal regular expression")),
|
||||
}
|
||||
} else {
|
||||
|
@ -29,30 +27,14 @@ fn parse_style(chars: &[char]) -> Result<crate::NumberingStyle, String> {
|
|||
pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) -> Vec<String> {
|
||||
// This vector holds error messages encountered.
|
||||
let mut errs: Vec<String> = vec![];
|
||||
settings.renumber = !opts.contains_id(options::NO_RENUMBER);
|
||||
match opts.get_one::<String>(options::NUMBER_SEPARATOR) {
|
||||
None => {}
|
||||
Some(val) => {
|
||||
settings.number_separator = val.to_owned();
|
||||
}
|
||||
}
|
||||
match opts.get_one::<String>(options::NUMBER_FORMAT) {
|
||||
None => {}
|
||||
Some(val) => match val.as_str() {
|
||||
"ln" => {
|
||||
settings.number_format = crate::NumberFormat::Left;
|
||||
}
|
||||
"rn" => {
|
||||
settings.number_format = crate::NumberFormat::Right;
|
||||
}
|
||||
"rz" => {
|
||||
settings.number_format = crate::NumberFormat::RightZero;
|
||||
}
|
||||
_ => {
|
||||
errs.push(String::from("Illegal value for -n"));
|
||||
}
|
||||
},
|
||||
settings.renumber = opts.get_flag(options::NO_RENUMBER);
|
||||
if let Some(val) = opts.get_one::<String>(options::NUMBER_SEPARATOR) {
|
||||
settings.number_separator = val.to_owned();
|
||||
}
|
||||
settings.number_format = opts
|
||||
.get_one::<String>(options::NUMBER_FORMAT)
|
||||
.map(Into::into)
|
||||
.unwrap_or_default();
|
||||
match opts.get_one::<String>(options::BODY_NUMBERING) {
|
||||
None => {}
|
||||
Some(val) => {
|
||||
|
@ -95,53 +77,25 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) ->
|
|||
}
|
||||
}
|
||||
}
|
||||
match opts.get_one::<String>(options::LINE_INCREMENT) {
|
||||
match opts.get_one::<usize>(options::NUMBER_WIDTH) {
|
||||
None => {}
|
||||
Some(val) => {
|
||||
let conv: Option<u64> = val.parse().ok();
|
||||
match conv {
|
||||
None => {
|
||||
errs.push(String::from("Illegal value for -i"));
|
||||
}
|
||||
Some(num) => settings.line_increment = num,
|
||||
}
|
||||
}
|
||||
Some(num) if *num > 0 => settings.number_width = *num,
|
||||
Some(_) => errs.push(String::from(
|
||||
"Invalid line number field width: ‘0’: Numerical result out of range",
|
||||
)),
|
||||
}
|
||||
match opts.get_one::<String>(options::NUMBER_WIDTH) {
|
||||
match opts.get_one::<u64>(options::JOIN_BLANK_LINES) {
|
||||
None => {}
|
||||
Some(val) => {
|
||||
let conv: Option<usize> = val.parse().ok();
|
||||
match conv {
|
||||
None => {
|
||||
errs.push(String::from("Illegal value for -w"));
|
||||
}
|
||||
Some(num) => settings.number_width = num,
|
||||
}
|
||||
}
|
||||
Some(num) if *num > 0 => settings.join_blank_lines = *num,
|
||||
Some(_) => errs.push(String::from(
|
||||
"Invalid line number of blank lines: ‘0’: Numerical result out of range",
|
||||
)),
|
||||
}
|
||||
match opts.get_one::<String>(options::STARTING_LINE_NUMBER) {
|
||||
None => {}
|
||||
Some(val) => {
|
||||
let conv: Option<u64> = val.parse().ok();
|
||||
match conv {
|
||||
None => {
|
||||
errs.push(String::from("Illegal value for -v"));
|
||||
}
|
||||
Some(num) => settings.starting_line_number = num,
|
||||
}
|
||||
}
|
||||
if let Some(num) = opts.get_one::<i64>(options::LINE_INCREMENT) {
|
||||
settings.line_increment = *num;
|
||||
}
|
||||
match opts.get_one::<String>(options::JOIN_BLANK_LINES) {
|
||||
None => {}
|
||||
Some(val) => {
|
||||
let conv: Option<u64> = val.parse().ok();
|
||||
match conv {
|
||||
None => {
|
||||
errs.push(String::from("Illegal value for -l"));
|
||||
}
|
||||
Some(num) => settings.join_blank_lines = num,
|
||||
}
|
||||
}
|
||||
if let Some(num) = opts.get_one::<i64>(options::STARTING_LINE_NUMBER) {
|
||||
settings.starting_line_number = *num;
|
||||
}
|
||||
errs
|
||||
}
|
||||
|
|
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