mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
Merge branch 'main' into cp-lb
This commit is contained in:
@@ -5,7 +5,7 @@ name: CICD
|
||||
# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain
|
||||
# spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy
|
||||
# spell-checker:ignore (shell/tools) choco clippy dmake dpkg esac fakeroot gmake grcov halium lcov libssl mkdir popd printf pushd rsync rustc rustfmt rustup shopt xargs
|
||||
# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend pell runtest tempfile testsuite uutils DESTDIR sizemulti
|
||||
# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend pell runtest tempfile testsuite uutils DESTDIR sizemulti Swatinem
|
||||
|
||||
# ToDO: [2021-06; rivy] change from `cargo-tree` to `cargo tree` once MSRV is >= 1.45
|
||||
|
||||
@@ -37,6 +37,7 @@ jobs:
|
||||
- { os: windows-latest , features: feat_os_windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -94,6 +95,7 @@ jobs:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -157,6 +159,7 @@ jobs:
|
||||
- { os: windows-latest , features: feat_os_windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -214,6 +217,7 @@ jobs:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -265,6 +269,7 @@ jobs:
|
||||
# - { os: windows-latest , features: feat_os_windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -309,6 +314,7 @@ jobs:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -385,6 +391,7 @@ jobs:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Install `rust` toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -409,6 +416,7 @@ jobs:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Install `rust` toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -436,6 +444,7 @@ jobs:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -497,6 +506,7 @@ jobs:
|
||||
- { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -745,6 +755,7 @@ jobs:
|
||||
- { os: ubuntu-latest }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Install/setup prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -780,6 +791,7 @@ jobs:
|
||||
mem: 2048
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Prepare, build and test
|
||||
## spell-checker:ignore (ToDO) sshfs usesh vmactions
|
||||
uses: vmactions/freebsd-vm@v0.1.5
|
||||
@@ -848,6 +860,7 @@ jobs:
|
||||
- { os: windows-latest , features: windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
# - name: Reattach HEAD ## may be needed for accurate code coverage info
|
||||
# run: git checkout ${{ github.head_ref }}
|
||||
- name: Initialize workflow variables
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
name: FixPR
|
||||
|
||||
# spell-checker:ignore Swatinem
|
||||
|
||||
# Trigger automated fixes for PRs being merged (with associated commits)
|
||||
|
||||
# ToDO: [2021-06; rivy] change from `cargo-tree` to `cargo tree` once MSRV is >= 1.45
|
||||
@@ -27,6 +29,7 @@ jobs:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize job variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -98,6 +101,7 @@ jobs:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Initialize job variables
|
||||
id: vars
|
||||
shell: bash
|
||||
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
run: |
|
||||
## Install dependencies
|
||||
sudo apt-get update
|
||||
sudo apt-get install autoconf autopoint bison texinfo gperf gcc g++ gdb python-pyinotify jq
|
||||
sudo apt-get install autoconf autopoint bison texinfo gperf gcc g++ gdb python-pyinotify jq valgrind libexpect-perl
|
||||
- name: Add various locales
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -197,3 +197,80 @@ jobs:
|
||||
else
|
||||
echo "::warning ::Skipping test summary comparison; no prior reference summary is available."
|
||||
fi
|
||||
|
||||
gnu_coverage:
|
||||
name: Run GNU tests with coverage
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
steps:
|
||||
- name: Checkout code uutil
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: 'uutils'
|
||||
- name: Checkout GNU coreutils
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'coreutils/coreutils'
|
||||
path: 'gnu'
|
||||
ref: 'v9.0'
|
||||
submodules: recursive
|
||||
- name: Install `rust` toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
default: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
components: rustfmt
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install autoconf autopoint bison texinfo gperf gcc g++ gdb python-pyinotify jq valgrind libexpect-perl -y
|
||||
- name: Add various locales
|
||||
run: |
|
||||
echo "Before:"
|
||||
locale -a
|
||||
## Some tests fail with 'cannot change locale (en_US.ISO-8859-1): No such file or directory'
|
||||
## Some others need a French locale
|
||||
sudo locale-gen
|
||||
sudo locale-gen fr_FR
|
||||
sudo locale-gen fr_FR.UTF-8
|
||||
sudo update-locale
|
||||
echo "After:"
|
||||
locale -a
|
||||
- name: Build binaries
|
||||
env:
|
||||
CARGO_INCREMENTAL: "0"
|
||||
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
|
||||
RUSTDOCFLAGS: "-Cpanic=abort"
|
||||
run: |
|
||||
cd uutils
|
||||
UU_MAKE_PROFILE=debug bash util/build-gnu.sh
|
||||
- name: Run GNU tests
|
||||
run: bash uutils/util/run-gnu-test.sh
|
||||
- name: "`grcov` ~ install"
|
||||
uses: actions-rs/install@v0.1
|
||||
with:
|
||||
crate: grcov
|
||||
version: latest
|
||||
use-tool-cache: false
|
||||
- name: Generate coverage data (via `grcov`)
|
||||
id: coverage
|
||||
run: |
|
||||
## Generate coverage data
|
||||
cd uutils
|
||||
COVERAGE_REPORT_DIR="target/debug"
|
||||
COVERAGE_REPORT_FILE="${COVERAGE_REPORT_DIR}/lcov.info"
|
||||
mkdir -p "${COVERAGE_REPORT_DIR}"
|
||||
sudo chown -R "$(whoami)" "${COVERAGE_REPORT_DIR}"
|
||||
# display coverage files
|
||||
grcov . --output-type files --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" | sort --unique
|
||||
# generate coverage report
|
||||
grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"
|
||||
echo ::set-output name=report::${COVERAGE_REPORT_FILE}
|
||||
- name: Upload coverage results (to Codecov.io)
|
||||
uses: codecov/codecov-action@v2
|
||||
with:
|
||||
file: ${{ steps.coverage.outputs.report }}
|
||||
flags: gnutests
|
||||
name: gnutests
|
||||
working-directory: uutils
|
||||
|
||||
Generated
+35
-25
@@ -652,11 +652,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0"
|
||||
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -719,13 +720,12 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.1"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b"
|
||||
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
@@ -957,9 +957,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.2.0"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
@@ -1128,10 +1128,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||
|
||||
[[package]]
|
||||
name = "md5"
|
||||
version = "0.3.8"
|
||||
name = "md-5"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79c56d6a0b07f9e19282511c83fc5b086364cbae4ba8c7d5f190c3d9b0425a48"
|
||||
checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
@@ -1331,9 +1334,9 @@ checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
|
||||
[[package]]
|
||||
name = "onig"
|
||||
version = "4.3.3"
|
||||
version = "6.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8518fcb2b1b8c2f45f0ad499df4fda6087fc3475ca69a185c173b8315d2fb383"
|
||||
checksum = "67ddfe2c93bb389eea6e6d713306880c7f6dcc99a75b659ce145d962c861b225"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"lazy_static",
|
||||
@@ -1343,9 +1346,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "onig_sys"
|
||||
version = "69.1.0"
|
||||
version = "69.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388410bf5fa341f10e58e6db3975f4bea1ac30247dd79d37a9e5ced3cb4cc3b0"
|
||||
checksum = "5dd3eee045c84695b53b20255bb7317063df090b68e18bfac0abb6c39cf7f33e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
@@ -1807,6 +1810,12 @@ dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@@ -1880,9 +1889,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cc229fb94bcb689ffc39bd4ded842f6ff76885efede7c6d1ffb62582878bea"
|
||||
checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
@@ -1891,9 +1900,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.1"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec"
|
||||
checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
@@ -1902,9 +1911,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd"
|
||||
checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"keccak",
|
||||
@@ -2000,19 +2009,20 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.21.0"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2"
|
||||
checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.21.1"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec"
|
||||
checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote 1.0.14",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -2617,7 +2627,7 @@ dependencies = [
|
||||
"digest",
|
||||
"hex",
|
||||
"libc",
|
||||
"md5",
|
||||
"md-5",
|
||||
"memchr 2.4.1",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
|
||||
@@ -21,7 +21,7 @@ Running GNU tests
|
||||
At the end you should have uutils, gnu and gnulib checked out next to each other.
|
||||
|
||||
- Run `cd uutils && ./util/build-gnu.sh && cd ..` to get everything ready (this may take a while)
|
||||
- Finally, you can run `tests with bash uutils/util/run-gnu-test.sh <test>`. Instead of `<test>` insert the test you want to run, e.g. `tests/misc/wc-proc`.
|
||||
- Finally, you can run tests with `bash uutils/util/run-gnu-test.sh <test>`. Instead of `<test>` insert the test you want to run, e.g. `tests/misc/wc-proc.sh`.
|
||||
|
||||
|
||||
Code Coverage Report Generation
|
||||
@@ -33,7 +33,7 @@ Code coverage report can be generated using [grcov](https://github.com/mozilla/g
|
||||
|
||||
### Using Nightly Rust
|
||||
|
||||
To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-cc) coverage report
|
||||
To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project) coverage report
|
||||
|
||||
```bash
|
||||
$ export CARGO_INCREMENTAL=0
|
||||
|
||||
+2
-2
@@ -94,7 +94,7 @@ fn write_usage(w: &mut impl Write, app: &mut App, name: &str) -> io::Result<()>
|
||||
.filter(|l| !l.is_empty())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
usage = usage.replace(app.get_name(), name);
|
||||
usage = usage.replace(uucore::execution_phrase(), name);
|
||||
writeln!(w, "{}", usage)?;
|
||||
writeln!(w, "```")
|
||||
}
|
||||
@@ -204,7 +204,7 @@ fn write_options(w: &mut impl Write, app: &App) -> io::Result<()> {
|
||||
writeln!(
|
||||
w,
|
||||
"<dd>\n\n{}\n\n</dd>",
|
||||
arg.get_help().unwrap_or_default().replace("\n", "<br />")
|
||||
arg.get_help().unwrap_or_default().replace('\n', "<br />")
|
||||
)?;
|
||||
}
|
||||
writeln!(w, "</dl>\n")
|
||||
|
||||
@@ -22,16 +22,13 @@ to attempt to recover from any other non-alphabet bytes in the
|
||||
encoded stream.
|
||||
";
|
||||
|
||||
fn usage() -> String {
|
||||
format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
|
||||
}
|
||||
const USAGE: &str = "{} [OPTION]... [FILE]";
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let format = Format::Base32;
|
||||
let usage = usage();
|
||||
|
||||
let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?;
|
||||
let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, USAGE)?;
|
||||
|
||||
// Create a reference to stdin so we can return a locked stdin from
|
||||
// parse_base_cmd_args
|
||||
@@ -48,5 +45,5 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
}
|
||||
|
||||
pub fn uu_app<'a>() -> App<'a> {
|
||||
base_common::base_app(ABOUT)
|
||||
base_common::base_app(ABOUT, USAGE)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use std::io::{stdout, Read, Write};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::encoding::{wrap_print, Data, Format};
|
||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
||||
use uucore::InvalidEncodingHandling;
|
||||
use uucore::{format_usage, InvalidEncodingHandling};
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Stdin};
|
||||
@@ -86,17 +86,18 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn parse_base_cmd_args(args: impl uucore::Args, about: &str, usage: &str) -> UResult<Config> {
|
||||
let app = base_app(about).override_usage(usage);
|
||||
let app = base_app(about, usage);
|
||||
let arg_list = args
|
||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||
.accept_any();
|
||||
Config::from(&app.get_matches_from(arg_list))
|
||||
}
|
||||
|
||||
pub fn base_app(about: &str) -> App {
|
||||
pub fn base_app<'a>(about: &'a str, usage: &'a str) -> App<'a> {
|
||||
App::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(about)
|
||||
.override_usage(format_usage(usage))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
// Format arguments.
|
||||
.arg(
|
||||
|
||||
@@ -23,16 +23,13 @@ to attempt to recover from any other non-alphabet bytes in the
|
||||
encoded stream.
|
||||
";
|
||||
|
||||
fn usage() -> String {
|
||||
format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
|
||||
}
|
||||
const USAGE: &str = "{0} [OPTION]... [FILE]";
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let format = Format::Base64;
|
||||
let usage = usage();
|
||||
|
||||
let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?;
|
||||
let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, USAGE)?;
|
||||
|
||||
// Create a reference to stdin so we can return a locked stdin from
|
||||
// parse_base_cmd_args
|
||||
|
||||
@@ -11,18 +11,13 @@ use clap::{crate_version, App, AppSettings, Arg};
|
||||
use std::path::{is_separator, PathBuf};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{UResult, UUsageError};
|
||||
use uucore::InvalidEncodingHandling;
|
||||
use uucore::{format_usage, InvalidEncodingHandling};
|
||||
|
||||
static SUMMARY: &str = "Print NAME with any leading directory components removed
|
||||
If specified, also remove a trailing SUFFIX";
|
||||
|
||||
fn usage() -> String {
|
||||
format!(
|
||||
"{0} NAME [SUFFIX]
|
||||
{0} OPTION... NAME...",
|
||||
uucore::execution_phrase()
|
||||
)
|
||||
}
|
||||
const USAGE: &str = "{} NAME [SUFFIX]
|
||||
{} OPTION... NAME...";
|
||||
|
||||
pub mod options {
|
||||
pub static MULTIPLE: &str = "multiple";
|
||||
@@ -36,11 +31,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let args = args
|
||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||
.accept_any();
|
||||
let usage = usage();
|
||||
//
|
||||
// Argument parsing
|
||||
//
|
||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
||||
let matches = uu_app().get_matches_from(args);
|
||||
|
||||
// too few arguments
|
||||
if !matches.is_present(options::NAME) {
|
||||
@@ -97,6 +91,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
App::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(SUMMARY)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
Arg::new(options::MULTIPLE)
|
||||
|
||||
@@ -38,12 +38,10 @@ const ENCODINGS: &[(&str, Format)] = &[
|
||||
("z85", Format::Z85),
|
||||
];
|
||||
|
||||
fn usage() -> String {
|
||||
format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
|
||||
}
|
||||
const USAGE: &str = "{} [OPTION]... [FILE]";
|
||||
|
||||
pub fn uu_app<'a>() -> App<'a> {
|
||||
let mut app = base_common::base_app(ABOUT);
|
||||
let mut app = base_common::base_app(ABOUT, USAGE);
|
||||
for encoding in ENCODINGS {
|
||||
app = app.arg(Arg::new(encoding.0).long(encoding.0));
|
||||
}
|
||||
@@ -51,8 +49,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
}
|
||||
|
||||
fn parse_cmd_args(args: impl uucore::Args) -> UResult<(Config, Format)> {
|
||||
let usage = usage();
|
||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(
|
||||
let matches = uu_app().get_matches_from(
|
||||
args.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||
.accept_any(),
|
||||
);
|
||||
|
||||
@@ -36,10 +36,10 @@ use std::net::Shutdown;
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
#[cfg(unix)]
|
||||
use unix_socket::UnixStream;
|
||||
use uucore::InvalidEncodingHandling;
|
||||
use uucore::{format_usage, InvalidEncodingHandling};
|
||||
|
||||
static NAME: &str = "cat";
|
||||
static SYNTAX: &str = "[OPTION]... [FILE]...";
|
||||
static USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||
static SUMMARY: &str = "Concatenate FILE(s), or standard input, to standard output
|
||||
With no FILE, or when FILE is -, read standard input.";
|
||||
|
||||
@@ -243,7 +243,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
App::new(uucore::util_name())
|
||||
.name(NAME)
|
||||
.version(crate_version!())
|
||||
.override_usage(SYNTAX)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.about(SUMMARY)
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
use uucore::error::{UResult, USimpleError, UUsageError};
|
||||
use uucore::format_usage;
|
||||
use uucore::{display::Quotable, show_error, show_warning};
|
||||
|
||||
use clap::{App, AppSettings, Arg};
|
||||
@@ -22,6 +23,10 @@ use errors::*;
|
||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
static ABOUT: &str = "Change the SELinux security context of each FILE to CONTEXT. \n\
|
||||
With --reference, change the security context of each FILE to that of RFILE.";
|
||||
const USAGE: &str = "\
|
||||
{} [OPTION]... CONTEXT FILE... \n \
|
||||
{} [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE... \n \
|
||||
{} [OPTION]... --reference=RFILE FILE...";
|
||||
|
||||
pub mod options {
|
||||
pub static VERBOSE: &str = "verbose";
|
||||
@@ -52,20 +57,9 @@ pub mod options {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_usage() -> String {
|
||||
format!(
|
||||
"{0} [OPTION]... CONTEXT FILE... \n \
|
||||
{0} [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE... \n \
|
||||
{0} [OPTION]... --reference=RFILE FILE...",
|
||||
uucore::execution_phrase()
|
||||
)
|
||||
}
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let usage = get_usage();
|
||||
|
||||
let config = uu_app().override_usage(usage.as_ref());
|
||||
let config = uu_app();
|
||||
|
||||
let options = match parse_command_line(config, args) {
|
||||
Ok(r) => r,
|
||||
@@ -164,6 +158,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
App::new(uucore::util_name())
|
||||
.version(VERSION)
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
Arg::new(options::dereference::DEREFERENCE)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
use uucore::display::Quotable;
|
||||
pub use uucore::entries;
|
||||
use uucore::error::{FromIo, UResult, USimpleError};
|
||||
use uucore::format_usage;
|
||||
use uucore::perms::{chown_base, options, IfFrom};
|
||||
|
||||
use clap::{App, AppSettings, Arg, ArgMatches};
|
||||
@@ -20,12 +21,9 @@ use std::os::unix::fs::MetadataExt;
|
||||
static ABOUT: &str = "Change the group of each FILE to GROUP.";
|
||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
fn get_usage() -> String {
|
||||
format!(
|
||||
"{0} [OPTION]... GROUP FILE...\n {0} [OPTION]... --reference=RFILE FILE...",
|
||||
uucore::execution_phrase()
|
||||
)
|
||||
}
|
||||
const USAGE: &str = "\
|
||||
{} [OPTION]... GROUP FILE...\n \
|
||||
{} [OPTION]... --reference=RFILE FILE...";
|
||||
|
||||
fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>, IfFrom)> {
|
||||
let dest_gid = if let Some(file) = matches.value_of(options::REFERENCE) {
|
||||
@@ -53,21 +51,14 @@ fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>,
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let usage = get_usage();
|
||||
|
||||
chown_base(
|
||||
uu_app().override_usage(&usage[..]),
|
||||
args,
|
||||
options::ARG_GROUP,
|
||||
parse_gid_and_uid,
|
||||
true,
|
||||
)
|
||||
chown_base(uu_app(), args, options::ARG_GROUP, parse_gid_and_uid, true)
|
||||
}
|
||||
|
||||
pub fn uu_app<'a>() -> App<'a> {
|
||||
App::new(uucore::util_name())
|
||||
.version(VERSION)
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
Arg::new(options::verbosity::CHANGES)
|
||||
|
||||
@@ -17,7 +17,7 @@ use uucore::fs::display_permissions_unix;
|
||||
use uucore::libc::mode_t;
|
||||
#[cfg(not(windows))]
|
||||
use uucore::mode;
|
||||
use uucore::{show_error, InvalidEncodingHandling};
|
||||
use uucore::{format_usage, show_error, InvalidEncodingHandling};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
static ABOUT: &str = "Change the mode of each FILE to MODE.
|
||||
@@ -35,14 +35,10 @@ mod options {
|
||||
pub const FILE: &str = "FILE";
|
||||
}
|
||||
|
||||
fn usage() -> String {
|
||||
format!(
|
||||
"{0} [OPTION]... MODE[,MODE]... FILE...
|
||||
or: {0} [OPTION]... OCTAL-MODE FILE...
|
||||
or: {0} [OPTION]... --reference=RFILE FILE...",
|
||||
uucore::execution_phrase()
|
||||
)
|
||||
}
|
||||
const USAGE: &str = "\
|
||||
{} [OPTION]... MODE[,MODE]... FILE...
|
||||
{} [OPTION]... OCTAL-MODE FILE...
|
||||
{} [OPTION]... --reference=RFILE FILE...";
|
||||
|
||||
fn get_long_usage() -> String {
|
||||
String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
|
||||
@@ -58,13 +54,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
// a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
|
||||
let mode_had_minus_prefix = mode::strip_minus_from_mode(&mut args);
|
||||
|
||||
let usage = usage();
|
||||
let after_help = get_long_usage();
|
||||
|
||||
let matches = uu_app()
|
||||
.override_usage(&usage[..])
|
||||
.after_help(&after_help[..])
|
||||
.get_matches_from(args);
|
||||
let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);
|
||||
|
||||
let changes = matches.is_present(options::CHANGES);
|
||||
let quiet = matches.is_present(options::QUIET);
|
||||
@@ -125,6 +117,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
App::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
Arg::new(options::CHANGES)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
use uucore::display::Quotable;
|
||||
pub use uucore::entries::{self, Group, Locate, Passwd};
|
||||
use uucore::format_usage;
|
||||
use uucore::perms::{chown_base, options, IfFrom};
|
||||
|
||||
use uucore::error::{FromIo, UResult, USimpleError};
|
||||
@@ -20,12 +21,9 @@ use std::os::unix::fs::MetadataExt;
|
||||
|
||||
static ABOUT: &str = "change file owner and group";
|
||||
|
||||
fn get_usage() -> String {
|
||||
format!(
|
||||
"{0} [OPTION]... [OWNER][:[GROUP]] FILE...\n{0} [OPTION]... --reference=RFILE FILE...",
|
||||
uucore::execution_phrase()
|
||||
)
|
||||
}
|
||||
const USAGE: &str = "\
|
||||
{} [OPTION]... [OWNER][:[GROUP]] FILE...
|
||||
{} [OPTION]... --reference=RFILE FILE...";
|
||||
|
||||
fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>, IfFrom)> {
|
||||
let filter = if let Some(spec) = matches.value_of(options::FROM) {
|
||||
@@ -56,10 +54,8 @@ fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<(Option<u32>, Optio
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let usage = get_usage();
|
||||
|
||||
chown_base(
|
||||
uu_app().override_usage(&usage[..]),
|
||||
uu_app(),
|
||||
args,
|
||||
options::ARG_OWNER,
|
||||
parse_gid_uid_and_filter,
|
||||
@@ -71,6 +67,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
App::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
Arg::new(options::verbosity::CHANGES)
|
||||
|
||||
@@ -17,10 +17,10 @@ use std::path::Path;
|
||||
use std::process::Command;
|
||||
use uucore::error::{set_exit_code, UResult};
|
||||
use uucore::libc::{self, chroot, setgid, setgroups, setuid};
|
||||
use uucore::{entries, InvalidEncodingHandling};
|
||||
use uucore::{entries, format_usage, InvalidEncodingHandling};
|
||||
|
||||
static ABOUT: &str = "Run COMMAND with root directory set to NEWROOT.";
|
||||
static SYNTAX: &str = "[OPTION]... NEWROOT [COMMAND [ARG]...]";
|
||||
static USAGE: &str = "{} [OPTION]... NEWROOT [COMMAND [ARG]...]";
|
||||
|
||||
mod options {
|
||||
pub const NEWROOT: &str = "newroot";
|
||||
@@ -95,7 +95,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
App::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(SYNTAX)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
Arg::new(options::NEWROOT)
|
||||
|
||||
@@ -12,15 +12,15 @@ use std::io::{self, stdin, BufReader, Read};
|
||||
use std::path::Path;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{FromIo, UResult};
|
||||
use uucore::show;
|
||||
use uucore::InvalidEncodingHandling;
|
||||
use uucore::{format_usage, show};
|
||||
|
||||
// NOTE: CRC_TABLE_LEN *must* be <= 256 as we cast 0..CRC_TABLE_LEN to u8
|
||||
const CRC_TABLE_LEN: usize = 256;
|
||||
const CRC_TABLE: [u32; CRC_TABLE_LEN] = generate_crc_table();
|
||||
|
||||
const NAME: &str = "cksum";
|
||||
const SYNTAX: &str = "[OPTIONS] [FILE]...";
|
||||
const USAGE: &str = "{} [OPTIONS] [FILE]...";
|
||||
const SUMMARY: &str = "Print CRC and size for each file";
|
||||
|
||||
const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] {
|
||||
@@ -145,7 +145,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
.name(NAME)
|
||||
.version(crate_version!())
|
||||
.about(SUMMARY)
|
||||
.override_usage(SYNTAX)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
Arg::new(options::FILE)
|
||||
|
||||
@@ -13,12 +13,13 @@ use std::io::{self, stdin, BufRead, BufReader, Stdin};
|
||||
use std::path::Path;
|
||||
use uucore::error::FromIo;
|
||||
use uucore::error::UResult;
|
||||
use uucore::InvalidEncodingHandling;
|
||||
use uucore::{format_usage, InvalidEncodingHandling};
|
||||
|
||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||
|
||||
static ABOUT: &str = "compare two sorted files line by line";
|
||||
static LONG_HELP: &str = "";
|
||||
const USAGE: &str = "{} [OPTION]... FILE1 FILE2";
|
||||
|
||||
mod options {
|
||||
pub const COLUMN_1: &str = "1";
|
||||
@@ -30,10 +31,6 @@ mod options {
|
||||
pub const FILE_2: &str = "FILE2";
|
||||
}
|
||||
|
||||
fn usage() -> String {
|
||||
format!("{} [OPTION]... FILE1 FILE2", uucore::execution_phrase())
|
||||
}
|
||||
|
||||
fn mkdelim(col: usize, opts: &ArgMatches) -> String {
|
||||
let mut s = String::new();
|
||||
let delim = opts.value_of(options::DELIMITER).unwrap();
|
||||
@@ -132,12 +129,11 @@ fn open_file(name: &str) -> io::Result<LineReader> {
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let usage = usage();
|
||||
let args = args
|
||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||
.accept_any();
|
||||
|
||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
||||
let matches = uu_app().get_matches_from(args);
|
||||
let filename1 = matches.value_of(options::FILE_1).unwrap();
|
||||
let filename2 = matches.value_of(options::FILE_2).unwrap();
|
||||
let mut f1 = open_file(filename1).map_err_context(|| filename1.to_string())?;
|
||||
@@ -152,6 +148,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.after_help(LONG_HELP)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(
|
||||
Arg::new(options::COLUMN_1)
|
||||
|
||||
+82
-33
@@ -19,6 +19,7 @@ extern crate quick_error;
|
||||
extern crate uucore;
|
||||
|
||||
use uucore::display::Quotable;
|
||||
use uucore::format_usage;
|
||||
use uucore::fs::FileInformation;
|
||||
#[cfg(windows)]
|
||||
use winapi::um::fileapi::CreateFileW;
|
||||
@@ -29,6 +30,8 @@ use std::borrow::Cow;
|
||||
|
||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||
use filetime::FileTime;
|
||||
#[cfg(unix)]
|
||||
use libc::mkfifo;
|
||||
use quick_error::ResultExt;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
@@ -42,6 +45,10 @@ use std::fs::OpenOptions;
|
||||
use std::io;
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use std::mem;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::{FileTypeExt, PermissionsExt};
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::unix::io::AsRawFd;
|
||||
#[cfg(windows)]
|
||||
@@ -54,9 +61,6 @@ use uucore::error::{set_exit_code, ExitCode, UError, UResult};
|
||||
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
ioctl!(write ficlone with 0x94, 9; std::os::raw::c_int);
|
||||
|
||||
@@ -149,7 +153,7 @@ pub type Target = PathBuf;
|
||||
pub type TargetSlice = Path;
|
||||
|
||||
/// Specifies whether when overwrite files
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub enum ClobberMode {
|
||||
Force,
|
||||
RemoveDestination,
|
||||
@@ -157,7 +161,7 @@ pub enum ClobberMode {
|
||||
}
|
||||
|
||||
/// Specifies whether when overwrite files
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub enum OverwriteMode {
|
||||
/// [Default] Always overwrite existing files
|
||||
Clobber(ClobberMode),
|
||||
@@ -230,14 +234,10 @@ static ABOUT: &str = "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.";
|
||||
static LONG_HELP: &str = "";
|
||||
static EXIT_ERR: i32 = 1;
|
||||
|
||||
fn usage() -> String {
|
||||
format!(
|
||||
"{0} [OPTION]... [-T] SOURCE DEST
|
||||
{0} [OPTION]... SOURCE... DIRECTORY
|
||||
{0} [OPTION]... -t DIRECTORY SOURCE...",
|
||||
uucore::execution_phrase()
|
||||
)
|
||||
}
|
||||
const USAGE: &str = "\
|
||||
{} [OPTION]... [-T] SOURCE DEST
|
||||
{} [OPTION]... SOURCE... DIRECTORY
|
||||
{} [OPTION]... -t DIRECTORY SOURCE...";
|
||||
|
||||
// Argument constants
|
||||
mod options {
|
||||
@@ -297,9 +297,17 @@ static DEFAULT_ATTRIBUTES: &[Attribute] = &[
|
||||
];
|
||||
|
||||
pub fn uu_app<'a>() -> App<'a> {
|
||||
const MODE_ARGS: &[&str] = &[
|
||||
options::LINK,
|
||||
options::REFLINK,
|
||||
options::SYMBOLIC_LINK,
|
||||
options::ATTRIBUTES_ONLY,
|
||||
options::COPY_CONTENTS,
|
||||
];
|
||||
App::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(Arg::new(options::TARGET_DIRECTORY)
|
||||
.short('t')
|
||||
@@ -316,17 +324,17 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
.arg(Arg::new(options::INTERACTIVE)
|
||||
.short('i')
|
||||
.long(options::INTERACTIVE)
|
||||
.conflicts_with(options::NO_CLOBBER)
|
||||
.overrides_with(options::NO_CLOBBER)
|
||||
.help("ask before overwriting files"))
|
||||
.arg(Arg::new(options::LINK)
|
||||
.short('l')
|
||||
.long(options::LINK)
|
||||
.overrides_with(options::REFLINK)
|
||||
.overrides_with_all(MODE_ARGS)
|
||||
.help("hard-link files instead of copying"))
|
||||
.arg(Arg::new(options::NO_CLOBBER)
|
||||
.short('n')
|
||||
.long(options::NO_CLOBBER)
|
||||
.conflicts_with(options::INTERACTIVE)
|
||||
.overrides_with(options::INTERACTIVE)
|
||||
.help("don't overwrite a file that already exists"))
|
||||
.arg(Arg::new(options::RECURSIVE)
|
||||
.short('r')
|
||||
@@ -346,8 +354,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
.arg(Arg::new(options::SYMBOLIC_LINK)
|
||||
.short('s')
|
||||
.long(options::SYMBOLIC_LINK)
|
||||
.conflicts_with(options::LINK)
|
||||
.overrides_with(options::REFLINK)
|
||||
.overrides_with_all(MODE_ARGS)
|
||||
.help("make symbolic links instead of copying"))
|
||||
.arg(Arg::new(options::FORCE)
|
||||
.short('f')
|
||||
@@ -357,9 +364,9 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
Currently not implemented for Windows."))
|
||||
.arg(Arg::new(options::REMOVE_DESTINATION)
|
||||
.long(options::REMOVE_DESTINATION)
|
||||
.conflicts_with(options::FORCE)
|
||||
.overrides_with(options::FORCE)
|
||||
.help("remove each existing destination file before attempting to open it \
|
||||
(contrast with --force). On Windows, current only works for writeable files."))
|
||||
(contrast with --force). On Windows, currently only works for writeable files."))
|
||||
.arg(backup_control::arguments::backup())
|
||||
.arg(backup_control::arguments::backup_no_args())
|
||||
.arg(backup_control::arguments::suffix())
|
||||
@@ -372,11 +379,11 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
.long(options::REFLINK)
|
||||
.takes_value(true)
|
||||
.value_name("WHEN")
|
||||
.overrides_with_all(MODE_ARGS)
|
||||
.help("control clone/CoW copies. See below"))
|
||||
.arg(Arg::new(options::ATTRIBUTES_ONLY)
|
||||
.long(options::ATTRIBUTES_ONLY)
|
||||
.conflicts_with(options::COPY_CONTENTS)
|
||||
.overrides_with(options::REFLINK)
|
||||
.overrides_with_all(MODE_ARGS)
|
||||
.help("Don't copy the file data, just the attributes"))
|
||||
.arg(Arg::new(options::PRESERVE)
|
||||
.long(options::PRESERVE)
|
||||
@@ -386,7 +393,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
.possible_values(PRESERVABLE_ATTRIBUTES)
|
||||
.min_values(0)
|
||||
.value_name("ATTR_LIST")
|
||||
.conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::NO_PRESERVE])
|
||||
.overrides_with_all(&[options::ARCHIVE, options::PRESERVE_DEFAULT_ATTRIBUTES, options::NO_PRESERVE])
|
||||
// -d sets this option
|
||||
// --archive sets this option
|
||||
.help("Preserve the specified attributes (default: mode, ownership (unix only), timestamps), \
|
||||
@@ -394,13 +401,13 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
.arg(Arg::new(options::PRESERVE_DEFAULT_ATTRIBUTES)
|
||||
.short('p')
|
||||
.long(options::PRESERVE_DEFAULT_ATTRIBUTES)
|
||||
.conflicts_with_all(&[options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE])
|
||||
.overrides_with_all(&[options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE])
|
||||
.help("same as --preserve=mode,ownership(unix only),timestamps"))
|
||||
.arg(Arg::new(options::NO_PRESERVE)
|
||||
.long(options::NO_PRESERVE)
|
||||
.takes_value(true)
|
||||
.value_name("ATTR_LIST")
|
||||
.conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::ARCHIVE])
|
||||
.overrides_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::ARCHIVE])
|
||||
.help("don't preserve the specified attributes"))
|
||||
.arg(Arg::new(options::PARENTS)
|
||||
.long(options::PARENTS)
|
||||
@@ -409,18 +416,18 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
.arg(Arg::new(options::NO_DEREFERENCE)
|
||||
.short('P')
|
||||
.long(options::NO_DEREFERENCE)
|
||||
.conflicts_with(options::DEREFERENCE)
|
||||
.overrides_with(options::DEREFERENCE)
|
||||
// -d sets this option
|
||||
.help("never follow symbolic links in SOURCE"))
|
||||
.arg(Arg::new(options::DEREFERENCE)
|
||||
.short('L')
|
||||
.long(options::DEREFERENCE)
|
||||
.conflicts_with(options::NO_DEREFERENCE)
|
||||
.overrides_with(options::NO_DEREFERENCE)
|
||||
.help("always follow symbolic links in SOURCE"))
|
||||
.arg(Arg::new(options::ARCHIVE)
|
||||
.short('a')
|
||||
.long(options::ARCHIVE)
|
||||
.conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::NO_PRESERVE])
|
||||
.overrides_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::NO_PRESERVE])
|
||||
.help("Same as -dR --preserve=all"))
|
||||
.arg(Arg::new(options::NO_DEREFERENCE_PRESERVE_LINKS)
|
||||
.short('d')
|
||||
@@ -433,7 +440,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
// TODO: implement the following args
|
||||
.arg(Arg::new(options::COPY_CONTENTS)
|
||||
.long(options::COPY_CONTENTS)
|
||||
.conflicts_with(options::ATTRIBUTES_ONLY)
|
||||
.overrides_with(options::ATTRIBUTES_ONLY)
|
||||
.help("NotImplemented: copy contents of special files when recursive"))
|
||||
.arg(Arg::new(options::SPARSE)
|
||||
.long(options::SPARSE)
|
||||
@@ -456,14 +463,12 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let usage = usage();
|
||||
let matches = uu_app()
|
||||
.after_help(&*format!(
|
||||
"{}\n{}",
|
||||
LONG_HELP,
|
||||
backup_control::BACKUP_CONTROL_LONG_HELP
|
||||
))
|
||||
.override_usage(&usage[..])
|
||||
.get_matches_from(args);
|
||||
|
||||
let options = Options::from_matches(&matches)?;
|
||||
@@ -969,6 +974,16 @@ fn copy_directory(
|
||||
return copy_file(root, target, options, symlinked_files);
|
||||
}
|
||||
|
||||
// check if root is a prefix of target
|
||||
if path_has_prefix(target, root)? {
|
||||
return Err(format!(
|
||||
"cannot copy a directory, {}, into itself, {}",
|
||||
root.quote(),
|
||||
target.quote()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let current_dir =
|
||||
env::current_dir().unwrap_or_else(|e| crash!(1, "failed to get current directory {}", e));
|
||||
|
||||
@@ -1388,12 +1403,23 @@ fn copy_helper(
|
||||
let parent = dest.parent().unwrap_or(dest);
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
let is_symlink = fs::symlink_metadata(&source)?.file_type().is_symlink();
|
||||
|
||||
let file_type = fs::symlink_metadata(&source)?.file_type();
|
||||
let is_symlink = file_type.is_symlink();
|
||||
|
||||
#[cfg(unix)]
|
||||
let is_fifo = file_type.is_fifo();
|
||||
#[cfg(not(unix))]
|
||||
let is_fifo = false;
|
||||
|
||||
if source.as_os_str() == "/dev/null" {
|
||||
/* workaround a limitation of fs::copy
|
||||
* https://github.com/rust-lang/rust/issues/79390
|
||||
*/
|
||||
File::create(dest).context(dest.display().to_string())?;
|
||||
} else if is_fifo && options.recursive {
|
||||
#[cfg(unix)]
|
||||
copy_fifo(dest, options.overwrite)?;
|
||||
} else if is_symlink {
|
||||
copy_link(source, dest, symlinked_files)?;
|
||||
} else if options.reflink_mode != ReflinkMode::Never {
|
||||
@@ -1413,6 +1439,23 @@ fn copy_helper(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// "Copies" a FIFO by creating a new one. This workaround is because Rust's
|
||||
// built-in fs::copy does not handle FIFOs (see rust-lang/rust/issues/79390).
|
||||
#[cfg(unix)]
|
||||
fn copy_fifo(dest: &Path, overwrite: OverwriteMode) -> CopyResult<()> {
|
||||
if dest.exists() {
|
||||
overwrite.verify(dest)?;
|
||||
fs::remove_file(&dest)?;
|
||||
}
|
||||
|
||||
let name = CString::new(dest.as_os_str().as_bytes()).unwrap();
|
||||
let err = unsafe { mkfifo(name.as_ptr(), 0o666) };
|
||||
if err == -1 {
|
||||
return Err(format!("cannot create fifo {}: File exists", dest.quote()).into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_link(
|
||||
source: &Path,
|
||||
dest: &Path,
|
||||
@@ -1496,7 +1539,6 @@ fn copy_on_write_macos(
|
||||
// Extract paths in a form suitable to be passed to a syscall.
|
||||
// The unwrap() is safe because they come from the command-line and so contain non nul
|
||||
// character.
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
let src = CString::new(source.as_os_str().as_bytes()).unwrap();
|
||||
let dst = CString::new(dest.as_os_str().as_bytes()).unwrap();
|
||||
|
||||
@@ -1582,6 +1624,13 @@ pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> io::Result<bool> {
|
||||
Ok(pathbuf1 == pathbuf2)
|
||||
}
|
||||
|
||||
pub fn path_has_prefix(p1: &Path, p2: &Path) -> io::Result<bool> {
|
||||
let pathbuf1 = canonicalize(p1, MissingHandling::Normal, ResolveMode::Logical)?;
|
||||
let pathbuf2 = canonicalize(p2, MissingHandling::Normal, ResolveMode::Logical)?;
|
||||
|
||||
Ok(pathbuf1.starts_with(pathbuf2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_localize_to_target() {
|
||||
assert!(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user