mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge branch 'main' into tail_notify
This commit is contained in:
commit
7228902e55
196 changed files with 3582 additions and 1752 deletions
14
.github/workflows/CICD.yml
vendored
14
.github/workflows/CICD.yml
vendored
|
@ -67,7 +67,7 @@ jobs:
|
||||||
- name: Install `rust` toolchain
|
- name: Install `rust` toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: nightly-2022-03-21
|
toolchain: nightly
|
||||||
default: true
|
default: true
|
||||||
profile: minimal
|
profile: minimal
|
||||||
- name: Install `cargo-udeps`
|
- name: Install `cargo-udeps`
|
||||||
|
@ -86,7 +86,7 @@ jobs:
|
||||||
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
|
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
|
||||||
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
|
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
|
||||||
#
|
#
|
||||||
cargo +nightly-2022-03-21 udeps ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --all-targets &> udeps.log || cat udeps.log
|
cargo +nightly udeps ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --all-targets &> udeps.log || cat udeps.log
|
||||||
grep --ignore-case "all deps seem to have been used" udeps.log || { printf "%s\n" "::${fault_type} ::${fault_prefix}: \`cargo udeps\`: style violation (unused dependency found)" ; fault=true ; }
|
grep --ignore-case "all deps seem to have been used" udeps.log || { printf "%s\n" "::${fault_type} ::${fault_prefix}: \`cargo udeps\`: style violation (unused dependency found)" ; fault=true ; }
|
||||||
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
|
if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi
|
||||||
|
|
||||||
|
@ -483,7 +483,7 @@ jobs:
|
||||||
- name: Install `rust` toolchain
|
- name: Install `rust` toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: nightly-2022-03-21
|
toolchain: nightly
|
||||||
default: true
|
default: true
|
||||||
profile: minimal # minimal component installation (ie, no documentation)
|
profile: minimal # minimal component installation (ie, no documentation)
|
||||||
- name: Test
|
- name: Test
|
||||||
|
@ -759,7 +759,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
||||||
command: test
|
command: test
|
||||||
args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }}
|
args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }}
|
||||||
toolchain: ${{ env.RUST_MIN_SRV }}
|
toolchain: ${{ env.RUST_MIN_SRV }}
|
||||||
- name: Archive executable artifacts
|
- name: Archive executable artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
@ -935,7 +935,7 @@ jobs:
|
||||||
## VARs setup
|
## VARs setup
|
||||||
outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; }
|
outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; }
|
||||||
# toolchain
|
# toolchain
|
||||||
TOOLCHAIN="nightly-2022-03-21" ## default to "nightly" toolchain (required for certain required unstable compiler flags) ## !maint: refactor when stable channel has needed support
|
TOOLCHAIN="nightly" ## default to "nightly" toolchain (required for certain required unstable compiler flags) ## !maint: refactor when stable channel has needed support
|
||||||
# * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files
|
# * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files
|
||||||
case ${{ matrix.job.os }} in windows-*) TOOLCHAIN="$TOOLCHAIN-x86_64-pc-windows-gnu" ;; esac;
|
case ${{ matrix.job.os }} in windows-*) TOOLCHAIN="$TOOLCHAIN-x86_64-pc-windows-gnu" ;; esac;
|
||||||
# * use requested TOOLCHAIN if specified
|
# * use requested TOOLCHAIN if specified
|
||||||
|
@ -994,7 +994,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast -p uucore
|
args: --no-fail-fast -p uucore
|
||||||
env:
|
env:
|
||||||
CARGO_INCREMENTAL: "0"
|
CARGO_INCREMENTAL: "0"
|
||||||
RUSTC_WRAPPER: ""
|
RUSTC_WRAPPER: ""
|
||||||
|
@ -1016,7 +1016,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }}
|
args: --no-fail-fast ${{ steps.dep_vars.outputs.CARGO_UTILITY_LIST_OPTIONS }}
|
||||||
env:
|
env:
|
||||||
CARGO_INCREMENTAL: "0"
|
CARGO_INCREMENTAL: "0"
|
||||||
RUSTC_WRAPPER: ""
|
RUSTC_WRAPPER: ""
|
||||||
|
|
6
.github/workflows/GnuTests.yml
vendored
6
.github/workflows/GnuTests.yml
vendored
|
@ -25,7 +25,7 @@ jobs:
|
||||||
outputs path_GNU path_GNU_tests path_reference path_UUTILS
|
outputs path_GNU path_GNU_tests path_reference path_UUTILS
|
||||||
#
|
#
|
||||||
repo_default_branch="${{ github.event.repository.default_branch }}"
|
repo_default_branch="${{ github.event.repository.default_branch }}"
|
||||||
repo_GNU_ref="v9.0"
|
repo_GNU_ref="v9.1"
|
||||||
repo_reference_branch="${{ github.event.repository.default_branch }}"
|
repo_reference_branch="${{ github.event.repository.default_branch }}"
|
||||||
outputs repo_default_branch repo_GNU_ref repo_reference_branch
|
outputs repo_default_branch repo_GNU_ref repo_reference_branch
|
||||||
#
|
#
|
||||||
|
@ -216,12 +216,12 @@ jobs:
|
||||||
with:
|
with:
|
||||||
repository: 'coreutils/coreutils'
|
repository: 'coreutils/coreutils'
|
||||||
path: 'gnu'
|
path: 'gnu'
|
||||||
ref: 'v9.0'
|
ref: 'v9.1'
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Install `rust` toolchain
|
- name: Install `rust` toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: nightly-2022-03-21
|
toolchain: nightly
|
||||||
default: true
|
default: true
|
||||||
profile: minimal # minimal component installation (ie, no documentation)
|
profile: minimal # minimal component installation (ie, no documentation)
|
||||||
components: rustfmt
|
components: rustfmt
|
||||||
|
|
|
@ -179,3 +179,4 @@ Smigle00
|
||||||
anonymousknight
|
anonymousknight
|
||||||
kwantam
|
kwantam
|
||||||
nicoo
|
nicoo
|
||||||
|
gmnsii
|
||||||
|
|
|
@ -93,6 +93,7 @@ rollup
|
||||||
sed
|
sed
|
||||||
selinuxenabled
|
selinuxenabled
|
||||||
sestatus
|
sestatus
|
||||||
|
vdir
|
||||||
wslpath
|
wslpath
|
||||||
xargs
|
xargs
|
||||||
|
|
||||||
|
|
531
Cargo.lock
generated
531
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
13
Cargo.toml
13
Cargo.toml
|
@ -16,7 +16,7 @@ repository = "https://github.com/uutils/coreutils"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ feat_common_core = [
|
||||||
"cut",
|
"cut",
|
||||||
"date",
|
"date",
|
||||||
"df",
|
"df",
|
||||||
|
"dir",
|
||||||
"dircolors",
|
"dircolors",
|
||||||
"dirname",
|
"dirname",
|
||||||
"dd",
|
"dd",
|
||||||
|
@ -100,6 +101,7 @@ feat_common_core = [
|
||||||
"unexpand",
|
"unexpand",
|
||||||
"uniq",
|
"uniq",
|
||||||
"unlink",
|
"unlink",
|
||||||
|
"vdir",
|
||||||
"wc",
|
"wc",
|
||||||
"yes",
|
"yes",
|
||||||
]
|
]
|
||||||
|
@ -252,8 +254,7 @@ lazy_static = { version="1.3" }
|
||||||
textwrap = { version="0.15", features=["terminal_size"] }
|
textwrap = { version="0.15", features=["terminal_size"] }
|
||||||
uucore = { version=">=0.0.11", package="uucore", path="src/uucore" }
|
uucore = { version=">=0.0.11", package="uucore", path="src/uucore" }
|
||||||
selinux = { version="0.2", optional = true }
|
selinux = { version="0.2", optional = true }
|
||||||
ureq = "2.4.0"
|
zip = { version = "0.6.0", default_features=false, features=["deflate"] }
|
||||||
zip = { version = "0.5.13", default_features=false, features=["deflate"] }
|
|
||||||
# * uutils
|
# * uutils
|
||||||
uu_test = { optional=true, version="0.0.13", package="uu_test", path="src/uu/test" }
|
uu_test = { optional=true, version="0.0.13", package="uu_test", path="src/uu/test" }
|
||||||
#
|
#
|
||||||
|
@ -276,6 +277,7 @@ cut = { optional=true, version="0.0.13", package="uu_cut", path="src/uu/cut
|
||||||
date = { optional=true, version="0.0.13", package="uu_date", path="src/uu/date" }
|
date = { optional=true, version="0.0.13", package="uu_date", path="src/uu/date" }
|
||||||
dd = { optional=true, version="0.0.13", package="uu_dd", path="src/uu/dd" }
|
dd = { optional=true, version="0.0.13", package="uu_dd", path="src/uu/dd" }
|
||||||
df = { optional=true, version="0.0.13", package="uu_df", path="src/uu/df" }
|
df = { optional=true, version="0.0.13", package="uu_df", path="src/uu/df" }
|
||||||
|
dir = { optional=true, version="0.0.13", package="uu_dir", path="src/uu/dir" }
|
||||||
dircolors= { optional=true, version="0.0.13", package="uu_dircolors", path="src/uu/dircolors" }
|
dircolors= { optional=true, version="0.0.13", package="uu_dircolors", path="src/uu/dircolors" }
|
||||||
dirname = { optional=true, version="0.0.13", package="uu_dirname", path="src/uu/dirname" }
|
dirname = { optional=true, version="0.0.13", package="uu_dirname", path="src/uu/dirname" }
|
||||||
du = { optional=true, version="0.0.13", package="uu_du", path="src/uu/du" }
|
du = { optional=true, version="0.0.13", package="uu_du", path="src/uu/du" }
|
||||||
|
@ -352,6 +354,7 @@ uniq = { optional=true, version="0.0.13", package="uu_uniq", path="src/uu/un
|
||||||
unlink = { optional=true, version="0.0.13", package="uu_unlink", path="src/uu/unlink" }
|
unlink = { optional=true, version="0.0.13", package="uu_unlink", path="src/uu/unlink" }
|
||||||
uptime = { optional=true, version="0.0.13", package="uu_uptime", path="src/uu/uptime" }
|
uptime = { optional=true, version="0.0.13", package="uu_uptime", path="src/uu/uptime" }
|
||||||
users = { optional=true, version="0.0.13", package="uu_users", path="src/uu/users" }
|
users = { optional=true, version="0.0.13", package="uu_users", path="src/uu/users" }
|
||||||
|
vdir = { optional=true, version="0.0.13", package="uu_vdir", path="src/uu/vdir" }
|
||||||
wc = { optional=true, version="0.0.13", package="uu_wc", path="src/uu/wc" }
|
wc = { optional=true, version="0.0.13", package="uu_wc", path="src/uu/wc" }
|
||||||
who = { optional=true, version="0.0.13", package="uu_who", path="src/uu/who" }
|
who = { optional=true, version="0.0.13", package="uu_who", path="src/uu/who" }
|
||||||
whoami = { optional=true, version="0.0.13", package="uu_whoami", path="src/uu/whoami" }
|
whoami = { optional=true, version="0.0.13", package="uu_whoami", path="src/uu/whoami" }
|
||||||
|
@ -373,7 +376,7 @@ glob = "0.3.0"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
pretty_assertions = "1"
|
pretty_assertions = "1"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
regex = "1.0"
|
regex = "1.5"
|
||||||
sha1 = { version="0.10", features=["std"] }
|
sha1 = { version="0.10", features=["std"] }
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
|
@ -384,7 +387,7 @@ atty = "0.2"
|
||||||
hex-literal = "0.3.1"
|
hex-literal = "0.3.1"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dev-dependencies]
|
[target.'cfg(target_os = "linux")'.dev-dependencies]
|
||||||
rlimit = "0.4.0"
|
rlimit = "0.8.3"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dev-dependencies]
|
[target.'cfg(unix)'.dev-dependencies]
|
||||||
nix = "0.23.1"
|
nix = "0.23.1"
|
||||||
|
|
28
GNUmakefile
28
GNUmakefile
|
@ -1,4 +1,4 @@
|
||||||
# spell-checker:ignore (misc) testsuite runtest findstring (targets) busytest distclean manpages pkgs ; (vars/env) BINDIR BUILDDIR CARGOFLAGS DESTDIR DOCSDIR INSTALLDIR INSTALLEES MANDIR MULTICALL
|
# spell-checker:ignore (misc) testsuite runtest findstring (targets) busytest distclean manpages pkgs ; (vars/env) BINDIR BUILDDIR CARGOFLAGS DESTDIR DOCSDIR INSTALLDIR INSTALLEES MULTICALL DATAROOTDIR
|
||||||
|
|
||||||
# Config options
|
# Config options
|
||||||
PROFILE ?= debug
|
PROFILE ?= debug
|
||||||
|
@ -22,10 +22,10 @@ CARGOFLAGS ?=
|
||||||
# Install directories
|
# Install directories
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
BINDIR ?= /bin
|
BINDIR ?= $(PREFIX)/bin
|
||||||
MANDIR ?= /man/man1
|
DATAROOTDIR ?= $(PREFIX)/share
|
||||||
|
|
||||||
INSTALLDIR_BIN=$(DESTDIR)$(PREFIX)$(BINDIR)
|
INSTALLDIR_BIN=$(DESTDIR)$(BINDIR)
|
||||||
|
|
||||||
#prefix to apply to coreutils binary and all tool binaries
|
#prefix to apply to coreutils binary and all tool binaries
|
||||||
PROG_PREFIX ?=
|
PROG_PREFIX ?=
|
||||||
|
@ -65,6 +65,7 @@ PROGS := \
|
||||||
date \
|
date \
|
||||||
dd \
|
dd \
|
||||||
df \
|
df \
|
||||||
|
dir \
|
||||||
dircolors \
|
dircolors \
|
||||||
dirname \
|
dirname \
|
||||||
echo \
|
echo \
|
||||||
|
@ -118,6 +119,7 @@ PROGS := \
|
||||||
tsort \
|
tsort \
|
||||||
unexpand \
|
unexpand \
|
||||||
uniq \
|
uniq \
|
||||||
|
vdir \
|
||||||
wc \
|
wc \
|
||||||
whoami \
|
whoami \
|
||||||
yes
|
yes
|
||||||
|
@ -328,13 +330,13 @@ else
|
||||||
$(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog);)
|
$(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog);)
|
||||||
$(if $(findstring test,$(INSTALLEES)), $(INSTALL) $(BUILDDIR)/test $(INSTALLDIR_BIN)/$(PROG_PREFIX)[)
|
$(if $(findstring test,$(INSTALLEES)), $(INSTALL) $(BUILDDIR)/test $(INSTALLDIR_BIN)/$(PROG_PREFIX)[)
|
||||||
endif
|
endif
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/share/zsh/site-functions
|
mkdir -p $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/share/bash-completion/completions
|
mkdir -p $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d
|
mkdir -p $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d
|
||||||
$(foreach prog, $(INSTALLEES), \
|
$(foreach prog, $(INSTALLEES), \
|
||||||
$(BUILDDIR)/coreutils completion $(prog) zsh > $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(PROG_PREFIX)$(prog); \
|
$(BUILDDIR)/coreutils completion $(prog) zsh > $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions/_$(PROG_PREFIX)$(prog); \
|
||||||
$(BUILDDIR)/coreutils completion $(prog) bash > $(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(PROG_PREFIX)$(prog); \
|
$(BUILDDIR)/coreutils completion $(prog) bash > $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/$(PROG_PREFIX)$(prog); \
|
||||||
$(BUILDDIR)/coreutils completion $(prog) fish > $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/$(PROG_PREFIX)$(prog).fish; \
|
$(BUILDDIR)/coreutils completion $(prog) fish > $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/$(PROG_PREFIX)$(prog).fish; \
|
||||||
)
|
)
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
|
@ -343,8 +345,8 @@ ifeq (${MULTICALL}, y)
|
||||||
endif
|
endif
|
||||||
rm -f $(addprefix $(INSTALLDIR_BIN)/$(PROG_PREFIX),$(PROGS))
|
rm -f $(addprefix $(INSTALLDIR_BIN)/$(PROG_PREFIX),$(PROGS))
|
||||||
rm -f $(INSTALLDIR_BIN)/$(PROG_PREFIX)[
|
rm -f $(INSTALLDIR_BIN)/$(PROG_PREFIX)[
|
||||||
rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(PROG_PREFIX),$(PROGS))
|
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions/_$(PROG_PREFIX),$(PROGS))
|
||||||
rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(PROG_PREFIX),$(PROGS))
|
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/$(PROG_PREFIX),$(PROGS))
|
||||||
rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS)))
|
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS)))
|
||||||
|
|
||||||
.PHONY: all build build-coreutils build-pkgs test distclean clean busytest install uninstall
|
.PHONY: all build build-coreutils build-pkgs test distclean clean busytest install uninstall
|
||||||
|
|
15
README.md
15
README.md
|
@ -385,6 +385,7 @@ To improve the GNU compatibility, the following process is recommended:
|
||||||
1. Start to modify `<your test>` to understand what is wrong. Examples:
|
1. Start to modify `<your test>` to understand what is wrong. Examples:
|
||||||
1. Add `set -v` to have the bash verbose mode
|
1. Add `set -v` to have the bash verbose mode
|
||||||
1. Add `echo $?` where needed
|
1. Add `echo $?` where needed
|
||||||
|
1. When the variable `fail` is used in the test, `echo $fail` to see when the test started to fail
|
||||||
1. Bump the content of the output (ex: `cat err`)
|
1. Bump the content of the output (ex: `cat err`)
|
||||||
1. ...
|
1. ...
|
||||||
1. Or, if the test is simple, extract the relevant information to create a new test case running both GNU & Rust implementation
|
1. Or, if the test is simple, extract the relevant information to create a new test case running both GNU & Rust implementation
|
||||||
|
@ -398,7 +399,15 @@ To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md).
|
||||||
|
|
||||||
## Utilities
|
## Utilities
|
||||||
|
|
||||||
| Done | Semi-Done | To Do |
|
Please note that this is not fully accurate:
|
||||||
|
* Some new options can be added / removed in the GNU implementation;
|
||||||
|
* Some error management might be missing;
|
||||||
|
* Some behaviors might be different.
|
||||||
|
|
||||||
|
See https://github.com/uutils/coreutils/issues/3336 for the main meta bugs
|
||||||
|
(many are missing).
|
||||||
|
|
||||||
|
| Done | WIP | To Do |
|
||||||
|-----------|-----------|--------|
|
|-----------|-----------|--------|
|
||||||
| arch | cp | stty |
|
| arch | cp | stty |
|
||||||
| base32 | date | |
|
| base32 | date | |
|
||||||
|
@ -417,8 +426,8 @@ To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md).
|
||||||
| cut | tac | |
|
| cut | tac | |
|
||||||
| dircolors | tail | |
|
| dircolors | tail | |
|
||||||
| dirname | test | |
|
| dirname | test | |
|
||||||
| du | | |
|
| du | dir | |
|
||||||
| echo | | |
|
| echo | vdir | |
|
||||||
| env | | |
|
| env | | |
|
||||||
| expand | | |
|
| expand | | |
|
||||||
| factor | | |
|
| factor | | |
|
||||||
|
|
1
docs/.gitignore
vendored
1
docs/.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
book
|
book
|
||||||
src/utils
|
src/utils
|
||||||
src/SUMMARY.md
|
src/SUMMARY.md
|
||||||
|
tldr.zip
|
11
docs/theme/head.hbs
vendored
11
docs/theme/head.hbs
vendored
|
@ -5,10 +5,17 @@
|
||||||
main {
|
main {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.version {
|
.additional {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 1em;
|
top: 0.5em;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
.platforms {
|
||||||
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
dd > p {
|
dd > p {
|
||||||
margin-top: 0.2em;
|
margin-top: 0.2em;
|
||||||
|
|
363
src/bin/uudoc.rs
363
src/bin/uudoc.rs
|
@ -5,23 +5,26 @@
|
||||||
// spell-checker:ignore tldr
|
// spell-checker:ignore tldr
|
||||||
|
|
||||||
use clap::Command;
|
use clap::Command;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Cursor;
|
|
||||||
use std::io::{self, Read, Seek, Write};
|
use std::io::{self, Read, Seek, Write};
|
||||||
use zip::ZipArchive;
|
use zip::ZipArchive;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));
|
include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
fn main() -> io::Result<()> {
|
||||||
println!("Downloading tldr archive");
|
let mut tldr_zip = File::open("docs/tldr.zip")
|
||||||
let mut zip_reader = ureq::get("https://tldr.sh/assets/tldr.zip")
|
.ok()
|
||||||
.call()
|
.and_then(|f| ZipArchive::new(f).ok());
|
||||||
.unwrap()
|
|
||||||
.into_reader();
|
if tldr_zip.is_none() {
|
||||||
let mut buffer = Vec::new();
|
println!("Warning: No tldr archive found, so the documentation will not include examples.");
|
||||||
zip_reader.read_to_end(&mut buffer).unwrap();
|
println!("To include examples in the documentation, download the tldr archive and put it in the docs/ folder.");
|
||||||
let mut tldr_zip = ZipArchive::new(Cursor::new(buffer)).unwrap();
|
println!();
|
||||||
|
println!(" curl https://tldr.sh/assets/tldr.zip -o docs/tldr.zip");
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
let utils = util_map::<Box<dyn Iterator<Item = OsString>>>();
|
let utils = util_map::<Box<dyn Iterator<Item = OsString>>>();
|
||||||
match std::fs::create_dir("docs/src/utils/") {
|
match std::fs::create_dir("docs/src/utils/") {
|
||||||
|
@ -29,6 +32,7 @@ fn main() -> io::Result<()> {
|
||||||
x => x,
|
x => x,
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
println!("Writing initial info to SUMMARY.md");
|
||||||
let mut summary = File::create("docs/src/SUMMARY.md")?;
|
let mut summary = File::create("docs/src/SUMMARY.md")?;
|
||||||
|
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
|
@ -44,6 +48,40 @@ fn main() -> io::Result<()> {
|
||||||
* [Multi-call binary](multicall.md)\n",
|
* [Multi-call binary](multicall.md)\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
println!("Gathering utils per platform");
|
||||||
|
let utils_per_platform = {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
for platform in ["unix", "macos", "windows"] {
|
||||||
|
let platform_utils: Vec<String> = String::from_utf8(
|
||||||
|
std::process::Command::new("./util/show-utils.sh")
|
||||||
|
.arg(format!("--features=feat_os_{}", platform))
|
||||||
|
.output()?
|
||||||
|
.stdout,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.split(' ')
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect();
|
||||||
|
map.insert(platform, platform_utils);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linux is a special case because it can support selinux
|
||||||
|
let platform_utils: Vec<String> = String::from_utf8(
|
||||||
|
std::process::Command::new("./util/show-utils.sh")
|
||||||
|
.arg("--features=feat_os_unix feat_selinux")
|
||||||
|
.output()?
|
||||||
|
.stdout,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.split(' ')
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect();
|
||||||
|
map.insert("linux", platform_utils);
|
||||||
|
|
||||||
|
map
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Writing to utils");
|
||||||
let mut utils = utils.entries().collect::<Vec<_>>();
|
let mut utils = utils.entries().collect::<Vec<_>>();
|
||||||
utils.sort();
|
utils.sort();
|
||||||
for (&name, (_, command)) in utils {
|
for (&name, (_, command)) in utils {
|
||||||
|
@ -52,7 +90,14 @@ fn main() -> io::Result<()> {
|
||||||
}
|
}
|
||||||
let p = format!("docs/src/utils/{}.md", name);
|
let p = format!("docs/src/utils/{}.md", name);
|
||||||
if let Ok(f) = File::create(&p) {
|
if let Ok(f) = File::create(&p) {
|
||||||
write_markdown(f, &mut command(), name, &mut tldr_zip)?;
|
MDWriter {
|
||||||
|
w: Box::new(f),
|
||||||
|
command: command(),
|
||||||
|
name,
|
||||||
|
tldr_zip: &mut tldr_zip,
|
||||||
|
utils_per_platform: &utils_per_platform,
|
||||||
|
}
|
||||||
|
.markdown()?;
|
||||||
println!("Wrote to '{}'", p);
|
println!("Wrote to '{}'", p);
|
||||||
} else {
|
} else {
|
||||||
println!("Error writing to {}", p);
|
println!("Error writing to {}", p);
|
||||||
|
@ -62,88 +107,186 @@ fn main() -> io::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_markdown(
|
struct MDWriter<'a, 'b> {
|
||||||
mut w: impl Write,
|
w: Box<dyn Write>,
|
||||||
command: &mut Command,
|
command: Command<'a>,
|
||||||
name: &str,
|
name: &'a str,
|
||||||
tldr_zip: &mut zip::ZipArchive<impl Read + Seek>,
|
tldr_zip: &'b mut Option<ZipArchive<File>>,
|
||||||
) -> io::Result<()> {
|
utils_per_platform: &'b HashMap<&'b str, Vec<String>>,
|
||||||
write!(w, "# {}\n\n", name)?;
|
|
||||||
write_version(&mut w, command)?;
|
|
||||||
write_usage(&mut w, command, name)?;
|
|
||||||
write_description(&mut w, command)?;
|
|
||||||
write_options(&mut w, command)?;
|
|
||||||
write_examples(&mut w, name, tldr_zip)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_version(w: &mut impl Write, command: &Command) -> io::Result<()> {
|
impl<'a, 'b> MDWriter<'a, 'b> {
|
||||||
writeln!(
|
fn markdown(&mut self) -> io::Result<()> {
|
||||||
w,
|
write!(self.w, "# {}\n\n", self.name)?;
|
||||||
"<div class=\"version\">version: {}</div>",
|
self.additional()?;
|
||||||
command.render_version().split_once(' ').unwrap().1
|
self.usage()?;
|
||||||
)
|
self.description()?;
|
||||||
}
|
self.options()?;
|
||||||
|
self.examples()
|
||||||
|
}
|
||||||
|
|
||||||
fn write_usage(w: &mut impl Write, command: &mut Command, name: &str) -> io::Result<()> {
|
fn additional(&mut self) -> io::Result<()> {
|
||||||
writeln!(w, "\n```")?;
|
writeln!(self.w, "<div class=\"additional\">")?;
|
||||||
let mut usage: String = command
|
self.platforms()?;
|
||||||
.render_usage()
|
self.version()?;
|
||||||
.lines()
|
writeln!(self.w, "</div>")
|
||||||
.skip(1)
|
}
|
||||||
.map(|l| l.trim())
|
|
||||||
.filter(|l| !l.is_empty())
|
fn platforms(&mut self) -> io::Result<()> {
|
||||||
.collect::<Vec<_>>()
|
writeln!(self.w, "<div class=\"platforms\">")?;
|
||||||
.join("\n");
|
for (feature, icon) in [
|
||||||
usage = usage.replace(uucore::execution_phrase(), name);
|
("linux", "linux"),
|
||||||
writeln!(w, "{}", usage)?;
|
// freebsd is disabled for now because mdbook does not use font-awesome 5 yet.
|
||||||
writeln!(w, "```")
|
// ("unix", "freebsd"),
|
||||||
}
|
("macos", "apple"),
|
||||||
|
("windows", "windows"),
|
||||||
|
] {
|
||||||
|
if self.name.contains("sum")
|
||||||
|
|| self.utils_per_platform[feature]
|
||||||
|
.iter()
|
||||||
|
.any(|u| u == self.name)
|
||||||
|
{
|
||||||
|
writeln!(self.w, "<i class=\"fa fa-brands fa-{}\"></i>", icon)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(self.w, "</div>")?;
|
||||||
|
|
||||||
fn write_description(w: &mut impl Write, command: &Command) -> io::Result<()> {
|
|
||||||
if let Some(about) = command.get_long_about().or_else(|| command.get_about()) {
|
|
||||||
writeln!(w, "{}", about)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn write_examples(
|
fn version(&mut self) -> io::Result<()> {
|
||||||
w: &mut impl Write,
|
writeln!(
|
||||||
name: &str,
|
self.w,
|
||||||
tldr_zip: &mut zip::ZipArchive<impl Read + Seek>,
|
"<div class=\"version\">v{}</div>",
|
||||||
) -> io::Result<()> {
|
self.command.render_version().split_once(' ').unwrap().1
|
||||||
let content = if let Some(f) = get_zip_content(tldr_zip, &format!("pages/common/{}.md", name)) {
|
)
|
||||||
f
|
}
|
||||||
} else if let Some(f) = get_zip_content(tldr_zip, &format!("pages/linux/{}.md", name)) {
|
|
||||||
f
|
|
||||||
} else {
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
writeln!(w, "## Examples")?;
|
fn usage(&mut self) -> io::Result<()> {
|
||||||
writeln!(w)?;
|
writeln!(self.w, "\n```")?;
|
||||||
for line in content.lines().skip_while(|l| !l.starts_with('-')) {
|
let mut usage: String = self
|
||||||
if let Some(l) = line.strip_prefix("- ") {
|
.command
|
||||||
writeln!(w, "{}", l)?;
|
.render_usage()
|
||||||
} else if line.starts_with('`') {
|
.lines()
|
||||||
writeln!(w, "```shell\n{}\n```", line.trim_matches('`'))?;
|
.skip(1)
|
||||||
} else if line.is_empty() {
|
.map(|l| l.trim())
|
||||||
writeln!(w)?;
|
.filter(|l| !l.is_empty())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
usage = usage.replace(uucore::execution_phrase(), self.name);
|
||||||
|
writeln!(self.w, "{}", usage)?;
|
||||||
|
writeln!(self.w, "```")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&mut self) -> io::Result<()> {
|
||||||
|
if let Some(about) = self
|
||||||
|
.command
|
||||||
|
.get_long_about()
|
||||||
|
.or_else(|| self.command.get_about())
|
||||||
|
{
|
||||||
|
writeln!(self.w, "{}", about)
|
||||||
} else {
|
} else {
|
||||||
println!("Not sure what to do with this line:");
|
Ok(())
|
||||||
println!("{}", line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(w)?;
|
|
||||||
writeln!(
|
fn examples(&mut self) -> io::Result<()> {
|
||||||
w,
|
if let Some(zip) = self.tldr_zip {
|
||||||
"> The examples are provided by the [tldr-pages project](https://tldr.sh) under the [CC BY 4.0 License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md)."
|
let content = if let Some(f) =
|
||||||
)?;
|
get_zip_content(zip, &format!("pages/common/{}.md", self.name))
|
||||||
writeln!(w, ">")?;
|
{
|
||||||
writeln!(
|
f
|
||||||
w,
|
} else if let Some(f) = get_zip_content(zip, &format!("pages/linux/{}.md", self.name)) {
|
||||||
"> Please note that, as uutils is a work in progress, some examples might fail."
|
f
|
||||||
)
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
writeln!(self.w, "## Examples")?;
|
||||||
|
writeln!(self.w)?;
|
||||||
|
for line in content.lines().skip_while(|l| !l.starts_with('-')) {
|
||||||
|
if let Some(l) = line.strip_prefix("- ") {
|
||||||
|
writeln!(self.w, "{}", l)?;
|
||||||
|
} else if line.starts_with('`') {
|
||||||
|
writeln!(self.w, "```shell\n{}\n```", line.trim_matches('`'))?;
|
||||||
|
} else if line.is_empty() {
|
||||||
|
writeln!(self.w)?;
|
||||||
|
} else {
|
||||||
|
println!("Not sure what to do with this line:");
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(self.w)?;
|
||||||
|
writeln!(
|
||||||
|
self.w,
|
||||||
|
"> The examples are provided by the [tldr-pages project](https://tldr.sh) under the [CC BY 4.0 License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md)."
|
||||||
|
)?;
|
||||||
|
writeln!(self.w, ">")?;
|
||||||
|
writeln!(
|
||||||
|
self.w,
|
||||||
|
"> Please note that, as uutils is a work in progress, some examples might fail."
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn options(&mut self) -> io::Result<()> {
|
||||||
|
writeln!(self.w, "<h2>Options</h2>")?;
|
||||||
|
write!(self.w, "<dl>")?;
|
||||||
|
for arg in self.command.get_arguments() {
|
||||||
|
write!(self.w, "<dt>")?;
|
||||||
|
let mut first = true;
|
||||||
|
for l in arg.get_long_and_visible_aliases().unwrap_or_default() {
|
||||||
|
if !first {
|
||||||
|
write!(self.w, ", ")?;
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
write!(self.w, "<code>")?;
|
||||||
|
write!(self.w, "--{}", l)?;
|
||||||
|
if let Some(names) = arg.get_value_names() {
|
||||||
|
write!(
|
||||||
|
self.w,
|
||||||
|
"={}",
|
||||||
|
names
|
||||||
|
.iter()
|
||||||
|
.map(|x| format!("<{}>", x))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
write!(self.w, "</code>")?;
|
||||||
|
}
|
||||||
|
for s in arg.get_short_and_visible_aliases().unwrap_or_default() {
|
||||||
|
if !first {
|
||||||
|
write!(self.w, ", ")?;
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
write!(self.w, "<code>")?;
|
||||||
|
write!(self.w, "-{}", s)?;
|
||||||
|
if let Some(names) = arg.get_value_names() {
|
||||||
|
write!(
|
||||||
|
self.w,
|
||||||
|
" {}",
|
||||||
|
names
|
||||||
|
.iter()
|
||||||
|
.map(|x| format!("<{}>", x))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
write!(self.w, "</code>")?;
|
||||||
|
}
|
||||||
|
writeln!(self.w, "</dt>")?;
|
||||||
|
writeln!(
|
||||||
|
self.w,
|
||||||
|
"<dd>\n\n{}\n\n</dd>",
|
||||||
|
arg.get_help().unwrap_or_default().replace('\n', "<br />")
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
writeln!(self.w, "</dl>\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Option<String> {
|
fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Option<String> {
|
||||||
|
@ -151,61 +294,3 @@ fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Op
|
||||||
archive.by_name(name).ok()?.read_to_string(&mut s).unwrap();
|
archive.by_name(name).ok()?.read_to_string(&mut s).unwrap();
|
||||||
Some(s)
|
Some(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_options(w: &mut impl Write, command: &Command) -> io::Result<()> {
|
|
||||||
writeln!(w, "<h2>Options</h2>")?;
|
|
||||||
write!(w, "<dl>")?;
|
|
||||||
for arg in command.get_arguments() {
|
|
||||||
write!(w, "<dt>")?;
|
|
||||||
let mut first = true;
|
|
||||||
for l in arg.get_long_and_visible_aliases().unwrap_or_default() {
|
|
||||||
if !first {
|
|
||||||
write!(w, ", ")?;
|
|
||||||
} else {
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
write!(w, "<code>")?;
|
|
||||||
write!(w, "--{}", l)?;
|
|
||||||
if let Some(names) = arg.get_value_names() {
|
|
||||||
write!(
|
|
||||||
w,
|
|
||||||
"={}",
|
|
||||||
names
|
|
||||||
.iter()
|
|
||||||
.map(|x| format!("<{}>", x))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" ")
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
write!(w, "</code>")?;
|
|
||||||
}
|
|
||||||
for s in arg.get_short_and_visible_aliases().unwrap_or_default() {
|
|
||||||
if !first {
|
|
||||||
write!(w, ", ")?;
|
|
||||||
} else {
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
write!(w, "<code>")?;
|
|
||||||
write!(w, "-{}", s)?;
|
|
||||||
if let Some(names) = arg.get_value_names() {
|
|
||||||
write!(
|
|
||||||
w,
|
|
||||||
" {}",
|
|
||||||
names
|
|
||||||
.iter()
|
|
||||||
.map(|x| format!("<{}>", x))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" ")
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
write!(w, "</code>")?;
|
|
||||||
}
|
|
||||||
writeln!(w, "</dt>")?;
|
|
||||||
writeln!(
|
|
||||||
w,
|
|
||||||
"<dd>\n\n{}\n\n</dd>",
|
|
||||||
arg.get_help().unwrap_or_default().replace('\n', "<br />")
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
writeln!(w, "</dl>\n")
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/arch"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/arch"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/arch.rs"
|
path = "src/arch.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/base32"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/base32"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/base32.rs"
|
path = "src/base32.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/base64"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/base64"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/base64.rs"
|
path = "src/base64.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/basename"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/basename"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/basename.rs"
|
path = "src/basename.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/basenc"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/basenc"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/basenc.rs"
|
path = "src/basenc.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cat"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cat"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/cat.rs"
|
path = "src/cat.rs"
|
||||||
|
|
|
@ -8,7 +8,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chcon"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chcon"
|
||||||
keywords = ["coreutils", "uutils", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/chcon.rs"
|
path = "src/chcon.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chgrp"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chgrp"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/chgrp.rs"
|
path = "src/chgrp.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chmod"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chmod"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/chmod.rs"
|
path = "src/chmod.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chown"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chown"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/chown.rs"
|
path = "src/chown.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chroot"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chroot"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/chroot.rs"
|
path = "src/chroot.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cksum"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cksum"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/cksum.rs"
|
path = "src/cksum.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/comm"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/comm"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/comm.rs"
|
path = "src/comm.rs"
|
||||||
|
|
|
@ -13,7 +13,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cp"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cp"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/cp.rs"
|
path = "src/cp.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ls"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ls"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/csplit.rs"
|
path = "src/csplit.rs"
|
||||||
|
@ -17,7 +17,7 @@ path = "src/csplit.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
regex = "1.0.0"
|
regex = "1.5.5"
|
||||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["entries", "fs"] }
|
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["entries", "fs"] }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cut"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cut"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/cut.rs"
|
path = "src/cut.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/date"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/date"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/date.rs"
|
path = "src/date.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dd"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dd"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/dd.rs"
|
path = "src/dd.rs"
|
||||||
|
|
|
@ -23,7 +23,6 @@ mod blocks;
|
||||||
use blocks::conv_block_unblock_helper;
|
use blocks::conv_block_unblock_helper;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::{self, Read, Seek, Write};
|
use std::io::{self, Read, Seek, Write};
|
||||||
|
|
|
@ -10,7 +10,7 @@ fn unimplemented_flags_should_error_non_linux() {
|
||||||
let mut succeeded = Vec::new();
|
let mut succeeded = Vec::new();
|
||||||
|
|
||||||
// The following flags are only implemented in linux
|
// The following flags are only implemented in linux
|
||||||
for &flag in &[
|
for flag in [
|
||||||
"direct",
|
"direct",
|
||||||
"directory",
|
"directory",
|
||||||
"dsync",
|
"dsync",
|
||||||
|
@ -47,7 +47,7 @@ fn unimplemented_flags_should_error() {
|
||||||
let mut succeeded = Vec::new();
|
let mut succeeded = Vec::new();
|
||||||
|
|
||||||
// The following flags are not implemented
|
// The following flags are not implemented
|
||||||
for &flag in &["cio", "nocache", "nolinks", "text", "binary"] {
|
for flag in ["cio", "nocache", "nolinks", "text", "binary"] {
|
||||||
let args = vec![
|
let args = vec![
|
||||||
String::from("dd"),
|
String::from("dd"),
|
||||||
format!("--iflag={}", flag),
|
format!("--iflag={}", flag),
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/df"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/df"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/df.rs"
|
path = "src/df.rs"
|
||||||
|
|
|
@ -183,4 +183,31 @@ impl Column {
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the alignment of the specified column.
|
||||||
|
pub(crate) fn alignment(column: &Self) -> Alignment {
|
||||||
|
match column {
|
||||||
|
Self::Source | Self::Target | Self::File | Self::Fstype => Alignment::Left,
|
||||||
|
_ => Alignment::Right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the minimum width of the specified column.
|
||||||
|
pub(crate) fn min_width(column: &Self) -> usize {
|
||||||
|
match column {
|
||||||
|
// 14 = length of "Filesystem" plus 4 spaces
|
||||||
|
Self::Source => 14,
|
||||||
|
// the shortest headers have a length of 4 chars so we use that as the minimum width
|
||||||
|
_ => 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A column's alignment.
|
||||||
|
///
|
||||||
|
/// We define our own `Alignment` enum instead of using `std::fmt::Alignment` because df doesn't
|
||||||
|
/// have centered columns and hence a `Center` variant is not needed.
|
||||||
|
pub(crate) enum Alignment {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ mod filesystem;
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UError, UResult};
|
use uucore::error::{UError, UResult, USimpleError};
|
||||||
use uucore::format_usage;
|
|
||||||
use uucore::fsext::{read_fs_list, MountInfo};
|
use uucore::fsext::{read_fs_list, MountInfo};
|
||||||
|
use uucore::{format_usage, show};
|
||||||
|
|
||||||
use clap::{crate_version, Arg, ArgMatches, Command};
|
use clap::{crate_version, Arg, ArgMatches, Command};
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ use std::path::Path;
|
||||||
use crate::blocks::{block_size_from_matches, BlockSize};
|
use crate::blocks::{block_size_from_matches, BlockSize};
|
||||||
use crate::columns::{Column, ColumnError};
|
use crate::columns::{Column, ColumnError};
|
||||||
use crate::filesystem::Filesystem;
|
use crate::filesystem::Filesystem;
|
||||||
use crate::table::{DisplayRow, Header, Row};
|
use crate::table::Table;
|
||||||
|
|
||||||
static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
|
static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
|
||||||
or all file systems by default.";
|
or all file systems by default.";
|
||||||
|
@ -61,7 +61,6 @@ static OUTPUT_FIELD_LIST: [&str; 12] = [
|
||||||
struct Options {
|
struct Options {
|
||||||
show_local_fs: bool,
|
show_local_fs: bool,
|
||||||
show_all_fs: bool,
|
show_all_fs: bool,
|
||||||
show_listed_fs: bool,
|
|
||||||
block_size: BlockSize,
|
block_size: BlockSize,
|
||||||
|
|
||||||
/// Optional list of filesystem types to include in the output table.
|
/// Optional list of filesystem types to include in the output table.
|
||||||
|
@ -88,7 +87,6 @@ impl Default for Options {
|
||||||
Self {
|
Self {
|
||||||
show_local_fs: Default::default(),
|
show_local_fs: Default::default(),
|
||||||
show_all_fs: Default::default(),
|
show_all_fs: Default::default(),
|
||||||
show_listed_fs: Default::default(),
|
|
||||||
block_size: Default::default(),
|
block_size: Default::default(),
|
||||||
include: Default::default(),
|
include: Default::default(),
|
||||||
exclude: Default::default(),
|
exclude: Default::default(),
|
||||||
|
@ -111,6 +109,8 @@ enum OptionsError {
|
||||||
|
|
||||||
/// An error getting the columns to display in the output table.
|
/// An error getting the columns to display in the output table.
|
||||||
ColumnError(ColumnError),
|
ColumnError(ColumnError),
|
||||||
|
|
||||||
|
FilesystemTypeBothSelectedAndExcluded(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for OptionsError {
|
impl fmt::Display for OptionsError {
|
||||||
|
@ -126,6 +126,16 @@ impl fmt::Display for OptionsError {
|
||||||
"option --output: field {} used more than once",
|
"option --output: field {} used more than once",
|
||||||
s.quote()
|
s.quote()
|
||||||
),
|
),
|
||||||
|
Self::FilesystemTypeBothSelectedAndExcluded(types) => {
|
||||||
|
for t in types {
|
||||||
|
eprintln!(
|
||||||
|
"{}: file system type {} both selected and excluded",
|
||||||
|
uucore::util_name(),
|
||||||
|
t.quote()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,18 +143,38 @@ impl fmt::Display for OptionsError {
|
||||||
impl Options {
|
impl Options {
|
||||||
/// Convert command-line arguments into [`Options`].
|
/// Convert command-line arguments into [`Options`].
|
||||||
fn from(matches: &ArgMatches) -> Result<Self, OptionsError> {
|
fn from(matches: &ArgMatches) -> Result<Self, OptionsError> {
|
||||||
|
let include = matches.values_of_lossy(OPT_TYPE);
|
||||||
|
let exclude = matches.values_of_lossy(OPT_EXCLUDE_TYPE);
|
||||||
|
|
||||||
|
if let (Some(include), Some(exclude)) = (&include, &exclude) {
|
||||||
|
if let Some(types) = Self::get_intersected_types(include, exclude) {
|
||||||
|
return Err(OptionsError::FilesystemTypeBothSelectedAndExcluded(types));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
show_local_fs: matches.is_present(OPT_LOCAL),
|
show_local_fs: matches.is_present(OPT_LOCAL),
|
||||||
show_all_fs: matches.is_present(OPT_ALL),
|
show_all_fs: matches.is_present(OPT_ALL),
|
||||||
show_listed_fs: false,
|
|
||||||
block_size: block_size_from_matches(matches)
|
block_size: block_size_from_matches(matches)
|
||||||
.map_err(|_| OptionsError::InvalidBlockSize)?,
|
.map_err(|_| OptionsError::InvalidBlockSize)?,
|
||||||
include: matches.values_of_lossy(OPT_TYPE),
|
include,
|
||||||
exclude: matches.values_of_lossy(OPT_EXCLUDE_TYPE),
|
exclude,
|
||||||
show_total: matches.is_present(OPT_TOTAL),
|
show_total: matches.is_present(OPT_TOTAL),
|
||||||
columns: Column::from_matches(matches).map_err(OptionsError::ColumnError)?,
|
columns: Column::from_matches(matches).map_err(OptionsError::ColumnError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_intersected_types(include: &[String], exclude: &[String]) -> Option<Vec<String>> {
|
||||||
|
let mut intersected_types = Vec::new();
|
||||||
|
|
||||||
|
for t in include {
|
||||||
|
if exclude.contains(t) {
|
||||||
|
intersected_types.push(t.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(!intersected_types.is_empty()).then(|| intersected_types)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to display the mount info given the inclusion settings.
|
/// Whether to display the mount info given the inclusion settings.
|
||||||
|
@ -155,7 +185,7 @@ fn is_included(mi: &MountInfo, opt: &Options) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't show pseudo filesystems unless `--all` has been given.
|
// Don't show pseudo filesystems unless `--all` has been given.
|
||||||
if mi.dummy && !opt.show_all_fs && !opt.show_listed_fs {
|
if mi.dummy && !opt.show_all_fs {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,10 +308,17 @@ where
|
||||||
|
|
||||||
// Convert each path into a `Filesystem`, which contains
|
// Convert each path into a `Filesystem`, which contains
|
||||||
// both the mount information and usage information.
|
// both the mount information and usage information.
|
||||||
paths
|
let mut result = vec![];
|
||||||
.iter()
|
for path in paths {
|
||||||
.filter_map(|p| Filesystem::from_path(&mounts, p))
|
match Filesystem::from_path(&mounts, path) {
|
||||||
.collect()
|
Some(fs) => result.push(fs),
|
||||||
|
None => show!(USimpleError::new(
|
||||||
|
1,
|
||||||
|
format!("{}: No such file or directory", path.as_ref().display())
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -309,6 +346,7 @@ impl fmt::Display for DfError {
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let matches = uu_app().get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
if matches.is_present(OPT_INODES) {
|
if matches.is_present(OPT_INODES) {
|
||||||
|
@ -318,36 +356,38 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let opt = Options::from(&matches).map_err(DfError::OptionsError)?;
|
let opt = Options::from(&matches).map_err(DfError::OptionsError)?;
|
||||||
|
|
||||||
// Get the list of filesystems to display in the output table.
|
// Get the list of filesystems to display in the output table.
|
||||||
let filesystems: Vec<Filesystem> = match matches.values_of(OPT_PATHS) {
|
let filesystems: Vec<Filesystem> = match matches.values_of(OPT_PATHS) {
|
||||||
None => get_all_filesystems(&opt),
|
None => {
|
||||||
|
let filesystems = get_all_filesystems(&opt);
|
||||||
|
|
||||||
|
if filesystems.is_empty() {
|
||||||
|
return Err(USimpleError::new(1, "No file systems processed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystems
|
||||||
|
}
|
||||||
Some(paths) => {
|
Some(paths) => {
|
||||||
let paths: Vec<&str> = paths.collect();
|
let paths: Vec<&str> = paths.collect();
|
||||||
get_named_filesystems(&paths)
|
let filesystems = get_named_filesystems(&paths);
|
||||||
|
|
||||||
|
// This can happen if paths are given as command-line arguments
|
||||||
|
// but none of the paths exist.
|
||||||
|
if filesystems.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystems
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The running total of filesystem sizes and usage.
|
// This can happen if paths are given as command-line arguments
|
||||||
//
|
// but none of the paths exist.
|
||||||
// This accumulator is computed in case we need to display the
|
if filesystems.is_empty() {
|
||||||
// total counts in the last row of the table.
|
return Ok(());
|
||||||
let mut total = Row::new("total");
|
}
|
||||||
|
|
||||||
println!("{}", Header::new(&opt));
|
println!("{}", Table::new(&opt, filesystems));
|
||||||
for filesystem in filesystems {
|
|
||||||
// If the filesystem is not empty, or if the options require
|
|
||||||
// showing all filesystems, then print the data as a row in
|
|
||||||
// the output table.
|
|
||||||
if opt.show_all_fs || opt.show_listed_fs || filesystem.usage.blocks > 0 {
|
|
||||||
let row = Row::from(filesystem);
|
|
||||||
println!("{}", DisplayRow::new(&row, &opt));
|
|
||||||
total += row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if opt.show_total {
|
|
||||||
println!("{}", DisplayRow::new(&total, &opt));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -367,6 +407,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
Arg::new(OPT_ALL)
|
Arg::new(OPT_ALL)
|
||||||
.short('a')
|
.short('a')
|
||||||
.long("all")
|
.long("all")
|
||||||
|
.overrides_with(OPT_ALL)
|
||||||
.help("include dummy file systems"),
|
.help("include dummy file systems"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -374,47 +415,56 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
.short('B')
|
.short('B')
|
||||||
.long("block-size")
|
.long("block-size")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
|
.overrides_with_all(&[OPT_KILO, OPT_BLOCKSIZE])
|
||||||
.help(
|
.help(
|
||||||
"scale sizes by SIZE before printing them; e.g.\
|
"scale sizes by SIZE before printing them; e.g.\
|
||||||
'-BM' prints sizes in units of 1,048,576 bytes",
|
'-BM' prints sizes in units of 1,048,576 bytes",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_TOTAL)
|
Arg::new(OPT_TOTAL)
|
||||||
.long("total")
|
.long("total")
|
||||||
|
.overrides_with(OPT_TOTAL)
|
||||||
.help("produce a grand total"),
|
.help("produce a grand total"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_HUMAN_READABLE_BINARY)
|
Arg::new(OPT_HUMAN_READABLE_BINARY)
|
||||||
.short('h')
|
.short('h')
|
||||||
.long("human-readable")
|
.long("human-readable")
|
||||||
.conflicts_with(OPT_HUMAN_READABLE_DECIMAL)
|
.overrides_with_all(&[OPT_HUMAN_READABLE_DECIMAL, OPT_HUMAN_READABLE_BINARY])
|
||||||
.help("print sizes in human readable format (e.g., 1K 234M 2G)"),
|
.help("print sizes in human readable format (e.g., 1K 234M 2G)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_HUMAN_READABLE_DECIMAL)
|
Arg::new(OPT_HUMAN_READABLE_DECIMAL)
|
||||||
.short('H')
|
.short('H')
|
||||||
.long("si")
|
.long("si")
|
||||||
.conflicts_with(OPT_HUMAN_READABLE_BINARY)
|
.overrides_with_all(&[OPT_HUMAN_READABLE_BINARY, OPT_HUMAN_READABLE_DECIMAL])
|
||||||
.help("likewise, but use powers of 1000 not 1024"),
|
.help("likewise, but use powers of 1000 not 1024"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_INODES)
|
Arg::new(OPT_INODES)
|
||||||
.short('i')
|
.short('i')
|
||||||
.long("inodes")
|
.long("inodes")
|
||||||
|
.overrides_with(OPT_INODES)
|
||||||
.help("list inode information instead of block usage"),
|
.help("list inode information instead of block usage"),
|
||||||
)
|
)
|
||||||
.arg(Arg::new(OPT_KILO).short('k').help("like --block-size=1K"))
|
.arg(
|
||||||
|
Arg::new(OPT_KILO)
|
||||||
|
.short('k')
|
||||||
|
.help("like --block-size=1K")
|
||||||
|
.overrides_with_all(&[OPT_BLOCKSIZE, OPT_KILO]),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_LOCAL)
|
Arg::new(OPT_LOCAL)
|
||||||
.short('l')
|
.short('l')
|
||||||
.long("local")
|
.long("local")
|
||||||
|
.overrides_with(OPT_LOCAL)
|
||||||
.help("limit listing to local file systems"),
|
.help("limit listing to local file systems"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_NO_SYNC)
|
Arg::new(OPT_NO_SYNC)
|
||||||
.long("no-sync")
|
.long("no-sync")
|
||||||
.conflicts_with(OPT_SYNC)
|
.overrides_with_all(&[OPT_SYNC, OPT_NO_SYNC])
|
||||||
.help("do not invoke sync before getting usage info (default)"),
|
.help("do not invoke sync before getting usage info (default)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -438,12 +488,13 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
Arg::new(OPT_PORTABILITY)
|
Arg::new(OPT_PORTABILITY)
|
||||||
.short('P')
|
.short('P')
|
||||||
.long("portability")
|
.long("portability")
|
||||||
|
.overrides_with(OPT_PORTABILITY)
|
||||||
.help("use the POSIX output format"),
|
.help("use the POSIX output format"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_SYNC)
|
Arg::new(OPT_SYNC)
|
||||||
.long("sync")
|
.long("sync")
|
||||||
.conflicts_with(OPT_NO_SYNC)
|
.overrides_with_all(&[OPT_NO_SYNC, OPT_SYNC])
|
||||||
.help("invoke sync before getting usage info"),
|
.help("invoke sync before getting usage info"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -459,6 +510,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
Arg::new(OPT_PRINT_TYPE)
|
Arg::new(OPT_PRINT_TYPE)
|
||||||
.short('T')
|
.short('T')
|
||||||
.long("print-type")
|
.long("print-type")
|
||||||
|
.overrides_with(OPT_PRINT_TYPE)
|
||||||
.help("print file system type"),
|
.help("print file system type"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -612,7 +664,6 @@ mod tests {
|
||||||
fn test_dummy_included() {
|
fn test_dummy_included() {
|
||||||
let opt = Options {
|
let opt = Options {
|
||||||
show_all_fs: true,
|
show_all_fs: true,
|
||||||
show_listed_fs: true,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let m = mount_info("ext4", "/mnt/foo", false, true);
|
let m = mount_info("ext4", "/mnt/foo", false, true);
|
||||||
|
@ -708,22 +759,6 @@ mod tests {
|
||||||
let m = mount_info("ext4", "/mnt/foo", false, false);
|
let m = mount_info("ext4", "/mnt/foo", false, false);
|
||||||
assert!(is_included(&m, &opt));
|
assert!(is_included(&m, &opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_include_and_exclude_match_both() {
|
|
||||||
// TODO The same filesystem type in both `include` and
|
|
||||||
// `exclude` should cause an error, but currently does
|
|
||||||
// not.
|
|
||||||
let include = Some(vec![String::from("ext4")]);
|
|
||||||
let exclude = Some(vec![String::from("ext4")]);
|
|
||||||
let opt = Options {
|
|
||||||
include,
|
|
||||||
exclude,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let m = mount_info("ext4", "/mnt/foo", false, false);
|
|
||||||
assert!(!is_included(&m, &opt));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod filter_mount_list {
|
mod filter_mount_list {
|
||||||
|
|
|
@ -5,13 +5,11 @@
|
||||||
// spell-checker:ignore tmpfs Pcent Itotal Iused Iavail Ipcent
|
// spell-checker:ignore tmpfs Pcent Itotal Iused Iavail Ipcent
|
||||||
//! The filesystem usage data table.
|
//! The filesystem usage data table.
|
||||||
//!
|
//!
|
||||||
//! A table comprises a header row ([`Header`]) and a collection of
|
//! A table ([`Table`]) comprises a header row ([`Header`]) and a
|
||||||
//! data rows ([`Row`]), one per filesystem. To display a [`Row`],
|
//! collection of data rows ([`Row`]), one per filesystem.
|
||||||
//! combine it with [`Options`] in the [`DisplayRow`] struct; the
|
|
||||||
//! [`DisplayRow`] implements [`std::fmt::Display`].
|
|
||||||
use number_prefix::NumberPrefix;
|
use number_prefix::NumberPrefix;
|
||||||
|
|
||||||
use crate::columns::Column;
|
use crate::columns::{Alignment, Column};
|
||||||
use crate::filesystem::Filesystem;
|
use crate::filesystem::Filesystem;
|
||||||
use crate::{BlockSize, Options};
|
use crate::{BlockSize, Options};
|
||||||
use uucore::fsext::{FsUsage, MountInfo};
|
use uucore::fsext::{FsUsage, MountInfo};
|
||||||
|
@ -154,6 +152,7 @@ impl From<Filesystem> for Row {
|
||||||
..
|
..
|
||||||
} = fs.usage;
|
} = fs.usage;
|
||||||
let bused = blocks - bfree;
|
let bused = blocks - bfree;
|
||||||
|
let fused = files - ffree;
|
||||||
Self {
|
Self {
|
||||||
file: fs.file,
|
file: fs.file,
|
||||||
fs_device: dev_name,
|
fs_device: dev_name,
|
||||||
|
@ -177,25 +176,25 @@ impl From<Filesystem> for Row {
|
||||||
Some(bavail as f64 / ((bused + bavail) as f64))
|
Some(bavail as f64 / ((bused + bavail) as f64))
|
||||||
},
|
},
|
||||||
inodes: files,
|
inodes: files,
|
||||||
inodes_used: files - ffree,
|
inodes_used: fused,
|
||||||
inodes_free: ffree,
|
inodes_free: ffree,
|
||||||
inodes_usage: if files == 0 {
|
inodes_usage: if files == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(ffree as f64 / files as f64)
|
Some(fused as f64 / files as f64)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A displayable wrapper around a [`Row`].
|
/// A formatter for [`Row`].
|
||||||
///
|
///
|
||||||
/// The `options` control how the information in the row gets displayed.
|
/// The `options` control how the information in the row gets formatted.
|
||||||
pub(crate) struct DisplayRow<'a> {
|
pub(crate) struct RowFormatter<'a> {
|
||||||
/// The data in this row.
|
/// The data in this row.
|
||||||
row: &'a Row,
|
row: &'a Row,
|
||||||
|
|
||||||
/// Options that control how to display the data.
|
/// Options that control how to format the data.
|
||||||
options: &'a Options,
|
options: &'a Options,
|
||||||
// TODO We don't need all of the command-line options here. Some
|
// TODO We don't need all of the command-line options here. Some
|
||||||
// of the command-line options indicate which rows to include or
|
// of the command-line options indicate which rows to include or
|
||||||
|
@ -206,28 +205,48 @@ pub(crate) struct DisplayRow<'a> {
|
||||||
// `df.rs` module.
|
// `df.rs` module.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DisplayRow<'a> {
|
impl<'a> RowFormatter<'a> {
|
||||||
/// Instantiate this struct.
|
/// Instantiate this struct.
|
||||||
pub(crate) fn new(row: &'a Row, options: &'a Options) -> Self {
|
pub(crate) fn new(row: &'a Row, options: &'a Options) -> Self {
|
||||||
Self { row, options }
|
Self { row, options }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a string giving the scaled version of the input number.
|
/// Get a human readable string giving the scaled version of the input number.
|
||||||
///
|
///
|
||||||
/// The scaling factor is defined in the `options` field.
|
/// The scaling factor is defined in the `options` field.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// This function is supposed to be used by `scaled_bytes()` and `scaled_inodes()` only.
|
||||||
///
|
fn scaled_human_readable(&self, size: u64) -> String {
|
||||||
/// If the scaling factor is not 1000, 1024, or a negative number.
|
|
||||||
fn scaled(&self, size: u64) -> Result<String, fmt::Error> {
|
|
||||||
let number_prefix = match self.options.block_size {
|
let number_prefix = match self.options.block_size {
|
||||||
BlockSize::HumanReadableDecimal => NumberPrefix::decimal(size as f64),
|
BlockSize::HumanReadableDecimal => NumberPrefix::decimal(size as f64),
|
||||||
BlockSize::HumanReadableBinary => NumberPrefix::binary(size as f64),
|
BlockSize::HumanReadableBinary => NumberPrefix::binary(size as f64),
|
||||||
BlockSize::Bytes(d) => return Ok((size / d).to_string()),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
match number_prefix {
|
match number_prefix {
|
||||||
NumberPrefix::Standalone(bytes) => Ok(bytes.to_string()),
|
NumberPrefix::Standalone(bytes) => bytes.to_string(),
|
||||||
NumberPrefix::Prefixed(prefix, bytes) => Ok(format!("{:.1}{}", bytes, prefix.symbol())),
|
NumberPrefix::Prefixed(prefix, bytes) => format!("{:.1}{}", bytes, prefix.symbol()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a string giving the scaled version of the input number.
|
||||||
|
///
|
||||||
|
/// The scaling factor is defined in the `options` field.
|
||||||
|
fn scaled_bytes(&self, size: u64) -> String {
|
||||||
|
if let BlockSize::Bytes(d) = self.options.block_size {
|
||||||
|
(size / d).to_string()
|
||||||
|
} else {
|
||||||
|
self.scaled_human_readable(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a string giving the scaled version of the input number.
|
||||||
|
///
|
||||||
|
/// The scaling factor is defined in the `options` field.
|
||||||
|
fn scaled_inodes(&self, size: u64) -> String {
|
||||||
|
if let BlockSize::Bytes(_) = self.options.block_size {
|
||||||
|
size.to_string()
|
||||||
|
} else {
|
||||||
|
self.scaled_human_readable(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,82 +259,163 @@ impl<'a> DisplayRow<'a> {
|
||||||
Some(x) => format!("{:.0}%", (100.0 * x).ceil()),
|
Some(x) => format!("{:.0}%", (100.0 * x).ceil()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for DisplayRow<'_> {
|
/// Returns formatted row data.
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn get_values(&self) -> Vec<String> {
|
||||||
|
let mut strings = Vec::new();
|
||||||
|
|
||||||
for column in &self.options.columns {
|
for column in &self.options.columns {
|
||||||
match column {
|
let string = match column {
|
||||||
Column::Source => write!(f, "{0: <16} ", self.row.fs_device)?,
|
Column::Source => self.row.fs_device.to_string(),
|
||||||
Column::Size => write!(f, "{0: >12} ", self.scaled(self.row.bytes)?)?,
|
Column::Size => self.scaled_bytes(self.row.bytes),
|
||||||
Column::Used => write!(f, "{0: >12} ", self.scaled(self.row.bytes_used)?)?,
|
Column::Used => self.scaled_bytes(self.row.bytes_used),
|
||||||
Column::Avail => write!(f, "{0: >12} ", self.scaled(self.row.bytes_avail)?)?,
|
Column::Avail => self.scaled_bytes(self.row.bytes_avail),
|
||||||
Column::Pcent => {
|
Column::Pcent => Self::percentage(self.row.bytes_usage),
|
||||||
write!(f, "{0: >5} ", DisplayRow::percentage(self.row.bytes_usage))?;
|
|
||||||
}
|
Column::Target => self.row.fs_mount.to_string(),
|
||||||
Column::Target => write!(f, "{0: <16}", self.row.fs_mount)?,
|
Column::Itotal => self.scaled_inodes(self.row.inodes),
|
||||||
Column::Itotal => write!(f, "{0: >12} ", self.scaled(self.row.inodes)?)?,
|
Column::Iused => self.scaled_inodes(self.row.inodes_used),
|
||||||
Column::Iused => write!(f, "{0: >12} ", self.scaled(self.row.inodes_used)?)?,
|
Column::Iavail => self.scaled_inodes(self.row.inodes_free),
|
||||||
Column::Iavail => write!(f, "{0: >12} ", self.scaled(self.row.inodes_free)?)?,
|
Column::Ipcent => Self::percentage(self.row.inodes_usage),
|
||||||
Column::Ipcent => {
|
Column::File => self.row.file.as_ref().unwrap_or(&"-".into()).to_string(),
|
||||||
write!(f, "{0: >5} ", DisplayRow::percentage(self.row.inodes_usage))?;
|
|
||||||
}
|
Column::Fstype => self.row.fs_type.to_string(),
|
||||||
Column::File => {
|
|
||||||
write!(f, "{0: <16}", self.row.file.as_ref().unwrap_or(&"-".into()))?;
|
|
||||||
}
|
|
||||||
Column::Fstype => write!(f, "{0: <5} ", self.row.fs_type)?,
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
Column::Capacity => write!(
|
Column::Capacity => Self::percentage(self.row.bytes_capacity),
|
||||||
f,
|
};
|
||||||
"{0: >12} ",
|
|
||||||
DisplayRow::percentage(self.row.bytes_capacity)
|
strings.push(string);
|
||||||
)?,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
|
strings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The header row.
|
/// The data of the header row.
|
||||||
///
|
struct Header {}
|
||||||
/// The `options` control which columns are displayed.
|
|
||||||
pub(crate) struct Header<'a> {
|
|
||||||
/// Options that control which columns are displayed.
|
|
||||||
options: &'a Options,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Header<'a> {
|
impl Header {
|
||||||
/// Instantiate this struct.
|
/// Return the headers for the specified columns.
|
||||||
pub(crate) fn new(options: &'a Options) -> Self {
|
///
|
||||||
Self { options }
|
/// The `options` control which column headers are returned.
|
||||||
|
fn get_headers(options: &Options) -> Vec<String> {
|
||||||
|
let mut headers = Vec::new();
|
||||||
|
|
||||||
|
for column in &options.columns {
|
||||||
|
let header = match column {
|
||||||
|
Column::Source => String::from("Filesystem"),
|
||||||
|
Column::Size => options.block_size.to_string(),
|
||||||
|
Column::Used => String::from("Used"),
|
||||||
|
Column::Avail => String::from("Available"),
|
||||||
|
Column::Pcent => String::from("Use%"),
|
||||||
|
Column::Target => String::from("Mounted on"),
|
||||||
|
Column::Itotal => String::from("Inodes"),
|
||||||
|
Column::Iused => String::from("IUsed"),
|
||||||
|
Column::Iavail => String::from("IFree"),
|
||||||
|
Column::Ipcent => String::from("IUse%"),
|
||||||
|
Column::File => String::from("File"),
|
||||||
|
Column::Fstype => String::from("Type"),
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
Column::Capacity => String::from("Capacity"),
|
||||||
|
};
|
||||||
|
|
||||||
|
headers.push(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
headers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Header<'_> {
|
/// The output table.
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
pub(crate) struct Table {
|
||||||
for column in &self.options.columns {
|
alignments: Vec<Alignment>,
|
||||||
match column {
|
rows: Vec<Vec<String>>,
|
||||||
Column::Source => write!(f, "{0: <16} ", "Filesystem")?,
|
widths: Vec<usize>,
|
||||||
// `Display` is implemented for `BlockSize`, but
|
}
|
||||||
// `Display` only works when formatting an object into
|
|
||||||
// an empty format, `{}`. So we use `format!()` first
|
impl Table {
|
||||||
// to create the string, then use `write!()` to align
|
pub(crate) fn new(options: &Options, filesystems: Vec<Filesystem>) -> Self {
|
||||||
// the string and pad with spaces.
|
let headers = Header::get_headers(options);
|
||||||
Column::Size => write!(f, "{0: >12} ", format!("{}", self.options.block_size))?,
|
let mut widths: Vec<_> = options
|
||||||
Column::Used => write!(f, "{0: >12} ", "Used")?,
|
.columns
|
||||||
Column::Avail => write!(f, "{0: >12} ", "Available")?,
|
.iter()
|
||||||
Column::Pcent => write!(f, "{0: >5} ", "Use%")?,
|
.enumerate()
|
||||||
Column::Target => write!(f, "{0: <16} ", "Mounted on")?,
|
.map(|(i, col)| Column::min_width(col).max(headers[i].len()))
|
||||||
Column::Itotal => write!(f, "{0: >12} ", "Inodes")?,
|
.collect();
|
||||||
Column::Iused => write!(f, "{0: >12} ", "IUsed")?,
|
|
||||||
Column::Iavail => write!(f, "{0: >12} ", "IFree")?,
|
let mut rows = vec![headers];
|
||||||
Column::Ipcent => write!(f, "{0: >5} ", "IUse%")?,
|
|
||||||
Column::File => write!(f, "{0: <16}", "File")?,
|
// The running total of filesystem sizes and usage.
|
||||||
Column::Fstype => write!(f, "{0: <5} ", "Type")?,
|
//
|
||||||
#[cfg(target_os = "macos")]
|
// This accumulator is computed in case we need to display the
|
||||||
Column::Capacity => write!(f, "{0: >12} ", "Capacity")?,
|
// total counts in the last row of the table.
|
||||||
|
let mut total = Row::new("total");
|
||||||
|
|
||||||
|
for filesystem in filesystems {
|
||||||
|
// If the filesystem is not empty, or if the options require
|
||||||
|
// showing all filesystems, then print the data as a row in
|
||||||
|
// the output table.
|
||||||
|
if options.show_all_fs || filesystem.usage.blocks > 0 {
|
||||||
|
let row = Row::from(filesystem);
|
||||||
|
let fmt = RowFormatter::new(&row, options);
|
||||||
|
let values = fmt.get_values();
|
||||||
|
total += row;
|
||||||
|
|
||||||
|
for (i, value) in values.iter().enumerate() {
|
||||||
|
if value.len() > widths[i] {
|
||||||
|
widths[i] = value.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.push(values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.show_total {
|
||||||
|
let total_row = RowFormatter::new(&total, options);
|
||||||
|
rows.push(total_row.get_values());
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
rows,
|
||||||
|
widths,
|
||||||
|
alignments: Self::get_alignments(&options.columns),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_alignments(columns: &Vec<Column>) -> Vec<Alignment> {
|
||||||
|
let mut alignments = Vec::new();
|
||||||
|
|
||||||
|
for column in columns {
|
||||||
|
alignments.push(Column::alignment(column));
|
||||||
|
}
|
||||||
|
|
||||||
|
alignments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Table {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut row_iter = self.rows.iter().peekable();
|
||||||
|
while let Some(row) = row_iter.next() {
|
||||||
|
let mut col_iter = row.iter().enumerate().peekable();
|
||||||
|
while let Some((i, elem)) = col_iter.next() {
|
||||||
|
match self.alignments[i] {
|
||||||
|
Alignment::Left => write!(f, "{:<width$}", elem, width = self.widths[i])?,
|
||||||
|
Alignment::Right => write!(f, "{:>width$}", elem, width = self.widths[i])?,
|
||||||
|
}
|
||||||
|
|
||||||
|
if col_iter.peek().is_some() {
|
||||||
|
// column separator
|
||||||
|
write!(f, " ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if row_iter.peek().is_some() {
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,7 +424,7 @@ impl fmt::Display for Header<'_> {
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::columns::Column;
|
use crate::columns::Column;
|
||||||
use crate::table::{DisplayRow, Header, Row};
|
use crate::table::{Header, Row, RowFormatter};
|
||||||
use crate::{BlockSize, Options};
|
use crate::{BlockSize, Options};
|
||||||
|
|
||||||
const COLUMNS_WITH_FS_TYPE: [Column; 7] = [
|
const COLUMNS_WITH_FS_TYPE: [Column; 7] = [
|
||||||
|
@ -346,76 +446,119 @@ mod tests {
|
||||||
];
|
];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display() {
|
fn test_default_header() {
|
||||||
let options = Default::default();
|
let options = Default::default();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Header::new(&options).to_string(),
|
Header::get_headers(&options),
|
||||||
"Filesystem 1K-blocks Used Available Use% Mounted on "
|
vec!(
|
||||||
|
"Filesystem",
|
||||||
|
"1K-blocks",
|
||||||
|
"Used",
|
||||||
|
"Available",
|
||||||
|
"Use%",
|
||||||
|
"Mounted on"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_fs_type() {
|
fn test_header_with_fs_type() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Header::new(&options).to_string(),
|
Header::get_headers(&options),
|
||||||
"Filesystem Type 1K-blocks Used Available Use% Mounted on "
|
vec!(
|
||||||
|
"Filesystem",
|
||||||
|
"Type",
|
||||||
|
"1K-blocks",
|
||||||
|
"Used",
|
||||||
|
"Available",
|
||||||
|
"Use%",
|
||||||
|
"Mounted on"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_inode() {
|
fn test_header_with_inodes() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
columns: COLUMNS_WITH_INODES.to_vec(),
|
columns: COLUMNS_WITH_INODES.to_vec(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Header::new(&options).to_string(),
|
Header::get_headers(&options),
|
||||||
"Filesystem Inodes IUsed IFree IUse% Mounted on "
|
vec!(
|
||||||
|
"Filesystem",
|
||||||
|
"Inodes",
|
||||||
|
"IUsed",
|
||||||
|
"IFree",
|
||||||
|
"IUse%",
|
||||||
|
"Mounted on"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_block_size_1024() {
|
fn test_header_with_block_size_1024() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::Bytes(3 * 1024),
|
block_size: BlockSize::Bytes(3 * 1024),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Header::new(&options).to_string(),
|
Header::get_headers(&options),
|
||||||
"Filesystem 3K-blocks Used Available Use% Mounted on "
|
vec!(
|
||||||
|
"Filesystem",
|
||||||
|
"3K-blocks",
|
||||||
|
"Used",
|
||||||
|
"Available",
|
||||||
|
"Use%",
|
||||||
|
"Mounted on"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_human_readable_binary() {
|
fn test_header_with_human_readable_binary() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::HumanReadableBinary,
|
block_size: BlockSize::HumanReadableBinary,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Header::new(&options).to_string(),
|
Header::get_headers(&options),
|
||||||
"Filesystem Size Used Available Use% Mounted on "
|
vec!(
|
||||||
|
"Filesystem",
|
||||||
|
"Size",
|
||||||
|
"Used",
|
||||||
|
"Available",
|
||||||
|
"Use%",
|
||||||
|
"Mounted on"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_human_readable_si() {
|
fn test_header_with_human_readable_si() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::HumanReadableDecimal,
|
block_size: BlockSize::HumanReadableDecimal,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Header::new(&options).to_string(),
|
Header::get_headers(&options),
|
||||||
"Filesystem Size Used Available Use% Mounted on "
|
vec!(
|
||||||
|
"Filesystem",
|
||||||
|
"Size",
|
||||||
|
"Used",
|
||||||
|
"Available",
|
||||||
|
"Use%",
|
||||||
|
"Mounted on"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display() {
|
fn test_row_formatter() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::Bytes(1),
|
block_size: BlockSize::Bytes(1),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -439,14 +582,15 @@ mod tests {
|
||||||
inodes_free: 8,
|
inodes_free: 8,
|
||||||
inodes_usage: Some(0.2),
|
inodes_usage: Some(0.2),
|
||||||
};
|
};
|
||||||
|
let fmt = RowFormatter::new(&row, &options);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayRow::new(&row, &options).to_string(),
|
fmt.get_values(),
|
||||||
"my_device 100 25 75 25% my_mount "
|
vec!("my_device", "100", "25", "75", "25%", "my_mount")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_fs_type() {
|
fn test_row_formatter_with_fs_type() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||||
block_size: BlockSize::Bytes(1),
|
block_size: BlockSize::Bytes(1),
|
||||||
|
@ -471,14 +615,15 @@ mod tests {
|
||||||
inodes_free: 8,
|
inodes_free: 8,
|
||||||
inodes_usage: Some(0.2),
|
inodes_usage: Some(0.2),
|
||||||
};
|
};
|
||||||
|
let fmt = RowFormatter::new(&row, &options);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayRow::new(&row, &options).to_string(),
|
fmt.get_values(),
|
||||||
"my_device my_type 100 25 75 25% my_mount "
|
vec!("my_device", "my_type", "100", "25", "75", "25%", "my_mount")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_inodes() {
|
fn test_row_formatter_with_inodes() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
columns: COLUMNS_WITH_INODES.to_vec(),
|
columns: COLUMNS_WITH_INODES.to_vec(),
|
||||||
block_size: BlockSize::Bytes(1),
|
block_size: BlockSize::Bytes(1),
|
||||||
|
@ -503,14 +648,45 @@ mod tests {
|
||||||
inodes_free: 8,
|
inodes_free: 8,
|
||||||
inodes_usage: Some(0.2),
|
inodes_usage: Some(0.2),
|
||||||
};
|
};
|
||||||
|
let fmt = RowFormatter::new(&row, &options);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayRow::new(&row, &options).to_string(),
|
fmt.get_values(),
|
||||||
"my_device 10 2 8 20% my_mount "
|
vec!("my_device", "10", "2", "8", "20%", "my_mount")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_human_readable_si() {
|
fn test_row_formatter_with_bytes_and_inodes() {
|
||||||
|
let options = Options {
|
||||||
|
columns: vec![Column::Size, Column::Itotal],
|
||||||
|
block_size: BlockSize::Bytes(100),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let row = Row {
|
||||||
|
file: Some("/path/to/file".to_string()),
|
||||||
|
fs_device: "my_device".to_string(),
|
||||||
|
fs_type: "my_type".to_string(),
|
||||||
|
fs_mount: "my_mount".to_string(),
|
||||||
|
|
||||||
|
bytes: 100,
|
||||||
|
bytes_used: 25,
|
||||||
|
bytes_avail: 75,
|
||||||
|
bytes_usage: Some(0.25),
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
bytes_capacity: Some(0.5),
|
||||||
|
|
||||||
|
inodes: 10,
|
||||||
|
inodes_used: 2,
|
||||||
|
inodes_free: 8,
|
||||||
|
inodes_usage: Some(0.2),
|
||||||
|
};
|
||||||
|
let fmt = RowFormatter::new(&row, &options);
|
||||||
|
assert_eq!(fmt.get_values(), vec!("1", "10"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_row_formatter_with_human_readable_si() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::HumanReadableDecimal,
|
block_size: BlockSize::HumanReadableDecimal,
|
||||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||||
|
@ -535,14 +711,23 @@ mod tests {
|
||||||
inodes_free: 8,
|
inodes_free: 8,
|
||||||
inodes_usage: Some(0.2),
|
inodes_usage: Some(0.2),
|
||||||
};
|
};
|
||||||
|
let fmt = RowFormatter::new(&row, &options);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayRow::new(&row, &options).to_string(),
|
fmt.get_values(),
|
||||||
"my_device my_type 4.0k 1.0k 3.0k 25% my_mount "
|
vec!(
|
||||||
|
"my_device",
|
||||||
|
"my_type",
|
||||||
|
"4.0k",
|
||||||
|
"1.0k",
|
||||||
|
"3.0k",
|
||||||
|
"25%",
|
||||||
|
"my_mount"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_human_readable_binary() {
|
fn test_row_formatter_with_human_readable_binary() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::HumanReadableBinary,
|
block_size: BlockSize::HumanReadableBinary,
|
||||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||||
|
@ -567,14 +752,23 @@ mod tests {
|
||||||
inodes_free: 8,
|
inodes_free: 8,
|
||||||
inodes_usage: Some(0.2),
|
inodes_usage: Some(0.2),
|
||||||
};
|
};
|
||||||
|
let fmt = RowFormatter::new(&row, &options);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayRow::new(&row, &options).to_string(),
|
fmt.get_values(),
|
||||||
"my_device my_type 4.0Ki 1.0Ki 3.0Ki 25% my_mount "
|
vec!(
|
||||||
|
"my_device",
|
||||||
|
"my_type",
|
||||||
|
"4.0Ki",
|
||||||
|
"1.0Ki",
|
||||||
|
"3.0Ki",
|
||||||
|
"25%",
|
||||||
|
"my_mount"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_round_up_usage() {
|
fn test_row_formatter_with_round_up_usage() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::Bytes(1),
|
block_size: BlockSize::Bytes(1),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -598,9 +792,10 @@ mod tests {
|
||||||
inodes_free: 8,
|
inodes_free: 8,
|
||||||
inodes_usage: Some(0.2),
|
inodes_usage: Some(0.2),
|
||||||
};
|
};
|
||||||
|
let fmt = RowFormatter::new(&row, &options);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DisplayRow::new(&row, &options).to_string(),
|
fmt.get_values(),
|
||||||
"my_device 100 25 75 26% my_mount "
|
vec!("my_device", "100", "25", "75", "26%", "my_mount")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
25
src/uu/dir/Cargo.toml
Normal file
25
src/uu/dir/Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "uu_dir"
|
||||||
|
version = "0.0.13"
|
||||||
|
authors = ["uutils developers"]
|
||||||
|
license = "MIT"
|
||||||
|
description = "shortcut to ls -C -b"
|
||||||
|
|
||||||
|
homepage = "https://github.com/uutils/coreutils"
|
||||||
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ls"
|
||||||
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
|
categories = ["command-line-utilities"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/dir.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "3.1", features = ["wrap_help", "cargo", "env"] }
|
||||||
|
uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore", features = ["entries", "fs"] }
|
||||||
|
selinux = { version="0.2", optional = true }
|
||||||
|
uu_ls = {path="../ls"}
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "dir"
|
||||||
|
path = "src/main.rs"
|
1
src/uu/dir/LICENSE
Symbolic link
1
src/uu/dir/LICENSE
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../../LICENSE
|
70
src/uu/dir/src/dir.rs
Normal file
70
src/uu/dir/src/dir.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// * This file is part of the uutils coreutils package.
|
||||||
|
// *
|
||||||
|
// * (c) gmnsii <gmnsii@protonmail.com>
|
||||||
|
// *
|
||||||
|
// * For the full copyright and license information, please view the LICENSE file
|
||||||
|
// * that was distributed with this source code.
|
||||||
|
|
||||||
|
use clap::Command;
|
||||||
|
use std::path::Path;
|
||||||
|
use uu_ls::quoting_style::{Quotes, QuotingStyle};
|
||||||
|
use uu_ls::{options, Config, Format};
|
||||||
|
use uucore::error::UResult;
|
||||||
|
|
||||||
|
#[uucore::main]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
let command = uu_ls::uu_app();
|
||||||
|
|
||||||
|
let matches = command.get_matches_from(args);
|
||||||
|
|
||||||
|
let mut default_quoting_style = false;
|
||||||
|
let mut default_format_style = false;
|
||||||
|
|
||||||
|
// We check if any options on formatting or quoting style have been given.
|
||||||
|
// If not, we will use dir default formatting and quoting style options
|
||||||
|
|
||||||
|
if !matches.is_present(options::QUOTING_STYLE)
|
||||||
|
&& !matches.is_present(options::quoting::C)
|
||||||
|
&& !matches.is_present(options::quoting::ESCAPE)
|
||||||
|
&& !matches.is_present(options::quoting::LITERAL)
|
||||||
|
{
|
||||||
|
default_quoting_style = true;
|
||||||
|
}
|
||||||
|
if !matches.is_present(options::FORMAT)
|
||||||
|
&& !matches.is_present(options::format::ACROSS)
|
||||||
|
&& !matches.is_present(options::format::COLUMNS)
|
||||||
|
&& !matches.is_present(options::format::COMMAS)
|
||||||
|
&& !matches.is_present(options::format::LONG)
|
||||||
|
&& !matches.is_present(options::format::LONG_NO_GROUP)
|
||||||
|
&& !matches.is_present(options::format::LONG_NO_OWNER)
|
||||||
|
&& !matches.is_present(options::format::LONG_NUMERIC_UID_GID)
|
||||||
|
&& !matches.is_present(options::format::ONE_LINE)
|
||||||
|
{
|
||||||
|
default_format_style = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut config = Config::from(&matches)?;
|
||||||
|
|
||||||
|
if default_quoting_style {
|
||||||
|
config.quoting_style = QuotingStyle::C {
|
||||||
|
quotes: Quotes::None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if default_format_style {
|
||||||
|
config.format = Format::Columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
let locs = matches
|
||||||
|
.values_of_os(options::PATHS)
|
||||||
|
.map(|v| v.map(Path::new).collect())
|
||||||
|
.unwrap_or_else(|| vec![Path::new(".")]);
|
||||||
|
|
||||||
|
uu_ls::list(locs, &config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid code duplication, we reuse ls uu_app function which has the same
|
||||||
|
// arguments. However, coreutils won't compile if one of the utils is missing
|
||||||
|
// an uu_app function, so we need this dummy one.
|
||||||
|
pub fn uu_app<'a>() -> Command<'a> {
|
||||||
|
Command::new(uucore::util_name())
|
||||||
|
}
|
1
src/uu/dir/src/main.rs
Normal file
1
src/uu/dir/src/main.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
uucore::bin!(uu_dir);
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dircolors"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dircolors"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/dircolors.rs"
|
path = "src/dircolors.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dirname"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dirname"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/dirname.rs"
|
path = "src/dirname.rs"
|
||||||
|
|
|
@ -9,13 +9,15 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/du"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/du"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/du.rs"
|
path = "src/du.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "^0.4.11"
|
chrono = "^0.4.11"
|
||||||
|
# For the --exclude & --exclude-from options
|
||||||
|
glob = "0.3.0"
|
||||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,15 @@ extern crate uucore;
|
||||||
use chrono::prelude::DateTime;
|
use chrono::prelude::DateTime;
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use clap::{crate_version, Arg, ArgMatches, Command};
|
use clap::{crate_version, Arg, ArgMatches, Command};
|
||||||
|
use glob::Pattern;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::fs::File;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
use std::fs::Metadata;
|
use std::fs::Metadata;
|
||||||
|
use std::io::BufRead;
|
||||||
|
use std::io::BufReader;
|
||||||
use std::io::{ErrorKind, Result};
|
use std::io::{ErrorKind, Result};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
|
@ -24,14 +28,13 @@ use std::os::unix::fs::MetadataExt;
|
||||||
use std::os::windows::fs::MetadataExt;
|
use std::os::windows::fs::MetadataExt;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::os::windows::io::AsRawHandle;
|
use std::os::windows::io::AsRawHandle;
|
||||||
#[cfg(windows)]
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::{Duration, UNIX_EPOCH};
|
use std::time::{Duration, UNIX_EPOCH};
|
||||||
use std::{error::Error, fmt::Display};
|
use std::{error::Error, fmt::Display};
|
||||||
use uucore::display::{print_verbatim, Quotable};
|
use uucore::display::{print_verbatim, Quotable};
|
||||||
use uucore::error::{UError, UResult};
|
use uucore::error::{set_exit_code, UError, UResult};
|
||||||
use uucore::format_usage;
|
use uucore::format_usage;
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
@ -68,6 +71,9 @@ mod options {
|
||||||
pub const ONE_FILE_SYSTEM: &str = "one-file-system";
|
pub const ONE_FILE_SYSTEM: &str = "one-file-system";
|
||||||
pub const DEREFERENCE: &str = "dereference";
|
pub const DEREFERENCE: &str = "dereference";
|
||||||
pub const INODES: &str = "inodes";
|
pub const INODES: &str = "inodes";
|
||||||
|
pub const EXCLUDE: &str = "exclude";
|
||||||
|
pub const EXCLUDE_FROM: &str = "exclude-from";
|
||||||
|
pub const VERBOSE: &str = "verbose";
|
||||||
pub const FILE: &str = "FILE";
|
pub const FILE: &str = "FILE";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +86,12 @@ Otherwise, units default to 1024 bytes (or 512 if POSIXLY_CORRECT is set).
|
||||||
SIZE is an integer and optional unit (example: 10M is 10*1024*1024).
|
SIZE is an integer and optional unit (example: 10M is 10*1024*1024).
|
||||||
Units are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB,... (powers
|
Units are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB,... (powers
|
||||||
of 1000).
|
of 1000).
|
||||||
|
|
||||||
|
PATTERN allows some advanced exclusions. For example, the following syntaxes
|
||||||
|
are supported:
|
||||||
|
? will match only one character
|
||||||
|
* will match zero or more characters
|
||||||
|
{a,b} will match a or b
|
||||||
";
|
";
|
||||||
const USAGE: &str = "\
|
const USAGE: &str = "\
|
||||||
{} [OPTION]... [FILE]...
|
{} [OPTION]... [FILE]...
|
||||||
|
@ -97,6 +109,7 @@ struct Options {
|
||||||
one_file_system: bool,
|
one_file_system: bool,
|
||||||
dereference: bool,
|
dereference: bool,
|
||||||
inodes: bool,
|
inodes: bool,
|
||||||
|
verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
@ -253,7 +266,7 @@ fn read_block_size(s: Option<&str>) -> u64 {
|
||||||
parse_size(s)
|
parse_size(s)
|
||||||
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::BLOCK_SIZE)))
|
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::BLOCK_SIZE)))
|
||||||
} else {
|
} else {
|
||||||
for env_var in &["DU_BLOCK_SIZE", "BLOCK_SIZE", "BLOCKSIZE"] {
|
for env_var in ["DU_BLOCK_SIZE", "BLOCK_SIZE", "BLOCKSIZE"] {
|
||||||
if let Ok(env_size) = env::var(env_var) {
|
if let Ok(env_size) = env::var(env_var) {
|
||||||
if let Ok(v) = parse_size(&env_size) {
|
if let Ok(v) = parse_size(&env_size) {
|
||||||
return v;
|
return v;
|
||||||
|
@ -287,6 +300,7 @@ fn du(
|
||||||
options: &Options,
|
options: &Options,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
inodes: &mut HashSet<FileInfo>,
|
inodes: &mut HashSet<FileInfo>,
|
||||||
|
exclude: &[Pattern],
|
||||||
) -> Box<dyn DoubleEndedIterator<Item = Stat>> {
|
) -> Box<dyn DoubleEndedIterator<Item = Stat>> {
|
||||||
let mut stats = vec![];
|
let mut stats = vec![];
|
||||||
let mut futures = vec![];
|
let mut futures = vec![];
|
||||||
|
@ -301,49 +315,73 @@ fn du(
|
||||||
my_stat.path.quote(),
|
my_stat.path.quote(),
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
|
set_exit_code(1);
|
||||||
return Box::new(iter::once(my_stat));
|
return Box::new(iter::once(my_stat));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for f in read {
|
'file_loop: for f in read {
|
||||||
match f {
|
match f {
|
||||||
Ok(entry) => match Stat::new(entry.path(), options) {
|
Ok(entry) => {
|
||||||
Ok(this_stat) => {
|
match Stat::new(entry.path(), options) {
|
||||||
if let Some(inode) = this_stat.inode {
|
Ok(this_stat) => {
|
||||||
if inodes.contains(&inode) {
|
// We have an exclude list
|
||||||
continue;
|
for pattern in exclude {
|
||||||
}
|
// Look at all patterns with both short and long paths
|
||||||
inodes.insert(inode);
|
// if we have 'du foo' but search to exclude 'foo/bar'
|
||||||
}
|
// we need the full path
|
||||||
if this_stat.is_dir {
|
if pattern.matches(&this_stat.path.to_string_lossy())
|
||||||
if options.one_file_system {
|
|| pattern.matches(&entry.file_name().into_string().unwrap())
|
||||||
if let (Some(this_inode), Some(my_inode)) =
|
|
||||||
(this_stat.inode, my_stat.inode)
|
|
||||||
{
|
{
|
||||||
if this_inode.dev_id != my_inode.dev_id {
|
// if the directory is ignored, leave early
|
||||||
continue;
|
if options.verbose {
|
||||||
|
println!("{} ignored", &this_stat.path.quote());
|
||||||
}
|
}
|
||||||
|
// Go to the next file
|
||||||
|
continue 'file_loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
futures.push(du(this_stat, options, depth + 1, inodes));
|
|
||||||
} else {
|
if let Some(inode) = this_stat.inode {
|
||||||
my_stat.size += this_stat.size;
|
if inodes.contains(&inode) {
|
||||||
my_stat.blocks += this_stat.blocks;
|
continue;
|
||||||
my_stat.inodes += 1;
|
}
|
||||||
if options.all {
|
inodes.insert(inode);
|
||||||
stats.push(this_stat);
|
}
|
||||||
|
if this_stat.is_dir {
|
||||||
|
if options.one_file_system {
|
||||||
|
if let (Some(this_inode), Some(my_inode)) =
|
||||||
|
(this_stat.inode, my_stat.inode)
|
||||||
|
{
|
||||||
|
if this_inode.dev_id != my_inode.dev_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
futures.push(du(this_stat, options, depth + 1, inodes, exclude));
|
||||||
|
} else {
|
||||||
|
my_stat.size += this_stat.size;
|
||||||
|
my_stat.blocks += this_stat.blocks;
|
||||||
|
my_stat.inodes += 1;
|
||||||
|
if options.all {
|
||||||
|
stats.push(this_stat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(error) => match error.kind() {
|
||||||
|
ErrorKind::PermissionDenied => {
|
||||||
|
let description = format!("cannot access {}", entry.path().quote());
|
||||||
|
let error_message = "Permission denied";
|
||||||
|
show_error_custom_description!(description, "{}", error_message);
|
||||||
|
set_exit_code(1);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
set_exit_code(1);
|
||||||
|
show_error!("cannot access {}: {}", entry.path().quote(), error);
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Err(error) => match error.kind() {
|
}
|
||||||
ErrorKind::PermissionDenied => {
|
|
||||||
let description = format!("cannot access {}", entry.path().quote());
|
|
||||||
let error_message = "Permission denied";
|
|
||||||
show_error_custom_description!(description, "{}", error_message);
|
|
||||||
}
|
|
||||||
_ => show_error!("cannot access {}: {}", entry.path().quote(), error),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err(error) => show_error!("{}", error),
|
Err(error) => show_error!("{}", error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,6 +439,7 @@ enum DuError {
|
||||||
SummarizeDepthConflict(String),
|
SummarizeDepthConflict(String),
|
||||||
InvalidTimeStyleArg(String),
|
InvalidTimeStyleArg(String),
|
||||||
InvalidTimeArg(String),
|
InvalidTimeArg(String),
|
||||||
|
InvalidGlob(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for DuError {
|
impl Display for DuError {
|
||||||
|
@ -431,6 +470,7 @@ Try '{} --help' for more information.",
|
||||||
'birth' and 'creation' arguments are not supported on this platform.",
|
'birth' and 'creation' arguments are not supported on this platform.",
|
||||||
s.quote()
|
s.quote()
|
||||||
),
|
),
|
||||||
|
DuError::InvalidGlob(s) => write!(f, "Invalid exclude syntax: {}", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,11 +483,75 @@ impl UError for DuError {
|
||||||
Self::InvalidMaxDepthArg(_)
|
Self::InvalidMaxDepthArg(_)
|
||||||
| Self::SummarizeDepthConflict(_)
|
| Self::SummarizeDepthConflict(_)
|
||||||
| Self::InvalidTimeStyleArg(_)
|
| Self::InvalidTimeStyleArg(_)
|
||||||
| Self::InvalidTimeArg(_) => 1,
|
| Self::InvalidTimeArg(_)
|
||||||
|
| Self::InvalidGlob(_) => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read a file and return each line in a vector of String
|
||||||
|
fn file_as_vec(filename: impl AsRef<Path>) -> Vec<String> {
|
||||||
|
let file = File::open(filename).expect("no such file");
|
||||||
|
let buf = BufReader::new(file);
|
||||||
|
|
||||||
|
buf.lines()
|
||||||
|
.map(|l| l.expect("Could not parse line"))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given the --exclude-from and/or --exclude arguments, returns the globset lists
|
||||||
|
// to ignore the files
|
||||||
|
fn get_glob_ignore(matches: &ArgMatches) -> UResult<Vec<Pattern>> {
|
||||||
|
let mut excludes_from = if matches.is_present(options::EXCLUDE_FROM) {
|
||||||
|
match matches.values_of(options::EXCLUDE_FROM) {
|
||||||
|
Some(all_files) => {
|
||||||
|
let mut exclusion = Vec::<String>::new();
|
||||||
|
// Read the exclude lists from all the files
|
||||||
|
// and add them into a vector of string
|
||||||
|
let files: Vec<String> = all_files.clone().map(|v| v.to_owned()).collect();
|
||||||
|
for f in files {
|
||||||
|
exclusion.extend(file_as_vec(&f));
|
||||||
|
}
|
||||||
|
exclusion
|
||||||
|
}
|
||||||
|
None => Vec::<String>::new(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Vec::<String>::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut excludes = if matches.is_present(options::EXCLUDE) {
|
||||||
|
match matches.values_of(options::EXCLUDE) {
|
||||||
|
Some(v) => {
|
||||||
|
// Read the various arguments
|
||||||
|
v.clone().map(|v| v.to_owned()).collect()
|
||||||
|
}
|
||||||
|
None => Vec::<String>::new(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Vec::<String>::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Merge the two lines
|
||||||
|
excludes.append(&mut excludes_from);
|
||||||
|
if !&excludes.is_empty() {
|
||||||
|
let mut builder = Vec::new();
|
||||||
|
// Create the `Vec` of excludes
|
||||||
|
for f in excludes {
|
||||||
|
if matches.is_present(options::VERBOSE) {
|
||||||
|
println!("adding {:?} to the exclude list ", &f);
|
||||||
|
}
|
||||||
|
match Pattern::new(&f) {
|
||||||
|
Ok(glob) => builder.push(glob),
|
||||||
|
Err(err) => return Err(DuError::InvalidGlob(err.to_string()).into()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(builder)
|
||||||
|
} else {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
@ -470,6 +574,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
one_file_system: matches.is_present(options::ONE_FILE_SYSTEM),
|
one_file_system: matches.is_present(options::ONE_FILE_SYSTEM),
|
||||||
dereference: matches.is_present(options::DEREFERENCE),
|
dereference: matches.is_present(options::DEREFERENCE),
|
||||||
inodes: matches.is_present(options::INODES),
|
inodes: matches.is_present(options::INODES),
|
||||||
|
verbose: matches.is_present(options::VERBOSE),
|
||||||
};
|
};
|
||||||
|
|
||||||
let files = match matches.value_of(options::FILE) {
|
let files = match matches.value_of(options::FILE) {
|
||||||
|
@ -524,8 +629,25 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
"\n"
|
"\n"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let excludes = get_glob_ignore(&matches)?;
|
||||||
|
|
||||||
let mut grand_total = 0;
|
let mut grand_total = 0;
|
||||||
for path_string in files {
|
'loop_file: for path_string in files {
|
||||||
|
// Skip if we don't want to ignore anything
|
||||||
|
if !&excludes.is_empty() {
|
||||||
|
for pattern in &excludes {
|
||||||
|
{
|
||||||
|
if pattern.matches(path_string) {
|
||||||
|
// if the directory is ignored, leave early
|
||||||
|
if options.verbose {
|
||||||
|
println!("{} ignored", path_string.quote());
|
||||||
|
}
|
||||||
|
continue 'loop_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let path = PathBuf::from(&path_string);
|
let path = PathBuf::from(&path_string);
|
||||||
match Stat::new(path, &options) {
|
match Stat::new(path, &options) {
|
||||||
Ok(stat) => {
|
Ok(stat) => {
|
||||||
|
@ -533,7 +655,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
if let Some(inode) = stat.inode {
|
if let Some(inode) = stat.inode {
|
||||||
inodes.insert(inode);
|
inodes.insert(inode);
|
||||||
}
|
}
|
||||||
let iter = du(stat, &options, 0, &mut inodes);
|
let iter = du(stat, &options, 0, &mut inodes, &excludes);
|
||||||
let (_, len) = iter.size_hint();
|
let (_, len) = iter.size_hint();
|
||||||
let len = len.unwrap();
|
let len = len.unwrap();
|
||||||
for (index, stat) in iter.enumerate() {
|
for (index, stat) in iter.enumerate() {
|
||||||
|
@ -758,19 +880,28 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
.help("exclude entries smaller than SIZE if positive, \
|
.help("exclude entries smaller than SIZE if positive, \
|
||||||
or entries greater than SIZE if negative")
|
or entries greater than SIZE if negative")
|
||||||
)
|
)
|
||||||
// .arg(
|
.arg(
|
||||||
// Arg::new("")
|
Arg::new(options::VERBOSE)
|
||||||
// .short('x')
|
.short('v')
|
||||||
// .long("exclude-from")
|
.long("verbose")
|
||||||
// .value_name("FILE")
|
.help("verbose mode (option not present in GNU/Coreutils)")
|
||||||
// .help("exclude files that match any pattern in FILE")
|
)
|
||||||
// )
|
.arg(
|
||||||
// .arg(
|
Arg::new(options::EXCLUDE)
|
||||||
// Arg::new("exclude")
|
.long(options::EXCLUDE)
|
||||||
// .long("exclude")
|
.value_name("PATTERN")
|
||||||
// .value_name("PATTERN")
|
.help("exclude files that match PATTERN")
|
||||||
// .help("exclude files that match PATTERN")
|
.multiple_occurrences(true)
|
||||||
// )
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(options::EXCLUDE_FROM)
|
||||||
|
.short('X')
|
||||||
|
.long("exclude-from")
|
||||||
|
.value_name("FILE")
|
||||||
|
.help("exclude files that match any pattern in FILE")
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::TIME)
|
Arg::new(options::TIME)
|
||||||
.long(options::TIME)
|
.long(options::TIME)
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/echo"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/echo"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/echo.rs"
|
path = "src/echo.rs"
|
||||||
|
|
2
src/uu/env/Cargo.toml
vendored
2
src/uu/env/Cargo.toml
vendored
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/env"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/env"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/env.rs"
|
path = "src/env.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/expand"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/expand"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/expand.rs"
|
path = "src/expand.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/expr"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/expr"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/expr.rs"
|
path = "src/expr.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
num-traits = "0.2.13" # used in src/numerics.rs, which is included by build.rs
|
num-traits = "0.2.13" # used in src/numerics.rs, which is included by build.rs
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub(crate) fn test<A: Arithmetic + Basis>(m: A) -> Result {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let a = m.from_u64(_a);
|
let a = m.to_mod(_a);
|
||||||
|
|
||||||
// x = a^r mod n
|
// x = a^r mod n
|
||||||
let mut x = m.pow(a, r);
|
let mut x = m.pow(a, r);
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub(crate) trait Arithmetic: Copy + Sized {
|
||||||
|
|
||||||
fn new(m: u64) -> Self;
|
fn new(m: u64) -> Self;
|
||||||
fn modulus(&self) -> u64;
|
fn modulus(&self) -> u64;
|
||||||
fn from_u64(&self, n: u64) -> Self::ModInt;
|
fn to_mod(&self, n: u64) -> Self::ModInt;
|
||||||
fn to_u64(&self, n: Self::ModInt) -> u64;
|
fn to_u64(&self, n: Self::ModInt) -> u64;
|
||||||
fn add(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt;
|
fn add(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt;
|
||||||
fn mul(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt;
|
fn mul(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt;
|
||||||
|
@ -47,13 +47,13 @@ pub(crate) trait Arithmetic: Copy + Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one(&self) -> Self::ModInt {
|
fn one(&self) -> Self::ModInt {
|
||||||
self.from_u64(1)
|
self.to_mod(1)
|
||||||
}
|
}
|
||||||
fn minus_one(&self) -> Self::ModInt {
|
fn minus_one(&self) -> Self::ModInt {
|
||||||
self.from_u64(self.modulus() - 1)
|
self.to_mod(self.modulus() - 1)
|
||||||
}
|
}
|
||||||
fn zero(&self) -> Self::ModInt {
|
fn zero(&self) -> Self::ModInt {
|
||||||
self.from_u64(0)
|
self.to_mod(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ impl<T: DoubleInt> Arithmetic for Montgomery<T> {
|
||||||
self.n.as_u64()
|
self.n.as_u64()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_u64(&self, x: u64) -> Self::ModInt {
|
fn to_mod(&self, x: u64) -> Self::ModInt {
|
||||||
// TODO: optimise!
|
// TODO: optimise!
|
||||||
debug_assert!(x < self.n.as_u64());
|
debug_assert!(x < self.n.as_u64());
|
||||||
let r = T::from_double_width(
|
let r = T::from_double_width(
|
||||||
|
@ -189,9 +189,9 @@ mod tests {
|
||||||
let n = 2 * n + 1;
|
let n = 2 * n + 1;
|
||||||
let m = Montgomery::<A>::new(n);
|
let m = Montgomery::<A>::new(n);
|
||||||
for x in 0..n {
|
for x in 0..n {
|
||||||
let m_x = m.from_u64(x);
|
let m_x = m.to_mod(x);
|
||||||
for y in 0..=x {
|
for y in 0..=x {
|
||||||
let m_y = m.from_u64(y);
|
let m_y = m.to_mod(y);
|
||||||
println!("{n:?}, {x:?}, {y:?}", n = n, x = x, y = y);
|
println!("{n:?}, {x:?}, {y:?}", n = n, x = x, y = y);
|
||||||
assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y)));
|
assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y)));
|
||||||
}
|
}
|
||||||
|
@ -205,9 +205,9 @@ mod tests {
|
||||||
let n = 2 * n + 1;
|
let n = 2 * n + 1;
|
||||||
let m = Montgomery::<A>::new(n);
|
let m = Montgomery::<A>::new(n);
|
||||||
for x in 0..n {
|
for x in 0..n {
|
||||||
let m_x = m.from_u64(x);
|
let m_x = m.to_mod(x);
|
||||||
for y in 0..=x {
|
for y in 0..=x {
|
||||||
let m_y = m.from_u64(y);
|
let m_y = m.to_mod(y);
|
||||||
assert_eq!((x * y) % n, m.to_u64(m.mul(m_x, m_y)));
|
assert_eq!((x * y) % n, m.to_u64(m.mul(m_x, m_y)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ mod tests {
|
||||||
let n = 2 * n + 1;
|
let n = 2 * n + 1;
|
||||||
let m = Montgomery::<A>::new(n);
|
let m = Montgomery::<A>::new(n);
|
||||||
for x in 0..n {
|
for x in 0..n {
|
||||||
let x_ = m.from_u64(x);
|
let x_ = m.to_mod(x);
|
||||||
assert_eq!(x, m.to_u64(x_));
|
assert_eq!(x, m.to_u64(x_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub(crate) fn find_divisor<A: Arithmetic>(n: A) -> u64 {
|
||||||
let mut rand = {
|
let mut rand = {
|
||||||
let range = Uniform::new(1, n.modulus());
|
let range = Uniform::new(1, n.modulus());
|
||||||
let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
|
let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
|
||||||
move || n.from_u64(range.sample(&mut rng))
|
move || n.to_mod(range.sample(&mut rng))
|
||||||
};
|
};
|
||||||
|
|
||||||
let quadratic = |a, b| move |x| n.add(n.mul(a, n.mul(x, x)), b);
|
let quadratic = |a, b| move |x| n.add(n.mul(a, n.mul(x, x)), b);
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/false"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/false"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/false.rs"
|
path = "src/false.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/fmt"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/fmt"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/fmt.rs"
|
path = "src/fmt.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/fold"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/fold"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/fold.rs"
|
path = "src/fold.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/groups"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/groups"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/groups.rs"
|
path = "src/groups.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hashsum"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hashsum"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/hashsum.rs"
|
path = "src/hashsum.rs"
|
||||||
|
@ -20,7 +20,7 @@ clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
memchr = "2"
|
memchr = "2"
|
||||||
md-5 = "0.10.1"
|
md-5 = "0.10.1"
|
||||||
regex = "1.0.1"
|
regex = "1.5.5"
|
||||||
sha1 = "0.10.1"
|
sha1 = "0.10.1"
|
||||||
sha2 = "0.10.2"
|
sha2 = "0.10.2"
|
||||||
sha3 = "0.10.1"
|
sha3 = "0.10.1"
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
// * For the full copyright and license information, please view the LICENSE
|
// * For the full copyright and license information, please view the LICENSE
|
||||||
// * file that was distributed with this source code.
|
// * file that was distributed with this source code.
|
||||||
|
|
||||||
// spell-checker:ignore (ToDO) algo, algoname, regexes, nread
|
// spell-checker:ignore (ToDO) algo, algoname, regexes, nread, nonames
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
@ -46,6 +46,7 @@ struct Options {
|
||||||
binary: bool,
|
binary: bool,
|
||||||
check: bool,
|
check: bool,
|
||||||
tag: bool,
|
tag: bool,
|
||||||
|
nonames: bool,
|
||||||
status: bool,
|
status: bool,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
strict: bool,
|
strict: bool,
|
||||||
|
@ -316,6 +317,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||||
};
|
};
|
||||||
let check = matches.is_present("check");
|
let check = matches.is_present("check");
|
||||||
let tag = matches.is_present("tag");
|
let tag = matches.is_present("tag");
|
||||||
|
let nonames = matches.is_present("no-names");
|
||||||
let status = matches.is_present("status");
|
let status = matches.is_present("status");
|
||||||
let quiet = matches.is_present("quiet") || status;
|
let quiet = matches.is_present("quiet") || status;
|
||||||
let strict = matches.is_present("strict");
|
let strict = matches.is_present("strict");
|
||||||
|
@ -328,6 +330,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||||
binary,
|
binary,
|
||||||
check,
|
check,
|
||||||
tag,
|
tag,
|
||||||
|
nonames,
|
||||||
status,
|
status,
|
||||||
quiet,
|
quiet,
|
||||||
strict,
|
strict,
|
||||||
|
@ -370,6 +373,11 @@ pub fn uu_app_common<'a>() -> Command<'a> {
|
||||||
.long("tag")
|
.long("tag")
|
||||||
.help("create a BSD-style checksum"),
|
.help("create a BSD-style checksum"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("no-names")
|
||||||
|
.long("no-names")
|
||||||
|
.help("Omits filenames in the output (option not present in GNU/Coreutils)"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("text")
|
Arg::new("text")
|
||||||
.short('t')
|
.short('t')
|
||||||
|
@ -602,6 +610,8 @@ where
|
||||||
.map_err_context(|| "failed to read input".to_string())?;
|
.map_err_context(|| "failed to read input".to_string())?;
|
||||||
if options.tag {
|
if options.tag {
|
||||||
println!("{} ({}) = {}", options.algoname, filename.display(), sum);
|
println!("{} ({}) = {}", options.algoname, filename.display(), sum);
|
||||||
|
} else if options.nonames {
|
||||||
|
println!("{}", sum);
|
||||||
} else {
|
} else {
|
||||||
println!("{} {}{}", sum, binary_marker, filename.display());
|
println!("{} {}{}", sum, binary_marker, filename.display());
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/head"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/head"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/head.rs"
|
path = "src/head.rs"
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
// spell-checker:ignore (vars) zlines BUFWRITER seekable
|
// spell-checker:ignore (vars) zlines BUFWRITER seekable
|
||||||
|
|
||||||
use clap::{crate_version, Arg, ArgMatches, Command};
|
use clap::{crate_version, Arg, ArgMatches, Command};
|
||||||
use std::convert::{TryFrom, TryInto};
|
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::io::{self, BufWriter, ErrorKind, Read, Seek, SeekFrom, Write};
|
use std::io::{self, BufWriter, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hostid"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hostid"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/hostid.rs"
|
path = "src/hostid.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hostname"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hostname"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/hostname.rs"
|
path = "src/hostname.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/id"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/id"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/id.rs"
|
path = "src/id.rs"
|
||||||
|
|
|
@ -12,7 +12,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/install"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/install"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/install.rs"
|
path = "src/install.rs"
|
||||||
|
|
|
@ -464,6 +464,19 @@ fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
|
||||||
} else {
|
} else {
|
||||||
if let Some(parent) = target.parent() {
|
if let Some(parent) = target.parent() {
|
||||||
if !parent.exists() && b.create_leading {
|
if !parent.exists() && b.create_leading {
|
||||||
|
if b.verbose {
|
||||||
|
let mut result = PathBuf::new();
|
||||||
|
// When creating directories with -Dv, show directory creations step
|
||||||
|
// by step
|
||||||
|
for part in parent.components() {
|
||||||
|
result.push(part.as_os_str());
|
||||||
|
if !Path::new(part.as_os_str()).is_dir() {
|
||||||
|
// Don't display when the directory already exists
|
||||||
|
println!("install: creating directory {}", result.quote());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(e) = fs::create_dir_all(parent) {
|
if let Err(e) = fs::create_dir_all(parent) {
|
||||||
return Err(InstallError::CreateDirFailed(parent.to_path_buf(), e).into());
|
return Err(InstallError::CreateDirFailed(parent.to_path_buf(), e).into());
|
||||||
}
|
}
|
||||||
|
@ -594,13 +607,19 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
|
||||||
match process::Command::new(&b.strip_program).arg(to).output() {
|
match process::Command::new(&b.strip_program).arg(to).output() {
|
||||||
Ok(o) => {
|
Ok(o) => {
|
||||||
if !o.status.success() {
|
if !o.status.success() {
|
||||||
|
// Follow GNU's behavior: if strip fails, removes the target
|
||||||
|
let _ = fs::remove_file(to);
|
||||||
return Err(InstallError::StripProgramFailed(
|
return Err(InstallError::StripProgramFailed(
|
||||||
String::from_utf8(o.stderr).unwrap_or_default(),
|
String::from_utf8(o.stderr).unwrap_or_default(),
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => return Err(InstallError::StripProgramFailed(e.to_string()).into()),
|
Err(e) => {
|
||||||
|
// Follow GNU's behavior: if strip fails, removes the target
|
||||||
|
let _ = fs::remove_file(to);
|
||||||
|
return Err(InstallError::StripProgramFailed(e.to_string()).into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/join"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/join"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/join.rs"
|
path = "src/join.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/kill"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/kill"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/kill.rs"
|
path = "src/kill.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/link"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/link"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/link.rs"
|
path = "src/link.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ln"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ln"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/ln.rs"
|
path = "src/ln.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/logname"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/logname"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/logname.rs"
|
path = "src/logname.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ls"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ls"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/ls.rs"
|
path = "src/ls.rs"
|
||||||
|
@ -22,7 +22,7 @@ number_prefix = "0.4"
|
||||||
term_grid = "0.1.5"
|
term_grid = "0.1.5"
|
||||||
termsize = "0.1.6"
|
termsize = "0.1.6"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
lscolors = { version = "0.7.1", features = ["ansi_term"] }
|
lscolors = { version = "0.9.0", features = ["ansi_term"] }
|
||||||
uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore", features = ["entries", "fs"] }
|
uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore", features = ["entries", "fs"] }
|
||||||
once_cell = "1.10.0"
|
once_cell = "1.10.0"
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
|
|
1231
src/uu/ls/src/ls.rs
1231
src/uu/ls/src/ls.rs
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@ use std::ffi::OsStr;
|
||||||
const SPECIAL_SHELL_CHARS_START: &[char] = &['~', '#'];
|
const SPECIAL_SHELL_CHARS_START: &[char] = &['~', '#'];
|
||||||
const SPECIAL_SHELL_CHARS: &str = "`$&*()|[]{};\\'\"<>?! ";
|
const SPECIAL_SHELL_CHARS: &str = "`$&*()|[]{};\\'\"<>?! ";
|
||||||
|
|
||||||
pub(super) enum QuotingStyle {
|
pub enum QuotingStyle {
|
||||||
Shell {
|
Shell {
|
||||||
escape: bool,
|
escape: bool,
|
||||||
always_quote: bool,
|
always_quote: bool,
|
||||||
|
@ -21,7 +21,7 @@ pub(super) enum QuotingStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub(super) enum Quotes {
|
pub enum Quotes {
|
||||||
None,
|
None,
|
||||||
Single,
|
Single,
|
||||||
Double,
|
Double,
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mkdir"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mkdir"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/mkdir.rs"
|
path = "src/mkdir.rs"
|
||||||
|
|
|
@ -64,12 +64,15 @@ fn get_mode(matches: &ArgMatches, mode_had_minus_prefix: bool) -> Result<u32, St
|
||||||
}
|
}
|
||||||
Ok(new_mode)
|
Ok(new_mode)
|
||||||
}
|
}
|
||||||
None => Ok(DEFAULT_PERM),
|
None => {
|
||||||
|
// If no mode argument is specified return the mode derived from umask
|
||||||
|
Ok(!mode::get_umask() & 0o0777)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn strip_minus_from_mode(_args: &mut Vec<String>) -> bool {
|
fn strip_minus_from_mode(_args: &mut [String]) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +118,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
.short('m')
|
.short('m')
|
||||||
.long(options::MODE)
|
.long(options::MODE)
|
||||||
.help("set file mode (not implemented on windows)")
|
.help("set file mode (not implemented on windows)")
|
||||||
.default_value("755"),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::PARENTS)
|
Arg::new(options::PARENTS)
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mkfifo"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mkfifo"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/mkfifo.rs"
|
path = "src/mkfifo.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mknod"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mknod"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "uu_mknod"
|
name = "uu_mknod"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mktemp"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mktemp"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/mktemp.rs"
|
path = "src/mktemp.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/more"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/more"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/more.rs"
|
path = "src/more.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mv"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mv"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/mv.rs"
|
path = "src/mv.rs"
|
||||||
|
|
|
@ -258,6 +258,16 @@ fn exec(files: &[OsString], b: &Behavior) -> UResult<()> {
|
||||||
move_files_into_dir(&[source.clone()], target, b)
|
move_files_into_dir(&[source.clone()], target, b)
|
||||||
}
|
}
|
||||||
} else if target.exists() && source.is_dir() {
|
} else if target.exists() && source.is_dir() {
|
||||||
|
match b.overwrite {
|
||||||
|
OverwriteMode::NoClobber => return Ok(()),
|
||||||
|
OverwriteMode::Interactive => {
|
||||||
|
println!("{}: overwrite {}? ", uucore::util_name(), target.quote());
|
||||||
|
if !read_yes() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OverwriteMode::Force => {}
|
||||||
|
};
|
||||||
Err(MvError::NonDirectoryToDirectory(
|
Err(MvError::NonDirectoryToDirectory(
|
||||||
source.quote().to_string(),
|
source.quote().to_string(),
|
||||||
target.quote().to_string(),
|
target.quote().to_string(),
|
||||||
|
@ -275,7 +285,23 @@ fn exec(files: &[OsString], b: &Behavior) -> UResult<()> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let target_dir = paths.last().unwrap();
|
let target_dir = paths.last().unwrap();
|
||||||
move_files_into_dir(&paths[..paths.len() - 1], target_dir, b)
|
let sources = &paths[..paths.len() - 1];
|
||||||
|
|
||||||
|
// Check if we have mv dir1 dir2 dir2
|
||||||
|
// And generate an error if this is the case
|
||||||
|
if sources.contains(target_dir) {
|
||||||
|
return Err(USimpleError::new(
|
||||||
|
1,
|
||||||
|
format!(
|
||||||
|
"cannot move {} to a subdirectory of itself, '{}/{}'",
|
||||||
|
target_dir.quote(),
|
||||||
|
target_dir.display(),
|
||||||
|
target_dir.display()
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
move_files_into_dir(sources, target_dir, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nice"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nice"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/nice.rs"
|
path = "src/nice.rs"
|
||||||
|
|
|
@ -9,14 +9,14 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nl"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nl"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/nl.rs"
|
path = "src/nl.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||||
regex = "1.0.1"
|
regex = "1.5.5"
|
||||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nohup"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nohup"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/nohup.rs"
|
path = "src/nohup.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nproc"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nproc"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/nproc.rs"
|
path = "src/nproc.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/numfmt"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/numfmt"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/numfmt.rs"
|
path = "src/numfmt.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/od"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/od"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/od.rs"
|
path = "src/od.rs"
|
||||||
|
|
|
@ -29,7 +29,6 @@ mod prn_float;
|
||||||
mod prn_int;
|
mod prn_int;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::convert::TryFrom;
|
|
||||||
|
|
||||||
use crate::byteorder_io::*;
|
use crate::byteorder_io::*;
|
||||||
use crate::formatteriteminfo::*;
|
use crate::formatteriteminfo::*;
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/paste"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/paste"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/paste.rs"
|
path = "src/paste.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pathchk"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pathchk"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/pathchk.rs"
|
path = "src/pathchk.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pinky"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pinky"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/pinky.rs"
|
path = "src/pinky.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pr"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pr"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/pr.rs"
|
path = "src/pr.rs"
|
||||||
|
@ -20,7 +20,7 @@ uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.19"
|
||||||
quick-error = "2.0.1"
|
quick-error = "2.0.1"
|
||||||
itertools = "0.10.0"
|
itertools = "0.10.0"
|
||||||
regex = "1.0"
|
regex = "1.5"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "pr"
|
name = "pr"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/printenv"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/printenv"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/printenv.rs"
|
path = "src/printenv.rs"
|
||||||
|
|
|
@ -12,7 +12,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/printf"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/printf"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/printf.rs"
|
path = "src/printf.rs"
|
||||||
|
|
|
@ -9,14 +9,14 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ptx"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ptx"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/ptx.rs"
|
path = "src/ptx.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||||
regex = "1.0.1"
|
regex = "1.5.5"
|
||||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pwd"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pwd"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/pwd.rs"
|
path = "src/pwd.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/readlink"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/readlink"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/readlink.rs"
|
path = "src/readlink.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/realpath"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/realpath"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/realpath.rs"
|
path = "src/realpath.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/relpath"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/relpath"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/relpath.rs"
|
path = "src/relpath.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/rm"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/rm"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/rm.rs"
|
path = "src/rm.rs"
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils"
|
||||||
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/rmdir"
|
repository = "https://github.com/uutils/coreutils/tree/main/src/uu/rmdir"
|
||||||
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/rmdir.rs"
|
path = "src/rmdir.rs"
|
||||||
|
|
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