diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 08803afb1..0cc2ba50b 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -67,7 +67,7 @@ jobs: - name: Install `rust` toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2022-03-21 + toolchain: nightly default: true profile: minimal - name: Install `cargo-udeps` @@ -86,7 +86,7 @@ jobs: fault_type="${{ steps.vars.outputs.FAULT_TYPE }}" 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 ; } if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi @@ -483,7 +483,7 @@ jobs: - name: Install `rust` toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2022-03-21 + toolchain: nightly default: true profile: minimal # minimal component installation (ie, no documentation) - name: Test @@ -759,7 +759,7 @@ jobs: with: use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }} command: test - args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} ${{ 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 }} - name: Archive executable artifacts uses: actions/upload-artifact@v2 @@ -935,7 +935,7 @@ jobs: ## VARs setup outputs() { step_id="vars"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo ::set-output name=${var}::${!var}; done; } # 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 case ${{ matrix.job.os }} in windows-*) TOOLCHAIN="$TOOLCHAIN-x86_64-pc-windows-gnu" ;; esac; # * use requested TOOLCHAIN if specified @@ -994,7 +994,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast -p uucore + args: --no-fail-fast -p uucore env: CARGO_INCREMENTAL: "0" RUSTC_WRAPPER: "" @@ -1016,7 +1016,7 @@ jobs: uses: actions-rs/cargo@v1 with: 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: CARGO_INCREMENTAL: "0" RUSTC_WRAPPER: "" diff --git a/.github/workflows/GnuTests.yml b/.github/workflows/GnuTests.yml index 579bea4c0..d306092c6 100644 --- a/.github/workflows/GnuTests.yml +++ b/.github/workflows/GnuTests.yml @@ -25,7 +25,7 @@ jobs: outputs path_GNU path_GNU_tests path_reference path_UUTILS # 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 }}" outputs repo_default_branch repo_GNU_ref repo_reference_branch # @@ -216,12 +216,12 @@ jobs: with: repository: 'coreutils/coreutils' path: 'gnu' - ref: 'v9.0' + ref: 'v9.1' submodules: recursive - name: Install `rust` toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2022-03-21 + toolchain: nightly default: true profile: minimal # minimal component installation (ie, no documentation) components: rustfmt diff --git a/.vscode/cspell.dictionaries/people.wordlist.txt b/.vscode/cspell.dictionaries/people.wordlist.txt index 405733836..8fe38d885 100644 --- a/.vscode/cspell.dictionaries/people.wordlist.txt +++ b/.vscode/cspell.dictionaries/people.wordlist.txt @@ -179,3 +179,4 @@ Smigle00 anonymousknight kwantam nicoo +gmnsii diff --git a/.vscode/cspell.dictionaries/shell.wordlist.txt b/.vscode/cspell.dictionaries/shell.wordlist.txt index 4ed281efb..16d7b25e9 100644 --- a/.vscode/cspell.dictionaries/shell.wordlist.txt +++ b/.vscode/cspell.dictionaries/shell.wordlist.txt @@ -93,6 +93,7 @@ rollup sed selinuxenabled sestatus +vdir wslpath xargs diff --git a/Cargo.lock b/Cargo.lock index 02ab122b0..1a387ffb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,12 +73,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bigdecimal" version = "0.3.0" @@ -173,17 +167,11 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "bumpalo" -version = "3.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" - [[package]] name = "byte-unit" -version = "4.0.13" +version = "4.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ffc5b0ec7d7a6949e3f21fd63ba5af4cffdc2ba1e0b7bf62b481458c4ae7f" +checksum = "95ebf10dda65f19ff0f42ea15572a359ed60d7fc74fdc984d90310937be0014b" dependencies = [ "utf8-width", ] @@ -240,12 +228,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "chunked_transfer" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" - [[package]] name = "clang-sys" version = "1.3.0" @@ -274,9 +256,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.6" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c" dependencies = [ "atty", "bitflags", @@ -295,7 +277,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", ] [[package]] @@ -325,7 +307,7 @@ version = "0.0.13" dependencies = [ "atty", "chrono", - "clap 3.1.6", + "clap 3.1.8", "clap_complete", "conv", "filetime", @@ -347,7 +329,6 @@ dependencies = [ "time", "unindent", "unix_socket", - "ureq", "users", "uu_arch", "uu_base32", @@ -368,6 +349,7 @@ dependencies = [ "uu_date", "uu_dd", "uu_df", + "uu_dir", "uu_dircolors", "uu_dirname", "uu_du", @@ -445,6 +427,7 @@ dependencies = [ "uu_unlink", "uu_uptime", "uu_users", + "uu_vdir", "uu_wc", "uu_who", "uu_whoami", @@ -836,16 +819,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - [[package]] name = "fs_extra" version = "1.2.0" @@ -975,17 +948,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "if_rust_version" version = "1.0.0" @@ -1046,15 +1008,6 @@ dependencies = [ "either", ] -[[package]] -name = "js-sys" -version = "0.3.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "keccak" version = "0.1.0" @@ -1139,9 +1092,9 @@ dependencies = [ [[package]] name = "lscolors" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24b894c45c9da468621cdd615a5a79ee5e5523dd4f75c76ebc03d458940c16e" +checksum = "4e9323b3525d4efad2dead1837a105e313253bfdbad1d470994038eededa4d62" dependencies = [ "ansi_term", ] @@ -1152,12 +1105,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "md-5" version = "0.10.1" @@ -1267,13 +1214,12 @@ dependencies = [ [[package]] name = "nom" -version = "7.1.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr 2.4.1", "minimal-lexical", - "version_check", ] [[package]] @@ -1395,9 +1341,9 @@ dependencies = [ [[package]] name = "os_display" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "748cc1d0dc55247316a5bedd8dc8c5478c8a0c2e2001176b38ce7c0ed732c7a5" +checksum = "7a6229bad892b46b0dcfaaeb18ad0d2e56400f5aaea05b768bde96e73676cf75" dependencies = [ "unicode-width", ] @@ -1479,12 +1425,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - [[package]] name = "phf" version = "0.10.1" @@ -1664,9 +1604,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" dependencies = [ "autocfg", "crossbeam-deque", @@ -1676,22 +1616,21 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] @@ -1713,9 +1652,9 @@ checksum = "ef445213a92fdddc4bc69d9111156d20ffd50704a86ad82b372aab701a0d3a9a" [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr 2.4.1", @@ -1749,28 +1688,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53552c6c49e1e13f1a203ef0080ab3bbef0beb570a528993e83df057a9d9bba1" -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi 0.3.9", -] - [[package]] name = "rlimit" -version = "0.4.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b02d62c38353a6fce45c25ca19783e25dd5f495ca681c674a4ee15aa4c1536" +checksum = "f7278a1ec8bfd4a4e07515c589f5ff7b309a373f987393aef44813d9dcf87aa3" dependencies = [ - "cfg-if 0.1.10", "libc", ] @@ -1790,18 +1713,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustls" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b323592e3164322f5b193dc4302e4e36cd8d37158a712d664efae1a5c2791700" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - [[package]] name = "rustversion" version = "1.0.6" @@ -1823,21 +1734,11 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "selinux" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09715d6b4356e916047e61e4dce40a67ac93036851957b91713d3d9c282d1548" +checksum = "0c4534fb886814d0015bcc290979263692213627bdf8ed4091746bb1c77acb0d" dependencies = [ "bitflags", "libc", @@ -1955,12 +1856,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2133,33 +2028,12 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "tinyvec" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - [[package]] name = "typenum" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[package]] -name = "unicode-bidi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" - [[package]] name = "unicode-linebreak" version = "0.1.2" @@ -2169,15 +2043,6 @@ dependencies = [ "regex", ] -[[package]] -name = "unicode-normalization" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.9.0" @@ -2218,41 +2083,6 @@ dependencies = [ "libc", ] -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "ureq" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5" -dependencies = [ - "base64", - "chunked_transfer", - "flate2", - "log", - "once_cell", - "rustls", - "url", - "webpki", - "webpki-roots", -] - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - [[package]] name = "users" version = "0.10.0" @@ -2279,7 +2109,7 @@ checksum = "7cf7d77f457ef8dfa11e4cd5933c5ddb5dc52a94664071951219a97710f0a32b" name = "uu_arch" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "platform-info", "uucore", ] @@ -2288,7 +2118,7 @@ dependencies = [ name = "uu_base32" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2304,7 +2134,7 @@ dependencies = [ name = "uu_basename" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2312,7 +2142,7 @@ dependencies = [ name = "uu_basenc" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uu_base32", "uucore", ] @@ -2322,7 +2152,7 @@ name = "uu_cat" version = "0.0.13" dependencies = [ "atty", - "clap 3.1.6", + "clap 3.1.8", "nix", "thiserror", "unix_socket", @@ -2333,7 +2163,7 @@ dependencies = [ name = "uu_chcon" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "fts-sys", "libc", "selinux", @@ -2345,7 +2175,7 @@ dependencies = [ name = "uu_chgrp" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2353,7 +2183,7 @@ dependencies = [ name = "uu_chmod" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2362,7 +2192,7 @@ dependencies = [ name = "uu_chown" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2370,7 +2200,7 @@ dependencies = [ name = "uu_chroot" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2378,7 +2208,7 @@ dependencies = [ name = "uu_cksum" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2386,7 +2216,7 @@ dependencies = [ name = "uu_comm" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2394,7 +2224,7 @@ dependencies = [ name = "uu_cp" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "exacl", "filetime", "ioctl-sys", @@ -2411,7 +2241,7 @@ dependencies = [ name = "uu_csplit" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "regex", "thiserror", "uucore", @@ -2423,7 +2253,7 @@ version = "0.0.13" dependencies = [ "atty", "bstr", - "clap 3.1.6", + "clap 3.1.8", "memchr 2.4.1", "uucore", ] @@ -2433,7 +2263,7 @@ name = "uu_date" version = "0.0.13" dependencies = [ "chrono", - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", "winapi 0.3.9", @@ -2444,7 +2274,7 @@ name = "uu_dd" version = "0.0.13" dependencies = [ "byte-unit", - "clap 3.1.6", + "clap 3.1.8", "gcd", "libc", "signal-hook", @@ -2455,16 +2285,26 @@ dependencies = [ name = "uu_df" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "number_prefix", "uucore", ] +[[package]] +name = "uu_dir" +version = "0.0.13" +dependencies = [ + "clap 3.1.8", + "selinux", + "uu_ls", + "uucore", +] + [[package]] name = "uu_dircolors" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "glob", "uucore", ] @@ -2473,7 +2313,7 @@ dependencies = [ name = "uu_dirname" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2482,7 +2322,8 @@ name = "uu_du" version = "0.0.13" dependencies = [ "chrono", - "clap 3.1.6", + "clap 3.1.8", + "glob", "uucore", "winapi 0.3.9", ] @@ -2491,7 +2332,7 @@ dependencies = [ name = "uu_echo" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2499,7 +2340,7 @@ dependencies = [ name = "uu_env" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "rust-ini", "uucore", ] @@ -2508,7 +2349,7 @@ dependencies = [ name = "uu_expand" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "unicode-width", "uucore", ] @@ -2517,7 +2358,7 @@ dependencies = [ name = "uu_expr" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "num-bigint", "num-traits", "onig", @@ -2528,7 +2369,7 @@ dependencies = [ name = "uu_factor" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "coz", "num-traits", "paste", @@ -2542,7 +2383,7 @@ dependencies = [ name = "uu_false" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2550,7 +2391,7 @@ dependencies = [ name = "uu_fmt" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "unicode-width", "uucore", ] @@ -2559,7 +2400,7 @@ dependencies = [ name = "uu_fold" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2567,7 +2408,7 @@ dependencies = [ name = "uu_groups" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2577,7 +2418,7 @@ version = "0.0.13" dependencies = [ "blake2b_simd", "blake3", - "clap 3.1.6", + "clap 3.1.8", "digest", "hex", "md-5", @@ -2593,7 +2434,7 @@ dependencies = [ name = "uu_head" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "memchr 2.4.1", "uucore", ] @@ -2602,7 +2443,7 @@ dependencies = [ name = "uu_hostid" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2611,7 +2452,7 @@ dependencies = [ name = "uu_hostname" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "hostname", "uucore", "winapi 0.3.9", @@ -2621,7 +2462,7 @@ dependencies = [ name = "uu_id" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "selinux", "uucore", ] @@ -2630,7 +2471,7 @@ dependencies = [ name = "uu_install" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "file_diff", "filetime", "libc", @@ -2641,7 +2482,7 @@ dependencies = [ name = "uu_join" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "memchr 2.4.1", "uucore", ] @@ -2650,7 +2491,7 @@ dependencies = [ name = "uu_kill" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2659,7 +2500,7 @@ dependencies = [ name = "uu_link" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2667,7 +2508,7 @@ dependencies = [ name = "uu_ln" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2675,7 +2516,7 @@ dependencies = [ name = "uu_logname" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2686,7 +2527,7 @@ version = "0.0.13" dependencies = [ "atty", "chrono", - "clap 3.1.6", + "clap 3.1.8", "glob", "lazy_static", "lscolors", @@ -2703,7 +2544,7 @@ dependencies = [ name = "uu_mkdir" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2711,7 +2552,7 @@ dependencies = [ name = "uu_mkfifo" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2720,7 +2561,7 @@ dependencies = [ name = "uu_mknod" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2729,7 +2570,7 @@ dependencies = [ name = "uu_mktemp" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "rand", "tempfile", "uucore", @@ -2740,7 +2581,7 @@ name = "uu_more" version = "0.0.13" dependencies = [ "atty", - "clap 3.1.6", + "clap 3.1.8", "crossterm", "nix", "unicode-segmentation", @@ -2752,7 +2593,7 @@ dependencies = [ name = "uu_mv" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "fs_extra", "uucore", ] @@ -2761,7 +2602,7 @@ dependencies = [ name = "uu_nice" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "nix", "uucore", @@ -2771,7 +2612,7 @@ dependencies = [ name = "uu_nl" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "regex", "uucore", ] @@ -2781,7 +2622,7 @@ name = "uu_nohup" version = "0.0.13" dependencies = [ "atty", - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2790,7 +2631,7 @@ dependencies = [ name = "uu_nproc" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "num_cpus", "uucore", @@ -2800,7 +2641,7 @@ dependencies = [ name = "uu_numfmt" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2809,7 +2650,7 @@ name = "uu_od" version = "0.0.13" dependencies = [ "byteorder", - "clap 3.1.6", + "clap 3.1.8", "half", "uucore", ] @@ -2818,7 +2659,7 @@ dependencies = [ name = "uu_paste" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2826,7 +2667,7 @@ dependencies = [ name = "uu_pathchk" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2835,7 +2676,7 @@ dependencies = [ name = "uu_pinky" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2844,7 +2685,7 @@ name = "uu_pr" version = "0.0.13" dependencies = [ "chrono", - "clap 3.1.6", + "clap 3.1.8", "itertools", "quick-error", "regex", @@ -2855,7 +2696,7 @@ dependencies = [ name = "uu_printenv" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2863,7 +2704,7 @@ dependencies = [ name = "uu_printf" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2871,7 +2712,7 @@ dependencies = [ name = "uu_ptx" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "regex", "uucore", ] @@ -2880,7 +2721,7 @@ dependencies = [ name = "uu_pwd" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2888,7 +2729,7 @@ dependencies = [ name = "uu_readlink" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2896,7 +2737,7 @@ dependencies = [ name = "uu_realpath" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2904,7 +2745,7 @@ dependencies = [ name = "uu_relpath" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2912,7 +2753,7 @@ dependencies = [ name = "uu_rm" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "remove_dir_all", "uucore", "walkdir", @@ -2923,7 +2764,7 @@ dependencies = [ name = "uu_rmdir" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -2932,7 +2773,7 @@ dependencies = [ name = "uu_runcon" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "selinux", "thiserror", @@ -2944,7 +2785,7 @@ name = "uu_seq" version = "0.0.13" dependencies = [ "bigdecimal", - "clap 3.1.6", + "clap 3.1.8", "num-bigint", "num-traits", "uucore", @@ -2954,7 +2795,7 @@ dependencies = [ name = "uu_shred" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "rand", "uucore", ] @@ -2963,7 +2804,7 @@ dependencies = [ name = "uu_shuf" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "rand", "rand_core", "uucore", @@ -2973,7 +2814,7 @@ dependencies = [ name = "uu_sleep" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -2982,7 +2823,7 @@ name = "uu_sort" version = "0.0.13" dependencies = [ "binary-heap-plus", - "clap 3.1.6", + "clap 3.1.8", "compare", "ctrlc", "fnv", @@ -3000,7 +2841,7 @@ dependencies = [ name = "uu_split" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "memchr 2.4.1", "uucore", ] @@ -3009,7 +2850,7 @@ dependencies = [ name = "uu_stat" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -3017,7 +2858,7 @@ dependencies = [ name = "uu_stdbuf" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "tempfile", "uu_stdbuf_libstdbuf", "uucore", @@ -3037,7 +2878,7 @@ dependencies = [ name = "uu_sum" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -3045,7 +2886,7 @@ dependencies = [ name = "uu_sync" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", "winapi 0.3.9", @@ -3055,7 +2896,7 @@ dependencies = [ name = "uu_tac" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "memchr 2.4.1", "memmap2", "regex", @@ -3066,7 +2907,7 @@ dependencies = [ name = "uu_tail" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "nix", "notify", @@ -3078,7 +2919,7 @@ dependencies = [ name = "uu_tee" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "retain_mut", "uucore", @@ -3088,7 +2929,7 @@ dependencies = [ name = "uu_test" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "redox_syscall", "uucore", @@ -3098,7 +2939,7 @@ dependencies = [ name = "uu_timeout" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "nix", "uucore", @@ -3108,7 +2949,7 @@ dependencies = [ name = "uu_touch" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "filetime", "time", "uucore", @@ -3119,7 +2960,7 @@ dependencies = [ name = "uu_tr" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "nom", "uucore", ] @@ -3128,7 +2969,7 @@ dependencies = [ name = "uu_true" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -3136,7 +2977,7 @@ dependencies = [ name = "uu_truncate" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -3144,7 +2985,7 @@ dependencies = [ name = "uu_tsort" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -3153,7 +2994,7 @@ name = "uu_tty" version = "0.0.13" dependencies = [ "atty", - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", ] @@ -3162,7 +3003,7 @@ dependencies = [ name = "uu_uname" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "platform-info", "uucore", ] @@ -3171,7 +3012,7 @@ dependencies = [ name = "uu_unexpand" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "unicode-width", "uucore", ] @@ -3180,7 +3021,7 @@ dependencies = [ name = "uu_uniq" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "strum", "strum_macros", "uucore", @@ -3190,7 +3031,7 @@ dependencies = [ name = "uu_unlink" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -3199,7 +3040,7 @@ name = "uu_uptime" version = "0.0.13" dependencies = [ "chrono", - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -3207,7 +3048,17 @@ dependencies = [ name = "uu_users" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", + "uucore", +] + +[[package]] +name = "uu_vdir" +version = "0.0.13" +dependencies = [ + "clap 3.1.8", + "selinux", + "uu_ls", "uucore", ] @@ -3216,7 +3067,7 @@ name = "uu_wc" version = "0.0.13" dependencies = [ "bytecount", - "clap 3.1.6", + "clap 3.1.8", "libc", "nix", "unicode-width", @@ -3228,7 +3079,7 @@ dependencies = [ name = "uu_who" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "uucore", ] @@ -3236,7 +3087,7 @@ dependencies = [ name = "uu_whoami" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "libc", "uucore", "winapi 0.3.9", @@ -3246,7 +3097,7 @@ dependencies = [ name = "uu_yes" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "nix", "uucore", ] @@ -3255,7 +3106,7 @@ dependencies = [ name = "uucore" version = "0.0.13" dependencies = [ - "clap 3.1.6", + "clap 3.1.8", "data-encoding", "data-encoding-macro", "dns-lookup", @@ -3325,89 +3176,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasm-bindgen" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote 1.0.14", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" -dependencies = [ - "quote 1.0.14", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" -dependencies = [ - "proc-macro2", - "quote 1.0.14", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" - -[[package]] -name = "web-sys" -version = "0.3.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" -dependencies = [ - "webpki", -] - [[package]] name = "which" version = "4.2.2" @@ -3531,12 +3299,11 @@ checksum = "af896e93db81340b74b65f74276a99b210c086f3d34ed0abf433182a462af856" [[package]] name = "zip" -version = "0.5.13" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +checksum = "e6fa4aa90e99fb8d701bda16fb040d8ed2f9c7176fb44de750e880a74b580315" dependencies = [ "byteorder", "crc32fast", "flate2", - "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 377f466eb..41532cd45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ repository = "https://github.com/uutils/coreutils" readme = "README.md" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" build = "build.rs" @@ -45,6 +45,7 @@ feat_common_core = [ "cut", "date", "df", + "dir", "dircolors", "dirname", "dd", @@ -100,6 +101,7 @@ feat_common_core = [ "unexpand", "uniq", "unlink", + "vdir", "wc", "yes", ] @@ -252,8 +254,7 @@ lazy_static = { version="1.3" } textwrap = { version="0.15", features=["terminal_size"] } uucore = { version=">=0.0.11", package="uucore", path="src/uucore" } selinux = { version="0.2", optional = true } -ureq = "2.4.0" -zip = { version = "0.5.13", default_features=false, features=["deflate"] } +zip = { version = "0.6.0", default_features=false, features=["deflate"] } # * uutils 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" } 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" } +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" } 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" } @@ -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" } 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" } +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" } 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" } @@ -373,7 +376,7 @@ glob = "0.3.0" libc = "0.2" pretty_assertions = "1" rand = "0.8" -regex = "1.0" +regex = "1.5" sha1 = { version="0.10", features=["std"] } tempfile = "3" time = "0.1" @@ -384,7 +387,7 @@ atty = "0.2" hex-literal = "0.3.1" [target.'cfg(target_os = "linux")'.dev-dependencies] -rlimit = "0.4.0" +rlimit = "0.8.3" [target.'cfg(unix)'.dev-dependencies] nix = "0.23.1" diff --git a/GNUmakefile b/GNUmakefile index 281952736..d3c26ce80 100644 --- a/GNUmakefile +++ b/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 PROFILE ?= debug @@ -22,10 +22,10 @@ CARGOFLAGS ?= # Install directories PREFIX ?= /usr/local DESTDIR ?= -BINDIR ?= /bin -MANDIR ?= /man/man1 +BINDIR ?= $(PREFIX)/bin +DATAROOTDIR ?= $(PREFIX)/share -INSTALLDIR_BIN=$(DESTDIR)$(PREFIX)$(BINDIR) +INSTALLDIR_BIN=$(DESTDIR)$(BINDIR) #prefix to apply to coreutils binary and all tool binaries PROG_PREFIX ?= @@ -65,6 +65,7 @@ PROGS := \ date \ dd \ df \ + dir \ dircolors \ dirname \ echo \ @@ -118,6 +119,7 @@ PROGS := \ tsort \ unexpand \ uniq \ + vdir \ wc \ whoami \ yes @@ -328,13 +330,13 @@ else $(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog);) $(if $(findstring test,$(INSTALLEES)), $(INSTALL) $(BUILDDIR)/test $(INSTALLDIR_BIN)/$(PROG_PREFIX)[) endif - mkdir -p $(DESTDIR)$(PREFIX)/share/zsh/site-functions - mkdir -p $(DESTDIR)$(PREFIX)/share/bash-completion/completions - mkdir -p $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d + mkdir -p $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions + mkdir -p $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions + mkdir -p $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d $(foreach prog, $(INSTALLEES), \ - $(BUILDDIR)/coreutils completion $(prog) zsh > $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(PROG_PREFIX)$(prog); \ - $(BUILDDIR)/coreutils completion $(prog) bash > $(DESTDIR)$(PREFIX)/share/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) zsh > $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions/_$(PROG_PREFIX)$(prog); \ + $(BUILDDIR)/coreutils completion $(prog) bash > $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/$(PROG_PREFIX)$(prog); \ + $(BUILDDIR)/coreutils completion $(prog) fish > $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/$(PROG_PREFIX)$(prog).fish; \ ) uninstall: @@ -343,8 +345,8 @@ ifeq (${MULTICALL}, y) endif rm -f $(addprefix $(INSTALLDIR_BIN)/$(PROG_PREFIX),$(PROGS)) rm -f $(INSTALLDIR_BIN)/$(PROG_PREFIX)[ - rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(PROG_PREFIX),$(PROGS)) - rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/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)/zsh/site-functions/_$(PROG_PREFIX),$(PROGS)) + rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/$(PROG_PREFIX),$(PROGS)) + rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS))) .PHONY: all build build-coreutils build-pkgs test distclean clean busytest install uninstall diff --git a/README.md b/README.md index 0683e42f8..f6df9fdcf 100644 --- a/README.md +++ b/README.md @@ -385,6 +385,7 @@ To improve the GNU compatibility, the following process is recommended: 1. Start to modify `` to understand what is wrong. Examples: 1. Add `set -v` to have the bash verbose mode 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. ... 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 -| 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 | | base32 | date | | @@ -417,8 +426,8 @@ To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md). | cut | tac | | | dircolors | tail | | | dirname | test | | -| du | | | -| echo | | | +| du | dir | | +| echo | vdir | | | env | | | | expand | | | | factor | | | diff --git a/docs/.gitignore b/docs/.gitignore index f2b5c7168..c669da8f6 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,3 +1,4 @@ book src/utils src/SUMMARY.md +tldr.zip \ No newline at end of file diff --git a/docs/theme/head.hbs b/docs/theme/head.hbs index 31cc2dad5..bb78156c9 100644 --- a/docs/theme/head.hbs +++ b/docs/theme/head.hbs @@ -5,10 +5,17 @@ main { position: relative; } - .version { + .additional { position: absolute; - top: 1em; + top: 0.5em; right: 0; + display: flex; + gap: 5px; + align-items: center; + font-size: 1.3em; + } + .platforms { + font-size: 2rem; } dd > p { margin-top: 0.2em; diff --git a/src/bin/uudoc.rs b/src/bin/uudoc.rs index 24c347fe7..150849e6f 100644 --- a/src/bin/uudoc.rs +++ b/src/bin/uudoc.rs @@ -5,23 +5,26 @@ // spell-checker:ignore tldr use clap::Command; +use std::collections::HashMap; use std::ffi::OsString; use std::fs::File; -use std::io::Cursor; use std::io::{self, Read, Seek, Write}; use zip::ZipArchive; include!(concat!(env!("OUT_DIR"), "/uutils_map.rs")); fn main() -> io::Result<()> { - println!("Downloading tldr archive"); - let mut zip_reader = ureq::get("https://tldr.sh/assets/tldr.zip") - .call() - .unwrap() - .into_reader(); - let mut buffer = Vec::new(); - zip_reader.read_to_end(&mut buffer).unwrap(); - let mut tldr_zip = ZipArchive::new(Cursor::new(buffer)).unwrap(); + let mut tldr_zip = File::open("docs/tldr.zip") + .ok() + .and_then(|f| ZipArchive::new(f).ok()); + + if tldr_zip.is_none() { + println!("Warning: No tldr archive found, so the documentation will not include examples."); + println!("To include examples in the documentation, download the tldr archive and put it in the docs/ folder."); + println!(); + println!(" curl https://tldr.sh/assets/tldr.zip -o docs/tldr.zip"); + println!(); + } let utils = util_map::>>(); match std::fs::create_dir("docs/src/utils/") { @@ -29,6 +32,7 @@ fn main() -> io::Result<()> { x => x, }?; + println!("Writing initial info to SUMMARY.md"); let mut summary = File::create("docs/src/SUMMARY.md")?; let _ = write!( @@ -44,6 +48,40 @@ fn main() -> io::Result<()> { * [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::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::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::>(); utils.sort(); for (&name, (_, command)) in utils { @@ -52,7 +90,14 @@ fn main() -> io::Result<()> { } let p = format!("docs/src/utils/{}.md", name); 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); } else { println!("Error writing to {}", p); @@ -62,88 +107,186 @@ fn main() -> io::Result<()> { Ok(()) } -fn write_markdown( - mut w: impl Write, - command: &mut Command, - name: &str, - tldr_zip: &mut zip::ZipArchive, -) -> io::Result<()> { - 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) +struct MDWriter<'a, 'b> { + w: Box, + command: Command<'a>, + name: &'a str, + tldr_zip: &'b mut Option>, + utils_per_platform: &'b HashMap<&'b str, Vec>, } -fn write_version(w: &mut impl Write, command: &Command) -> io::Result<()> { - writeln!( - w, - "
version: {}
", - command.render_version().split_once(' ').unwrap().1 - ) -} +impl<'a, 'b> MDWriter<'a, 'b> { + fn markdown(&mut self) -> io::Result<()> { + write!(self.w, "# {}\n\n", self.name)?; + self.additional()?; + self.usage()?; + self.description()?; + self.options()?; + self.examples() + } -fn write_usage(w: &mut impl Write, command: &mut Command, name: &str) -> io::Result<()> { - writeln!(w, "\n```")?; - let mut usage: String = command - .render_usage() - .lines() - .skip(1) - .map(|l| l.trim()) - .filter(|l| !l.is_empty()) - .collect::>() - .join("\n"); - usage = usage.replace(uucore::execution_phrase(), name); - writeln!(w, "{}", usage)?; - writeln!(w, "```") -} + fn additional(&mut self) -> io::Result<()> { + writeln!(self.w, "
")?; + self.platforms()?; + self.version()?; + writeln!(self.w, "
") + } + + fn platforms(&mut self) -> io::Result<()> { + writeln!(self.w, "
")?; + for (feature, icon) in [ + ("linux", "linux"), + // freebsd is disabled for now because mdbook does not use font-awesome 5 yet. + // ("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, "", icon)?; + } + } + writeln!(self.w, "
")?; -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(()) } -} -fn write_examples( - w: &mut impl Write, - name: &str, - tldr_zip: &mut zip::ZipArchive, -) -> io::Result<()> { - 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(()); - }; + fn version(&mut self) -> io::Result<()> { + writeln!( + self.w, + "
v{}
", + self.command.render_version().split_once(' ').unwrap().1 + ) + } - writeln!(w, "## Examples")?; - writeln!(w)?; - for line in content.lines().skip_while(|l| !l.starts_with('-')) { - if let Some(l) = line.strip_prefix("- ") { - writeln!(w, "{}", l)?; - } else if line.starts_with('`') { - writeln!(w, "```shell\n{}\n```", line.trim_matches('`'))?; - } else if line.is_empty() { - writeln!(w)?; + fn usage(&mut self) -> io::Result<()> { + writeln!(self.w, "\n```")?; + let mut usage: String = self + .command + .render_usage() + .lines() + .skip(1) + .map(|l| l.trim()) + .filter(|l| !l.is_empty()) + .collect::>() + .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 { - println!("Not sure what to do with this line:"); - println!("{}", line); + Ok(()) } } - writeln!(w)?; - writeln!( - 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!(w, ">")?; - writeln!( - w, - "> Please note that, as uutils is a work in progress, some examples might fail." - ) + + fn examples(&mut self) -> io::Result<()> { + if let Some(zip) = self.tldr_zip { + let content = if let Some(f) = + get_zip_content(zip, &format!("pages/common/{}.md", self.name)) + { + f + } else if let Some(f) = get_zip_content(zip, &format!("pages/linux/{}.md", self.name)) { + 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, "

Options

")?; + write!(self.w, "
")?; + for arg in self.command.get_arguments() { + write!(self.w, "
")?; + 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, "")?; + write!(self.w, "--{}", l)?; + if let Some(names) = arg.get_value_names() { + write!( + self.w, + "={}", + names + .iter() + .map(|x| format!("<{}>", x)) + .collect::>() + .join(" ") + )?; + } + write!(self.w, "")?; + } + for s in arg.get_short_and_visible_aliases().unwrap_or_default() { + if !first { + write!(self.w, ", ")?; + } else { + first = false; + } + write!(self.w, "")?; + write!(self.w, "-{}", s)?; + if let Some(names) = arg.get_value_names() { + write!( + self.w, + " {}", + names + .iter() + .map(|x| format!("<{}>", x)) + .collect::>() + .join(" ") + )?; + } + write!(self.w, "")?; + } + writeln!(self.w, "
")?; + writeln!( + self.w, + "
\n\n{}\n\n
", + arg.get_help().unwrap_or_default().replace('\n', "
") + )?; + } + writeln!(self.w, "
\n") + } } fn get_zip_content(archive: &mut ZipArchive, name: &str) -> Option { @@ -151,61 +294,3 @@ fn get_zip_content(archive: &mut ZipArchive, name: &str) -> Op archive.by_name(name).ok()?.read_to_string(&mut s).unwrap(); Some(s) } - -fn write_options(w: &mut impl Write, command: &Command) -> io::Result<()> { - writeln!(w, "

Options

")?; - write!(w, "
")?; - for arg in command.get_arguments() { - write!(w, "
")?; - 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, "")?; - write!(w, "--{}", l)?; - if let Some(names) = arg.get_value_names() { - write!( - w, - "={}", - names - .iter() - .map(|x| format!("<{}>", x)) - .collect::>() - .join(" ") - )?; - } - write!(w, "")?; - } - for s in arg.get_short_and_visible_aliases().unwrap_or_default() { - if !first { - write!(w, ", ")?; - } else { - first = false; - } - write!(w, "")?; - write!(w, "-{}", s)?; - if let Some(names) = arg.get_value_names() { - write!( - w, - " {}", - names - .iter() - .map(|x| format!("<{}>", x)) - .collect::>() - .join(" ") - )?; - } - write!(w, "")?; - } - writeln!(w, "
")?; - writeln!( - w, - "
\n\n{}\n\n
", - arg.get_help().unwrap_or_default().replace('\n', "
") - )?; - } - writeln!(w, "
\n") -} diff --git a/src/uu/arch/Cargo.toml b/src/uu/arch/Cargo.toml index 588520fa3..d57e747aa 100644 --- a/src/uu/arch/Cargo.toml +++ b/src/uu/arch/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/arch" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/arch.rs" diff --git a/src/uu/base32/Cargo.toml b/src/uu/base32/Cargo.toml index c5d54133e..ede70e70d 100644 --- a/src/uu/base32/Cargo.toml +++ b/src/uu/base32/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/base32" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/base32.rs" diff --git a/src/uu/base64/Cargo.toml b/src/uu/base64/Cargo.toml index 0169ee77b..9569467dc 100644 --- a/src/uu/base64/Cargo.toml +++ b/src/uu/base64/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/base64" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/base64.rs" diff --git a/src/uu/basename/Cargo.toml b/src/uu/basename/Cargo.toml index 226f61b20..517805164 100644 --- a/src/uu/basename/Cargo.toml +++ b/src/uu/basename/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/basename" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/basename.rs" diff --git a/src/uu/basenc/Cargo.toml b/src/uu/basenc/Cargo.toml index 4242e0391..1eeddbfae 100644 --- a/src/uu/basenc/Cargo.toml +++ b/src/uu/basenc/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/basenc" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/basenc.rs" diff --git a/src/uu/cat/Cargo.toml b/src/uu/cat/Cargo.toml index f76846491..ddf129bdb 100644 --- a/src/uu/cat/Cargo.toml +++ b/src/uu/cat/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cat" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/cat.rs" diff --git a/src/uu/chcon/Cargo.toml b/src/uu/chcon/Cargo.toml index 092f7702e..62283c6af 100644 --- a/src/uu/chcon/Cargo.toml +++ b/src/uu/chcon/Cargo.toml @@ -8,7 +8,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chcon" keywords = ["coreutils", "uutils", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/chcon.rs" diff --git a/src/uu/chgrp/Cargo.toml b/src/uu/chgrp/Cargo.toml index 952c83e54..e270069cf 100644 --- a/src/uu/chgrp/Cargo.toml +++ b/src/uu/chgrp/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chgrp" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/chgrp.rs" diff --git a/src/uu/chmod/Cargo.toml b/src/uu/chmod/Cargo.toml index 844c65544..66ba42736 100644 --- a/src/uu/chmod/Cargo.toml +++ b/src/uu/chmod/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chmod" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/chmod.rs" diff --git a/src/uu/chown/Cargo.toml b/src/uu/chown/Cargo.toml index 7db67752c..c0162f12a 100644 --- a/src/uu/chown/Cargo.toml +++ b/src/uu/chown/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chown" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/chown.rs" diff --git a/src/uu/chroot/Cargo.toml b/src/uu/chroot/Cargo.toml index 8976f8256..db7669704 100644 --- a/src/uu/chroot/Cargo.toml +++ b/src/uu/chroot/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/chroot" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/chroot.rs" diff --git a/src/uu/cksum/Cargo.toml b/src/uu/cksum/Cargo.toml index 50fdccf88..e694c7c38 100644 --- a/src/uu/cksum/Cargo.toml +++ b/src/uu/cksum/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cksum" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/cksum.rs" diff --git a/src/uu/comm/Cargo.toml b/src/uu/comm/Cargo.toml index a6de62a58..b4f1a96ce 100644 --- a/src/uu/comm/Cargo.toml +++ b/src/uu/comm/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/comm" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/comm.rs" diff --git a/src/uu/cp/Cargo.toml b/src/uu/cp/Cargo.toml index 452e1e8cf..b60006df1 100644 --- a/src/uu/cp/Cargo.toml +++ b/src/uu/cp/Cargo.toml @@ -13,7 +13,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cp" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/cp.rs" diff --git a/src/uu/csplit/Cargo.toml b/src/uu/csplit/Cargo.toml index 5c9ae227a..6c86900a3 100644 --- a/src/uu/csplit/Cargo.toml +++ b/src/uu/csplit/Cargo.toml @@ -9,7 +9,7 @@ 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 = "2018" +edition = "2021" [lib] path = "src/csplit.rs" @@ -17,7 +17,7 @@ path = "src/csplit.rs" [dependencies] clap = { version = "3.1", features = ["wrap_help", "cargo"] } thiserror = "1.0" -regex = "1.0.0" +regex = "1.5.5" uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["entries", "fs"] } [[bin]] diff --git a/src/uu/cut/Cargo.toml b/src/uu/cut/Cargo.toml index 3f800a786..65ba2c416 100644 --- a/src/uu/cut/Cargo.toml +++ b/src/uu/cut/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/cut" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/cut.rs" diff --git a/src/uu/date/Cargo.toml b/src/uu/date/Cargo.toml index a73a04d1b..cf723279f 100644 --- a/src/uu/date/Cargo.toml +++ b/src/uu/date/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/date" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/date.rs" diff --git a/src/uu/dd/Cargo.toml b/src/uu/dd/Cargo.toml index da2d43184..d311c9733 100644 --- a/src/uu/dd/Cargo.toml +++ b/src/uu/dd/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dd" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/dd.rs" diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 354e4b261..3b9bb02d8 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -23,7 +23,6 @@ mod blocks; use blocks::conv_block_unblock_helper; use std::cmp; -use std::convert::TryInto; use std::env; use std::fs::{File, OpenOptions}; use std::io::{self, Read, Seek, Write}; diff --git a/src/uu/dd/src/parseargs/unit_tests.rs b/src/uu/dd/src/parseargs/unit_tests.rs index 6a2ea5b54..95e783c58 100644 --- a/src/uu/dd/src/parseargs/unit_tests.rs +++ b/src/uu/dd/src/parseargs/unit_tests.rs @@ -10,7 +10,7 @@ fn unimplemented_flags_should_error_non_linux() { let mut succeeded = Vec::new(); // The following flags are only implemented in linux - for &flag in &[ + for flag in [ "direct", "directory", "dsync", @@ -47,7 +47,7 @@ fn unimplemented_flags_should_error() { let mut succeeded = Vec::new(); // 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![ String::from("dd"), format!("--iflag={}", flag), diff --git a/src/uu/df/Cargo.toml b/src/uu/df/Cargo.toml index 0490621ca..c6a1c570b 100644 --- a/src/uu/df/Cargo.toml +++ b/src/uu/df/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/df" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/df.rs" diff --git a/src/uu/df/src/columns.rs b/src/uu/df/src/columns.rs index 91c52ed2e..bd8cab438 100644 --- a/src/uu/df/src/columns.rs +++ b/src/uu/df/src/columns.rs @@ -183,4 +183,31 @@ impl Column { _ => 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, } diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index d125e73d0..ce6804770 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -12,9 +12,9 @@ mod filesystem; mod table; use uucore::display::Quotable; -use uucore::error::{UError, UResult}; -use uucore::format_usage; +use uucore::error::{UError, UResult, USimpleError}; use uucore::fsext::{read_fs_list, MountInfo}; +use uucore::{format_usage, show}; 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::columns::{Column, ColumnError}; 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\ or all file systems by default."; @@ -61,7 +61,6 @@ static OUTPUT_FIELD_LIST: [&str; 12] = [ struct Options { show_local_fs: bool, show_all_fs: bool, - show_listed_fs: bool, block_size: BlockSize, /// Optional list of filesystem types to include in the output table. @@ -88,7 +87,6 @@ impl Default for Options { Self { show_local_fs: Default::default(), show_all_fs: Default::default(), - show_listed_fs: Default::default(), block_size: Default::default(), include: Default::default(), exclude: Default::default(), @@ -111,6 +109,8 @@ enum OptionsError { /// An error getting the columns to display in the output table. ColumnError(ColumnError), + + FilesystemTypeBothSelectedAndExcluded(Vec), } impl fmt::Display for OptionsError { @@ -126,6 +126,16 @@ impl fmt::Display for OptionsError { "option --output: field {} used more than once", 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 { /// Convert command-line arguments into [`Options`]. fn from(matches: &ArgMatches) -> Result { + 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 { show_local_fs: matches.is_present(OPT_LOCAL), show_all_fs: matches.is_present(OPT_ALL), - show_listed_fs: false, block_size: block_size_from_matches(matches) .map_err(|_| OptionsError::InvalidBlockSize)?, - include: matches.values_of_lossy(OPT_TYPE), - exclude: matches.values_of_lossy(OPT_EXCLUDE_TYPE), + include, + exclude, show_total: matches.is_present(OPT_TOTAL), columns: Column::from_matches(matches).map_err(OptionsError::ColumnError)?, }) } + + fn get_intersected_types(include: &[String], exclude: &[String]) -> Option> { + 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. @@ -155,7 +185,7 @@ fn is_included(mi: &MountInfo, opt: &Options) -> bool { } // 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; } @@ -278,10 +308,17 @@ where // Convert each path into a `Filesystem`, which contains // both the mount information and usage information. - paths - .iter() - .filter_map(|p| Filesystem::from_path(&mounts, p)) - .collect() + let mut result = vec![]; + for path in paths { + match Filesystem::from_path(&mounts, path) { + Some(fs) => result.push(fs), + None => show!(USimpleError::new( + 1, + format!("{}: No such file or directory", path.as_ref().display()) + )), + } + } + result } #[derive(Debug)] @@ -309,6 +346,7 @@ impl fmt::Display for DfError { #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let matches = uu_app().get_matches_from(args); + #[cfg(windows)] { 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)?; - // Get the list of filesystems to display in the output table. let filesystems: Vec = 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) => { 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 accumulator is computed in case we need to display the - // total counts in the last row of the table. - let mut total = Row::new("total"); + // This can happen if paths are given as command-line arguments + // but none of the paths exist. + if filesystems.is_empty() { + return Ok(()); + } - println!("{}", Header::new(&opt)); - 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)); - } + println!("{}", Table::new(&opt, filesystems)); Ok(()) } @@ -367,6 +407,7 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_ALL) .short('a') .long("all") + .overrides_with(OPT_ALL) .help("include dummy file systems"), ) .arg( @@ -374,47 +415,56 @@ pub fn uu_app<'a>() -> Command<'a> { .short('B') .long("block-size") .takes_value(true) + .overrides_with_all(&[OPT_KILO, OPT_BLOCKSIZE]) .help( "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::new(OPT_TOTAL) .long("total") + .overrides_with(OPT_TOTAL) .help("produce a grand total"), ) .arg( Arg::new(OPT_HUMAN_READABLE_BINARY) .short('h') .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)"), ) .arg( Arg::new(OPT_HUMAN_READABLE_DECIMAL) .short('H') .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"), ) .arg( Arg::new(OPT_INODES) .short('i') .long("inodes") + .overrides_with(OPT_INODES) .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::new(OPT_LOCAL) .short('l') .long("local") + .overrides_with(OPT_LOCAL) .help("limit listing to local file systems"), ) .arg( Arg::new(OPT_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)"), ) .arg( @@ -438,12 +488,13 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_PORTABILITY) .short('P') .long("portability") + .overrides_with(OPT_PORTABILITY) .help("use the POSIX output format"), ) .arg( Arg::new(OPT_SYNC) .long("sync") - .conflicts_with(OPT_NO_SYNC) + .overrides_with_all(&[OPT_NO_SYNC, OPT_SYNC]) .help("invoke sync before getting usage info"), ) .arg( @@ -459,6 +510,7 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(OPT_PRINT_TYPE) .short('T') .long("print-type") + .overrides_with(OPT_PRINT_TYPE) .help("print file system type"), ) .arg( @@ -612,7 +664,6 @@ mod tests { fn test_dummy_included() { let opt = Options { show_all_fs: true, - show_listed_fs: true, ..Default::default() }; let m = mount_info("ext4", "/mnt/foo", false, true); @@ -708,22 +759,6 @@ mod tests { let m = mount_info("ext4", "/mnt/foo", false, false); 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 { diff --git a/src/uu/df/src/table.rs b/src/uu/df/src/table.rs index 0f4daa0e1..698da2bdb 100644 --- a/src/uu/df/src/table.rs +++ b/src/uu/df/src/table.rs @@ -5,13 +5,11 @@ // spell-checker:ignore tmpfs Pcent Itotal Iused Iavail Ipcent //! The filesystem usage data table. //! -//! A table comprises a header row ([`Header`]) and a collection of -//! data rows ([`Row`]), one per filesystem. To display a [`Row`], -//! combine it with [`Options`] in the [`DisplayRow`] struct; the -//! [`DisplayRow`] implements [`std::fmt::Display`]. +//! A table ([`Table`]) comprises a header row ([`Header`]) and a +//! collection of data rows ([`Row`]), one per filesystem. use number_prefix::NumberPrefix; -use crate::columns::Column; +use crate::columns::{Alignment, Column}; use crate::filesystem::Filesystem; use crate::{BlockSize, Options}; use uucore::fsext::{FsUsage, MountInfo}; @@ -154,6 +152,7 @@ impl From for Row { .. } = fs.usage; let bused = blocks - bfree; + let fused = files - ffree; Self { file: fs.file, fs_device: dev_name, @@ -177,25 +176,25 @@ impl From for Row { Some(bavail as f64 / ((bused + bavail) as f64)) }, inodes: files, - inodes_used: files - ffree, + inodes_used: fused, inodes_free: ffree, inodes_usage: if files == 0 { None } 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. -pub(crate) struct DisplayRow<'a> { +/// The `options` control how the information in the row gets formatted. +pub(crate) struct RowFormatter<'a> { /// The data in this row. row: &'a Row, - /// Options that control how to display the data. + /// Options that control how to format the data. options: &'a Options, // TODO We don't need all of the command-line options here. Some // of the command-line options indicate which rows to include or @@ -206,28 +205,48 @@ pub(crate) struct DisplayRow<'a> { // `df.rs` module. } -impl<'a> DisplayRow<'a> { +impl<'a> RowFormatter<'a> { /// Instantiate this struct. pub(crate) fn new(row: &'a Row, options: &'a Options) -> Self { 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. /// - /// # Errors - /// - /// If the scaling factor is not 1000, 1024, or a negative number. - fn scaled(&self, size: u64) -> Result { + /// This function is supposed to be used by `scaled_bytes()` and `scaled_inodes()` only. + fn scaled_human_readable(&self, size: u64) -> String { let number_prefix = match self.options.block_size { BlockSize::HumanReadableDecimal => NumberPrefix::decimal(size as f64), BlockSize::HumanReadableBinary => NumberPrefix::binary(size as f64), - BlockSize::Bytes(d) => return Ok((size / d).to_string()), + _ => unreachable!(), }; match number_prefix { - NumberPrefix::Standalone(bytes) => Ok(bytes.to_string()), - NumberPrefix::Prefixed(prefix, bytes) => Ok(format!("{:.1}{}", bytes, prefix.symbol())), + NumberPrefix::Standalone(bytes) => bytes.to_string(), + 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()), } } -} -impl fmt::Display for DisplayRow<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// Returns formatted row data. + fn get_values(&self) -> Vec { + let mut strings = Vec::new(); + for column in &self.options.columns { - match column { - Column::Source => write!(f, "{0: <16} ", self.row.fs_device)?, - Column::Size => write!(f, "{0: >12} ", self.scaled(self.row.bytes)?)?, - Column::Used => write!(f, "{0: >12} ", self.scaled(self.row.bytes_used)?)?, - Column::Avail => write!(f, "{0: >12} ", self.scaled(self.row.bytes_avail)?)?, - Column::Pcent => { - write!(f, "{0: >5} ", DisplayRow::percentage(self.row.bytes_usage))?; - } - Column::Target => write!(f, "{0: <16}", self.row.fs_mount)?, - Column::Itotal => write!(f, "{0: >12} ", self.scaled(self.row.inodes)?)?, - Column::Iused => write!(f, "{0: >12} ", self.scaled(self.row.inodes_used)?)?, - Column::Iavail => write!(f, "{0: >12} ", self.scaled(self.row.inodes_free)?)?, - Column::Ipcent => { - write!(f, "{0: >5} ", DisplayRow::percentage(self.row.inodes_usage))?; - } - Column::File => { - write!(f, "{0: <16}", self.row.file.as_ref().unwrap_or(&"-".into()))?; - } - Column::Fstype => write!(f, "{0: <5} ", self.row.fs_type)?, + let string = match column { + Column::Source => self.row.fs_device.to_string(), + Column::Size => self.scaled_bytes(self.row.bytes), + Column::Used => self.scaled_bytes(self.row.bytes_used), + Column::Avail => self.scaled_bytes(self.row.bytes_avail), + Column::Pcent => Self::percentage(self.row.bytes_usage), + + Column::Target => self.row.fs_mount.to_string(), + Column::Itotal => self.scaled_inodes(self.row.inodes), + Column::Iused => self.scaled_inodes(self.row.inodes_used), + Column::Iavail => self.scaled_inodes(self.row.inodes_free), + Column::Ipcent => Self::percentage(self.row.inodes_usage), + Column::File => self.row.file.as_ref().unwrap_or(&"-".into()).to_string(), + + Column::Fstype => self.row.fs_type.to_string(), #[cfg(target_os = "macos")] - Column::Capacity => write!( - f, - "{0: >12} ", - DisplayRow::percentage(self.row.bytes_capacity) - )?, - } + Column::Capacity => Self::percentage(self.row.bytes_capacity), + }; + + strings.push(string); } - Ok(()) + + strings } } -/// The header row. -/// -/// The `options` control which columns are displayed. -pub(crate) struct Header<'a> { - /// Options that control which columns are displayed. - options: &'a Options, -} +/// The data of the header row. +struct Header {} -impl<'a> Header<'a> { - /// Instantiate this struct. - pub(crate) fn new(options: &'a Options) -> Self { - Self { options } +impl Header { + /// Return the headers for the specified columns. + /// + /// The `options` control which column headers are returned. + fn get_headers(options: &Options) -> Vec { + 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<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for column in &self.options.columns { - match column { - Column::Source => write!(f, "{0: <16} ", "Filesystem")?, - // `Display` is implemented for `BlockSize`, but - // `Display` only works when formatting an object into - // an empty format, `{}`. So we use `format!()` first - // to create the string, then use `write!()` to align - // the string and pad with spaces. - Column::Size => write!(f, "{0: >12} ", format!("{}", self.options.block_size))?, - Column::Used => write!(f, "{0: >12} ", "Used")?, - Column::Avail => write!(f, "{0: >12} ", "Available")?, - Column::Pcent => write!(f, "{0: >5} ", "Use%")?, - Column::Target => write!(f, "{0: <16} ", "Mounted on")?, - Column::Itotal => write!(f, "{0: >12} ", "Inodes")?, - Column::Iused => write!(f, "{0: >12} ", "IUsed")?, - Column::Iavail => write!(f, "{0: >12} ", "IFree")?, - Column::Ipcent => write!(f, "{0: >5} ", "IUse%")?, - Column::File => write!(f, "{0: <16}", "File")?, - Column::Fstype => write!(f, "{0: <5} ", "Type")?, - #[cfg(target_os = "macos")] - Column::Capacity => write!(f, "{0: >12} ", "Capacity")?, +/// The output table. +pub(crate) struct Table { + alignments: Vec, + rows: Vec>, + widths: Vec, +} + +impl Table { + pub(crate) fn new(options: &Options, filesystems: Vec) -> Self { + let headers = Header::get_headers(options); + let mut widths: Vec<_> = options + .columns + .iter() + .enumerate() + .map(|(i, col)| Column::min_width(col).max(headers[i].len())) + .collect(); + + let mut rows = vec![headers]; + + // The running total of filesystem sizes and usage. + // + // This accumulator is computed in case we need to display the + // 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) -> Vec { + 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, "{: 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(()) } } @@ -324,7 +424,7 @@ impl fmt::Display for Header<'_> { mod tests { use crate::columns::Column; - use crate::table::{DisplayRow, Header, Row}; + use crate::table::{Header, Row, RowFormatter}; use crate::{BlockSize, Options}; const COLUMNS_WITH_FS_TYPE: [Column; 7] = [ @@ -346,76 +446,119 @@ mod tests { ]; #[test] - fn test_header_display() { + fn test_default_header() { let options = Default::default(); assert_eq!( - Header::new(&options).to_string(), - "Filesystem 1K-blocks Used Available Use% Mounted on " + Header::get_headers(&options), + vec!( + "Filesystem", + "1K-blocks", + "Used", + "Available", + "Use%", + "Mounted on" + ) ); } #[test] - fn test_header_display_fs_type() { + fn test_header_with_fs_type() { let options = Options { columns: COLUMNS_WITH_FS_TYPE.to_vec(), ..Default::default() }; assert_eq!( - Header::new(&options).to_string(), - "Filesystem Type 1K-blocks Used Available Use% Mounted on " + Header::get_headers(&options), + vec!( + "Filesystem", + "Type", + "1K-blocks", + "Used", + "Available", + "Use%", + "Mounted on" + ) ); } #[test] - fn test_header_display_inode() { + fn test_header_with_inodes() { let options = Options { columns: COLUMNS_WITH_INODES.to_vec(), ..Default::default() }; assert_eq!( - Header::new(&options).to_string(), - "Filesystem Inodes IUsed IFree IUse% Mounted on " + Header::get_headers(&options), + vec!( + "Filesystem", + "Inodes", + "IUsed", + "IFree", + "IUse%", + "Mounted on" + ) ); } #[test] - fn test_header_display_block_size_1024() { + fn test_header_with_block_size_1024() { let options = Options { block_size: BlockSize::Bytes(3 * 1024), ..Default::default() }; assert_eq!( - Header::new(&options).to_string(), - "Filesystem 3K-blocks Used Available Use% Mounted on " + Header::get_headers(&options), + vec!( + "Filesystem", + "3K-blocks", + "Used", + "Available", + "Use%", + "Mounted on" + ) ); } #[test] - fn test_header_display_human_readable_binary() { + fn test_header_with_human_readable_binary() { let options = Options { block_size: BlockSize::HumanReadableBinary, ..Default::default() }; assert_eq!( - Header::new(&options).to_string(), - "Filesystem Size Used Available Use% Mounted on " + Header::get_headers(&options), + vec!( + "Filesystem", + "Size", + "Used", + "Available", + "Use%", + "Mounted on" + ) ); } #[test] - fn test_header_display_human_readable_si() { + fn test_header_with_human_readable_si() { let options = Options { block_size: BlockSize::HumanReadableDecimal, ..Default::default() }; assert_eq!( - Header::new(&options).to_string(), - "Filesystem Size Used Available Use% Mounted on " + Header::get_headers(&options), + vec!( + "Filesystem", + "Size", + "Used", + "Available", + "Use%", + "Mounted on" + ) ); } #[test] - fn test_row_display() { + fn test_row_formatter() { let options = Options { block_size: BlockSize::Bytes(1), ..Default::default() @@ -439,14 +582,15 @@ mod tests { inodes_free: 8, inodes_usage: Some(0.2), }; + let fmt = RowFormatter::new(&row, &options); assert_eq!( - DisplayRow::new(&row, &options).to_string(), - "my_device 100 25 75 25% my_mount " + fmt.get_values(), + vec!("my_device", "100", "25", "75", "25%", "my_mount") ); } #[test] - fn test_row_display_fs_type() { + fn test_row_formatter_with_fs_type() { let options = Options { columns: COLUMNS_WITH_FS_TYPE.to_vec(), block_size: BlockSize::Bytes(1), @@ -471,14 +615,15 @@ mod tests { inodes_free: 8, inodes_usage: Some(0.2), }; + let fmt = RowFormatter::new(&row, &options); assert_eq!( - DisplayRow::new(&row, &options).to_string(), - "my_device my_type 100 25 75 25% my_mount " + fmt.get_values(), + vec!("my_device", "my_type", "100", "25", "75", "25%", "my_mount") ); } #[test] - fn test_row_display_inodes() { + fn test_row_formatter_with_inodes() { let options = Options { columns: COLUMNS_WITH_INODES.to_vec(), block_size: BlockSize::Bytes(1), @@ -503,14 +648,45 @@ mod tests { inodes_free: 8, inodes_usage: Some(0.2), }; + let fmt = RowFormatter::new(&row, &options); assert_eq!( - DisplayRow::new(&row, &options).to_string(), - "my_device 10 2 8 20% my_mount " + fmt.get_values(), + vec!("my_device", "10", "2", "8", "20%", "my_mount") ); } #[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 { block_size: BlockSize::HumanReadableDecimal, columns: COLUMNS_WITH_FS_TYPE.to_vec(), @@ -535,14 +711,23 @@ mod tests { inodes_free: 8, inodes_usage: Some(0.2), }; + let fmt = RowFormatter::new(&row, &options); assert_eq!( - DisplayRow::new(&row, &options).to_string(), - "my_device my_type 4.0k 1.0k 3.0k 25% my_mount " + fmt.get_values(), + vec!( + "my_device", + "my_type", + "4.0k", + "1.0k", + "3.0k", + "25%", + "my_mount" + ) ); } #[test] - fn test_row_display_human_readable_binary() { + fn test_row_formatter_with_human_readable_binary() { let options = Options { block_size: BlockSize::HumanReadableBinary, columns: COLUMNS_WITH_FS_TYPE.to_vec(), @@ -567,14 +752,23 @@ mod tests { inodes_free: 8, inodes_usage: Some(0.2), }; + let fmt = RowFormatter::new(&row, &options); assert_eq!( - DisplayRow::new(&row, &options).to_string(), - "my_device my_type 4.0Ki 1.0Ki 3.0Ki 25% my_mount " + fmt.get_values(), + vec!( + "my_device", + "my_type", + "4.0Ki", + "1.0Ki", + "3.0Ki", + "25%", + "my_mount" + ) ); } #[test] - fn test_row_display_round_up_usage() { + fn test_row_formatter_with_round_up_usage() { let options = Options { block_size: BlockSize::Bytes(1), ..Default::default() @@ -598,9 +792,10 @@ mod tests { inodes_free: 8, inodes_usage: Some(0.2), }; + let fmt = RowFormatter::new(&row, &options); assert_eq!( - DisplayRow::new(&row, &options).to_string(), - "my_device 100 25 75 26% my_mount " + fmt.get_values(), + vec!("my_device", "100", "25", "75", "26%", "my_mount") ); } } diff --git a/src/uu/dir/Cargo.toml b/src/uu/dir/Cargo.toml new file mode 100644 index 000000000..542abdc63 --- /dev/null +++ b/src/uu/dir/Cargo.toml @@ -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" diff --git a/src/uu/dir/LICENSE b/src/uu/dir/LICENSE new file mode 120000 index 000000000..5853aaea5 --- /dev/null +++ b/src/uu/dir/LICENSE @@ -0,0 +1 @@ +../../../LICENSE \ No newline at end of file diff --git a/src/uu/dir/src/dir.rs b/src/uu/dir/src/dir.rs new file mode 100644 index 000000000..749074726 --- /dev/null +++ b/src/uu/dir/src/dir.rs @@ -0,0 +1,70 @@ +// * This file is part of the uutils coreutils package. +// * +// * (c) gmnsii +// * +// * 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()) +} diff --git a/src/uu/dir/src/main.rs b/src/uu/dir/src/main.rs new file mode 100644 index 000000000..c5b5b6363 --- /dev/null +++ b/src/uu/dir/src/main.rs @@ -0,0 +1 @@ +uucore::bin!(uu_dir); diff --git a/src/uu/dircolors/Cargo.toml b/src/uu/dircolors/Cargo.toml index 533793b63..b5fe79b47 100644 --- a/src/uu/dircolors/Cargo.toml +++ b/src/uu/dircolors/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dircolors" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/dircolors.rs" diff --git a/src/uu/dirname/Cargo.toml b/src/uu/dirname/Cargo.toml index cede0c6b1..6e4c2f9f5 100644 --- a/src/uu/dirname/Cargo.toml +++ b/src/uu/dirname/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/dirname" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/dirname.rs" diff --git a/src/uu/du/Cargo.toml b/src/uu/du/Cargo.toml index c0c64f2e7..1760731e3 100644 --- a/src/uu/du/Cargo.toml +++ b/src/uu/du/Cargo.toml @@ -9,13 +9,15 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/du" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/du.rs" [dependencies] chrono = "^0.4.11" +# For the --exclude & --exclude-from options +glob = "0.3.0" clap = { version = "3.1", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.11", package="uucore", path="../../uucore" } diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index 0690c6299..ff7a5a5b7 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -11,11 +11,15 @@ extern crate uucore; use chrono::prelude::DateTime; use chrono::Local; use clap::{crate_version, Arg, ArgMatches, Command}; +use glob::Pattern; use std::collections::HashSet; use std::env; use std::fs; +use std::fs::File; #[cfg(not(windows))] use std::fs::Metadata; +use std::io::BufRead; +use std::io::BufReader; use std::io::{ErrorKind, Result}; use std::iter; #[cfg(not(windows))] @@ -24,14 +28,13 @@ use std::os::unix::fs::MetadataExt; use std::os::windows::fs::MetadataExt; #[cfg(windows)] use std::os::windows::io::AsRawHandle; -#[cfg(windows)] use std::path::Path; use std::path::PathBuf; use std::str::FromStr; use std::time::{Duration, UNIX_EPOCH}; use std::{error::Error, fmt::Display}; 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::parse_size::{parse_size, ParseSizeError}; use uucore::InvalidEncodingHandling; @@ -68,6 +71,9 @@ mod options { pub const ONE_FILE_SYSTEM: &str = "one-file-system"; pub const DEREFERENCE: &str = "dereference"; 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"; } @@ -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). Units are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB,... (powers 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 = "\ {} [OPTION]... [FILE]... @@ -97,6 +109,7 @@ struct Options { one_file_system: bool, dereference: bool, inodes: bool, + verbose: bool, } #[derive(PartialEq, Eq, Hash, Clone, Copy)] @@ -253,7 +266,7 @@ fn read_block_size(s: Option<&str>) -> u64 { parse_size(s) .unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::BLOCK_SIZE))) } 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(v) = parse_size(&env_size) { return v; @@ -287,6 +300,7 @@ fn du( options: &Options, depth: usize, inodes: &mut HashSet, + exclude: &[Pattern], ) -> Box> { let mut stats = vec![]; let mut futures = vec![]; @@ -301,49 +315,73 @@ fn du( my_stat.path.quote(), e ); + set_exit_code(1); return Box::new(iter::once(my_stat)); } }; - for f in read { + 'file_loop: for f in read { match f { - Ok(entry) => match Stat::new(entry.path(), options) { - Ok(this_stat) => { - if let Some(inode) = this_stat.inode { - if inodes.contains(&inode) { - continue; - } - inodes.insert(inode); - } - if this_stat.is_dir { - if options.one_file_system { - if let (Some(this_inode), Some(my_inode)) = - (this_stat.inode, my_stat.inode) + Ok(entry) => { + match Stat::new(entry.path(), options) { + Ok(this_stat) => { + // We have an exclude list + for pattern in exclude { + // Look at all patterns with both short and long paths + // if we have 'du foo' but search to exclude 'foo/bar' + // we need the full path + if pattern.matches(&this_stat.path.to_string_lossy()) + || pattern.matches(&entry.file_name().into_string().unwrap()) { - if this_inode.dev_id != my_inode.dev_id { - continue; + // if the directory is ignored, leave early + 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 { - my_stat.size += this_stat.size; - my_stat.blocks += this_stat.blocks; - my_stat.inodes += 1; - if options.all { - stats.push(this_stat); + + if let Some(inode) = this_stat.inode { + if inodes.contains(&inode) { + continue; + } + inodes.insert(inode); + } + 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), } } @@ -401,6 +439,7 @@ enum DuError { SummarizeDepthConflict(String), InvalidTimeStyleArg(String), InvalidTimeArg(String), + InvalidGlob(String), } impl Display for DuError { @@ -431,6 +470,7 @@ Try '{} --help' for more information.", 'birth' and 'creation' arguments are not supported on this platform.", s.quote() ), + DuError::InvalidGlob(s) => write!(f, "Invalid exclude syntax: {}", s), } } } @@ -443,11 +483,75 @@ impl UError for DuError { Self::InvalidMaxDepthArg(_) | Self::SummarizeDepthConflict(_) | 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) -> Vec { + 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> { + 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::::new(); + // Read the exclude lists from all the files + // and add them into a vector of string + let files: Vec = all_files.clone().map(|v| v.to_owned()).collect(); + for f in files { + exclusion.extend(file_as_vec(&f)); + } + exclusion + } + None => Vec::::new(), + } + } else { + Vec::::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::::new(), + } + } else { + Vec::::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] #[allow(clippy::cognitive_complexity)] 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), dereference: matches.is_present(options::DEREFERENCE), inodes: matches.is_present(options::INODES), + verbose: matches.is_present(options::VERBOSE), }; let files = match matches.value_of(options::FILE) { @@ -524,8 +629,25 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { "\n" }; + let excludes = get_glob_ignore(&matches)?; + 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); match Stat::new(path, &options) { Ok(stat) => { @@ -533,7 +655,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if let Some(inode) = stat.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 = len.unwrap(); 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, \ or entries greater than SIZE if negative") ) - // .arg( - // Arg::new("") - // .short('x') - // .long("exclude-from") - // .value_name("FILE") - // .help("exclude files that match any pattern in FILE") - // ) - // .arg( - // Arg::new("exclude") - // .long("exclude") - // .value_name("PATTERN") - // .help("exclude files that match PATTERN") - // ) + .arg( + Arg::new(options::VERBOSE) + .short('v') + .long("verbose") + .help("verbose mode (option not present in GNU/Coreutils)") + ) + .arg( + Arg::new(options::EXCLUDE) + .long(options::EXCLUDE) + .value_name("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::new(options::TIME) .long(options::TIME) diff --git a/src/uu/echo/Cargo.toml b/src/uu/echo/Cargo.toml index 9fde0ce35..374aa4881 100644 --- a/src/uu/echo/Cargo.toml +++ b/src/uu/echo/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/echo" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/echo.rs" diff --git a/src/uu/env/Cargo.toml b/src/uu/env/Cargo.toml index ae30458a0..e7f1df159 100644 --- a/src/uu/env/Cargo.toml +++ b/src/uu/env/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/env" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/env.rs" diff --git a/src/uu/expand/Cargo.toml b/src/uu/expand/Cargo.toml index aba67d6c7..9e21585e8 100644 --- a/src/uu/expand/Cargo.toml +++ b/src/uu/expand/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/expand" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/expand.rs" diff --git a/src/uu/expr/Cargo.toml b/src/uu/expr/Cargo.toml index 79107069f..c4a1bae4a 100644 --- a/src/uu/expr/Cargo.toml +++ b/src/uu/expr/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/expr" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/expr.rs" diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index b1d2d9560..e1620ed90 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [build-dependencies] num-traits = "0.2.13" # used in src/numerics.rs, which is included by build.rs diff --git a/src/uu/factor/src/miller_rabin.rs b/src/uu/factor/src/miller_rabin.rs index b5a01735a..8906abf59 100644 --- a/src/uu/factor/src/miller_rabin.rs +++ b/src/uu/factor/src/miller_rabin.rs @@ -69,7 +69,7 @@ pub(crate) fn test(m: A) -> Result { continue; } - let a = m.from_u64(_a); + let a = m.to_mod(_a); // x = a^r mod n let mut x = m.pow(a, r); diff --git a/src/uu/factor/src/numeric/montgomery.rs b/src/uu/factor/src/numeric/montgomery.rs index 504e6a09b..2a6782a02 100644 --- a/src/uu/factor/src/numeric/montgomery.rs +++ b/src/uu/factor/src/numeric/montgomery.rs @@ -16,7 +16,7 @@ pub(crate) trait Arithmetic: Copy + Sized { fn new(m: u64) -> Self; 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 add(&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 { - self.from_u64(1) + self.to_mod(1) } fn minus_one(&self) -> Self::ModInt { - self.from_u64(self.modulus() - 1) + self.to_mod(self.modulus() - 1) } fn zero(&self) -> Self::ModInt { - self.from_u64(0) + self.to_mod(0) } } @@ -113,7 +113,7 @@ impl Arithmetic for Montgomery { self.n.as_u64() } - fn from_u64(&self, x: u64) -> Self::ModInt { + fn to_mod(&self, x: u64) -> Self::ModInt { // TODO: optimise! debug_assert!(x < self.n.as_u64()); let r = T::from_double_width( @@ -189,9 +189,9 @@ mod tests { let n = 2 * n + 1; let m = Montgomery::::new(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 { - let m_y = m.from_u64(y); + let m_y = m.to_mod(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))); } @@ -205,9 +205,9 @@ mod tests { let n = 2 * n + 1; let m = Montgomery::::new(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 { - 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))); } } @@ -220,7 +220,7 @@ mod tests { let n = 2 * n + 1; let m = Montgomery::::new(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_)); } } diff --git a/src/uu/factor/src/rho.rs b/src/uu/factor/src/rho.rs index b28e88e91..e7aa00b4d 100644 --- a/src/uu/factor/src/rho.rs +++ b/src/uu/factor/src/rho.rs @@ -18,7 +18,7 @@ pub(crate) fn find_divisor(n: A) -> u64 { let mut rand = { let range = Uniform::new(1, n.modulus()); 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); diff --git a/src/uu/false/Cargo.toml b/src/uu/false/Cargo.toml index 3a4c7cc4e..26c2762b5 100644 --- a/src/uu/false/Cargo.toml +++ b/src/uu/false/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/false" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/false.rs" diff --git a/src/uu/fmt/Cargo.toml b/src/uu/fmt/Cargo.toml index 714b75ffe..6a85f1c66 100644 --- a/src/uu/fmt/Cargo.toml +++ b/src/uu/fmt/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/fmt" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/fmt.rs" diff --git a/src/uu/fold/Cargo.toml b/src/uu/fold/Cargo.toml index 0ac9a0006..67cc74ec9 100644 --- a/src/uu/fold/Cargo.toml +++ b/src/uu/fold/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/fold" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/fold.rs" diff --git a/src/uu/groups/Cargo.toml b/src/uu/groups/Cargo.toml index 0eee2a960..e1effbb23 100644 --- a/src/uu/groups/Cargo.toml +++ b/src/uu/groups/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/groups" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/groups.rs" diff --git a/src/uu/hashsum/Cargo.toml b/src/uu/hashsum/Cargo.toml index 6b0181629..c38c8499a 100644 --- a/src/uu/hashsum/Cargo.toml +++ b/src/uu/hashsum/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hashsum" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/hashsum.rs" @@ -20,7 +20,7 @@ clap = { version = "3.1", features = ["wrap_help", "cargo"] } hex = "0.4.3" memchr = "2" md-5 = "0.10.1" -regex = "1.0.1" +regex = "1.5.5" sha1 = "0.10.1" sha2 = "0.10.2" sha3 = "0.10.1" diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 722585033..244e4b928 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -7,7 +7,7 @@ // * For the full copyright and license information, please view the LICENSE // * 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] extern crate clap; @@ -46,6 +46,7 @@ struct Options { binary: bool, check: bool, tag: bool, + nonames: bool, status: bool, quiet: bool, strict: bool, @@ -316,6 +317,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { }; let check = matches.is_present("check"); let tag = matches.is_present("tag"); + let nonames = matches.is_present("no-names"); let status = matches.is_present("status"); let quiet = matches.is_present("quiet") || status; let strict = matches.is_present("strict"); @@ -328,6 +330,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { binary, check, tag, + nonames, status, quiet, strict, @@ -370,6 +373,11 @@ pub fn uu_app_common<'a>() -> Command<'a> { .long("tag") .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::new("text") .short('t') @@ -602,6 +610,8 @@ where .map_err_context(|| "failed to read input".to_string())?; if options.tag { println!("{} ({}) = {}", options.algoname, filename.display(), sum); + } else if options.nonames { + println!("{}", sum); } else { println!("{} {}{}", sum, binary_marker, filename.display()); } diff --git a/src/uu/head/Cargo.toml b/src/uu/head/Cargo.toml index 9159296d2..d02aaa9e0 100644 --- a/src/uu/head/Cargo.toml +++ b/src/uu/head/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/head" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/head.rs" diff --git a/src/uu/head/src/head.rs b/src/uu/head/src/head.rs index 1ddfc0492..b6d36a4ad 100644 --- a/src/uu/head/src/head.rs +++ b/src/uu/head/src/head.rs @@ -6,7 +6,6 @@ // spell-checker:ignore (vars) zlines BUFWRITER seekable use clap::{crate_version, Arg, ArgMatches, Command}; -use std::convert::{TryFrom, TryInto}; use std::ffi::OsString; use std::io::{self, BufWriter, ErrorKind, Read, Seek, SeekFrom, Write}; use uucore::display::Quotable; diff --git a/src/uu/hostid/Cargo.toml b/src/uu/hostid/Cargo.toml index 6449684f6..f9c2555d4 100644 --- a/src/uu/hostid/Cargo.toml +++ b/src/uu/hostid/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hostid" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/hostid.rs" diff --git a/src/uu/hostname/Cargo.toml b/src/uu/hostname/Cargo.toml index 0ff8f2f4d..d0c1234b6 100644 --- a/src/uu/hostname/Cargo.toml +++ b/src/uu/hostname/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/hostname" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/hostname.rs" diff --git a/src/uu/id/Cargo.toml b/src/uu/id/Cargo.toml index 332ba9ca6..de18a8269 100644 --- a/src/uu/id/Cargo.toml +++ b/src/uu/id/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/id" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/id.rs" diff --git a/src/uu/install/Cargo.toml b/src/uu/install/Cargo.toml index f82c6de34..009005a4c 100644 --- a/src/uu/install/Cargo.toml +++ b/src/uu/install/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/install" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/install.rs" diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index e3154aa51..808898cfb 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -464,6 +464,19 @@ fn standard(mut paths: Vec, b: &Behavior) -> UResult<()> { } else { if let Some(parent) = target.parent() { 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) { 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() { Ok(o) => { if !o.status.success() { + // Follow GNU's behavior: if strip fails, removes the target + let _ = fs::remove_file(to); return Err(InstallError::StripProgramFailed( String::from_utf8(o.stderr).unwrap_or_default(), ) .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()); + } } } diff --git a/src/uu/join/Cargo.toml b/src/uu/join/Cargo.toml index c4d8cb57c..1a28689a8 100644 --- a/src/uu/join/Cargo.toml +++ b/src/uu/join/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/join" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/join.rs" diff --git a/src/uu/kill/Cargo.toml b/src/uu/kill/Cargo.toml index 9eea3172b..561209eb3 100644 --- a/src/uu/kill/Cargo.toml +++ b/src/uu/kill/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/kill" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/kill.rs" diff --git a/src/uu/link/Cargo.toml b/src/uu/link/Cargo.toml index caec3e2a6..6cc51462e 100644 --- a/src/uu/link/Cargo.toml +++ b/src/uu/link/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/link" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/link.rs" diff --git a/src/uu/ln/Cargo.toml b/src/uu/ln/Cargo.toml index 9fd6b3d12..453222df8 100644 --- a/src/uu/ln/Cargo.toml +++ b/src/uu/ln/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ln" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/ln.rs" diff --git a/src/uu/logname/Cargo.toml b/src/uu/logname/Cargo.toml index d800d41b0..34ca9355a 100644 --- a/src/uu/logname/Cargo.toml +++ b/src/uu/logname/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/logname" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/logname.rs" diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index d082c8260..ec092d06a 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -9,7 +9,7 @@ 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 = "2018" +edition = "2021" [lib] path = "src/ls.rs" @@ -22,7 +22,7 @@ number_prefix = "0.4" term_grid = "0.1.5" termsize = "0.1.6" 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"] } once_cell = "1.10.0" atty = "0.2" diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 778283039..a55f29e23 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -13,7 +13,8 @@ extern crate uucore; #[macro_use] extern crate lazy_static; -mod quoting_style; +// dir and vdir also need access to the quoting_style module +pub mod quoting_style; use clap::{crate_version, Arg, Command}; use glob::Pattern; @@ -242,7 +243,7 @@ impl Display for LsError { } #[derive(PartialEq, Eq)] -enum Format { +pub enum Format { Columns, Long, OneLine, @@ -304,8 +305,9 @@ enum IndicatorStyle { Classify, } -struct Config { - format: Format, +pub struct Config { + // Dir and vdir needs access to this field + pub format: Format, files: Files, sort: Sort, recursive: bool, @@ -322,7 +324,8 @@ struct Config { alloc_size: bool, block_size: Option, width: u16, - quoting_style: QuotingStyle, + // Dir and vdir needs access to this field + pub quoting_style: QuotingStyle, indicator_style: IndicatorStyle, time_style: TimeStyle, context: bool, @@ -355,7 +358,7 @@ struct PaddingCollection { impl Config { #[allow(clippy::cognitive_complexity)] - fn from(options: &clap::ArgMatches) -> UResult { + pub fn from(options: &clap::ArgMatches) -> UResult { let context = options.is_present(options::CONTEXT); let (mut format, opt) = if let Some(format_) = options.value_of(options::FORMAT) { ( @@ -800,615 +803,611 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uu_app<'a>() -> Command<'a> { Command::new(uucore::util_name()) .version(crate_version!()) - .override_usage(format_usage(USAGE)) - .about( - "By default, ls will list the files and contents of any directories on \ - the command line, expect that it will ignore files and directories \ - whose names start with '.'.", - ) - .infer_long_args(true) - .arg( - Arg::new(options::HELP) - .long(options::HELP) - .help("Print help information.") - ) - // Format arguments - .arg( - Arg::new(options::FORMAT) - .long(options::FORMAT) - .help("Set the display format.") - .takes_value(true) - .possible_values(&[ - "long", - "verbose", - "single-column", - "columns", - "vertical", - "across", - "horizontal", - "commas", - ]) - .hide_possible_values(true) - .require_equals(true) - .overrides_with_all(&[ - options::FORMAT, - options::format::COLUMNS, - options::format::LONG, - options::format::ACROSS, - options::format::COLUMNS, - ]), - ) - .arg( - Arg::new(options::format::COLUMNS) - .short('C') - .help("Display the files in columns.") - .overrides_with_all(&[ - options::FORMAT, - options::format::COLUMNS, - options::format::LONG, - options::format::ACROSS, - options::format::COLUMNS, - ]), - ) - .arg( - Arg::new(options::format::LONG) - .short('l') - .long(options::format::LONG) - .help("Display detailed information.") - .overrides_with_all(&[ - options::FORMAT, - options::format::COLUMNS, - options::format::LONG, - options::format::ACROSS, - options::format::COLUMNS, - ]), - ) - .arg( - Arg::new(options::format::ACROSS) - .short('x') - .help("List entries in rows instead of in columns.") - .overrides_with_all(&[ - options::FORMAT, - options::format::COLUMNS, - options::format::LONG, - options::format::ACROSS, - options::format::COLUMNS, - ]), - ) - .arg( - Arg::new(options::format::COMMAS) - .short('m') - .help("List entries separated by commas.") - .overrides_with_all(&[ - options::FORMAT, - options::format::COLUMNS, - options::format::LONG, - options::format::ACROSS, - options::format::COLUMNS, - ]), - ) - // The next four arguments do not override with the other format - // options, see the comment in Config::from for the reason. - // Ideally, they would use Arg::override_with, with their own name - // but that doesn't seem to work in all cases. Example: - // ls -1g1 - // even though `ls -11` and `ls -1 -g -1` work. - .arg( - Arg::new(options::format::ONE_LINE) - .short('1') - .help("List one file per line.") - .multiple_occurrences(true), - ) - .arg( - Arg::new(options::format::LONG_NO_GROUP) - .short('o') - .help( - "Long format without group information. \ - Identical to --format=long with --no-group.", - ) - .multiple_occurrences(true), - ) - .arg( - Arg::new(options::format::LONG_NO_OWNER) - .short('g') - .help("Long format without owner information.") - .multiple_occurrences(true), - ) - .arg( - Arg::new(options::format::LONG_NUMERIC_UID_GID) - .short('n') - .long(options::format::LONG_NUMERIC_UID_GID) - .help("-l with numeric UIDs and GIDs.") - .multiple_occurrences(true), - ) - // Quoting style - .arg( - Arg::new(options::QUOTING_STYLE) - .long(options::QUOTING_STYLE) - .takes_value(true) - .help("Set quoting style.") - .possible_values(&[ - "literal", - "shell", - "shell-always", - "shell-escape", - "shell-escape-always", - "c", - "escape", - ]) - .overrides_with_all(&[ - options::QUOTING_STYLE, - options::quoting::LITERAL, - options::quoting::ESCAPE, - options::quoting::C, - ]), - ) - .arg( - Arg::new(options::quoting::LITERAL) - .short('N') - .long(options::quoting::LITERAL) - .help("Use literal quoting style. Equivalent to `--quoting-style=literal`") - .overrides_with_all(&[ - options::QUOTING_STYLE, - options::quoting::LITERAL, - options::quoting::ESCAPE, - options::quoting::C, - ]), - ) - .arg( - Arg::new(options::quoting::ESCAPE) - .short('b') - .long(options::quoting::ESCAPE) - .help("Use escape quoting style. Equivalent to `--quoting-style=escape`") - .overrides_with_all(&[ - options::QUOTING_STYLE, - options::quoting::LITERAL, - options::quoting::ESCAPE, - options::quoting::C, - ]), - ) - .arg( - Arg::new(options::quoting::C) - .short('Q') - .long(options::quoting::C) - .help("Use C quoting style. Equivalent to `--quoting-style=c`") - .overrides_with_all(&[ - options::QUOTING_STYLE, - options::quoting::LITERAL, - options::quoting::ESCAPE, - options::quoting::C, - ]), - ) - // Control characters - .arg( - Arg::new(options::HIDE_CONTROL_CHARS) - .short('q') - .long(options::HIDE_CONTROL_CHARS) - .help("Replace control characters with '?' if they are not escaped.") - .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]), - ) - .arg( - Arg::new(options::SHOW_CONTROL_CHARS) - .long(options::SHOW_CONTROL_CHARS) - .help("Show control characters 'as is' if they are not escaped.") - .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]), - ) - // Time arguments - .arg( - Arg::new(options::TIME) - .long(options::TIME) - .help( - "Show time in :\n\ - \taccess time (-u): atime, access, use;\n\ - \tchange time (-t): ctime, status.\n\ - \tbirth time: birth, creation;", - ) - .value_name("field") - .takes_value(true) - .possible_values(&[ - "atime", "access", "use", "ctime", "status", "birth", "creation", - ]) - .hide_possible_values(true) - .require_equals(true) - .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), - ) - .arg( - Arg::new(options::time::CHANGE) - .short('c') - .help( - "If the long listing format (e.g., -l, -o) is being used, print the status \ - change time (the 'ctime' in the inode) instead of the modification time. When \ - explicitly sorting by time (--sort=time or -t) or when not using a long listing \ - format, sort according to the status change time.", - ) - .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), - ) - .arg( - Arg::new(options::time::ACCESS) - .short('u') - .help( - "If the long listing format (e.g., -l, -o) is being used, print the status \ - access time instead of the modification time. When explicitly sorting by time \ - (--sort=time or -t) or when not using a long listing format, sort according to the \ - access time.", - ) - .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), - ) - // Hide and ignore - .arg( - Arg::new(options::HIDE) - .long(options::HIDE) - .takes_value(true) - .multiple_occurrences(true) - .value_name("PATTERN") - .help( - "do not list implied entries matching shell PATTERN (overridden by -a or -A)", - ), - ) - .arg( - Arg::new(options::IGNORE) - .short('I') - .long(options::IGNORE) - .takes_value(true) - .multiple_occurrences(true) - .value_name("PATTERN") - .help("do not list implied entries matching shell PATTERN"), - ) - .arg( - Arg::new(options::IGNORE_BACKUPS) - .short('B') - .long(options::IGNORE_BACKUPS) - .help("Ignore entries which end with ~."), - ) - // Sort arguments - .arg( - Arg::new(options::SORT) - .long(options::SORT) - .help("Sort by : name, none (-U), time (-t), size (-S) or extension (-X)") - .value_name("field") - .takes_value(true) - .possible_values(&["name", "none", "time", "size", "version", "extension"]) - .require_equals(true) - .overrides_with_all(&[ - options::SORT, - options::sort::SIZE, - options::sort::TIME, - options::sort::NONE, - options::sort::VERSION, - options::sort::EXTENSION, - ]), - ) - .arg( - Arg::new(options::sort::SIZE) - .short('S') - .help("Sort by file size, largest first.") - .overrides_with_all(&[ - options::SORT, - options::sort::SIZE, - options::sort::TIME, - options::sort::NONE, - options::sort::VERSION, - options::sort::EXTENSION, - ]), - ) - .arg( - Arg::new(options::sort::TIME) - .short('t') - .help("Sort by modification time (the 'mtime' in the inode), newest first.") - .overrides_with_all(&[ - options::SORT, - options::sort::SIZE, - options::sort::TIME, - options::sort::NONE, - options::sort::VERSION, - options::sort::EXTENSION, - ]), - ) - .arg( - Arg::new(options::sort::VERSION) - .short('v') - .help("Natural sort of (version) numbers in the filenames.") - .overrides_with_all(&[ - options::SORT, - options::sort::SIZE, - options::sort::TIME, - options::sort::NONE, - options::sort::VERSION, - options::sort::EXTENSION, - ]), - ) - .arg( - Arg::new(options::sort::EXTENSION) - .short('X') - .help("Sort alphabetically by entry extension.") - .overrides_with_all(&[ - options::SORT, - options::sort::SIZE, - options::sort::TIME, - options::sort::NONE, - options::sort::VERSION, - options::sort::EXTENSION, - ]), - ) - .arg( - Arg::new(options::sort::NONE) - .short('U') - .help( - "Do not sort; list the files in whatever order they are stored in the \ - directory. This is especially useful when listing very large directories, \ - since not doing any sorting can be noticeably faster.", - ) - .overrides_with_all(&[ - options::SORT, - options::sort::SIZE, - options::sort::TIME, - options::sort::NONE, - options::sort::VERSION, - options::sort::EXTENSION, - ]), - ) - // Dereferencing - .arg( - Arg::new(options::dereference::ALL) - .short('L') - .long(options::dereference::ALL) - .help( - "When showing file information for a symbolic link, show information for the \ - file the link references rather than the link itself.", - ) - .overrides_with_all(&[ - options::dereference::ALL, - options::dereference::DIR_ARGS, - options::dereference::ARGS, - ]), - ) - .arg( - Arg::new(options::dereference::DIR_ARGS) - .long(options::dereference::DIR_ARGS) - .help( - "Do not dereference symlinks except when they link to directories and are \ - given as command line arguments.", - ) - .overrides_with_all(&[ - options::dereference::ALL, - options::dereference::DIR_ARGS, - options::dereference::ARGS, - ]), - ) - .arg( - Arg::new(options::dereference::ARGS) - .short('H') - .long(options::dereference::ARGS) - .help("Do not dereference symlinks except when given as command line arguments.") - .overrides_with_all(&[ - options::dereference::ALL, - options::dereference::DIR_ARGS, - options::dereference::ARGS, - ]), - ) - // Long format options - .arg( - Arg::new(options::NO_GROUP) - .long(options::NO_GROUP) - .short('G') - .help("Do not show group in long format."), - ) - .arg(Arg::new(options::AUTHOR).long(options::AUTHOR).help( - "Show author in long format. \ - On the supported platforms, the author always matches the file owner.", - )) - // Other Flags - .arg( - Arg::new(options::files::ALL) - .short('a') - .long(options::files::ALL) - // Overrides -A (as the order matters) - .overrides_with(options::files::ALMOST_ALL) - .multiple_occurrences(true) - .help("Do not ignore hidden files (files with names that start with '.')."), - ) - .arg( - Arg::new(options::files::ALMOST_ALL) - .short('A') - .long(options::files::ALMOST_ALL) - // Overrides -a (as the order matters) - .overrides_with(options::files::ALL) - .multiple_occurrences(true) - .help( - "In a directory, do not ignore all file names that start with '.', \ -only ignore '.' and '..'.", - ), - ) - .arg( - Arg::new(options::DIRECTORY) - .short('d') - .long(options::DIRECTORY) - .help( - "Only list the names of directories, rather than listing directory contents. \ - This will not follow symbolic links unless one of `--dereference-command-line \ - (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is \ - specified.", - ), - ) - .arg( - Arg::new(options::size::HUMAN_READABLE) - .short('h') - .long(options::size::HUMAN_READABLE) - .help("Print human readable file sizes (e.g. 1K 234M 56G).") - .overrides_with(options::size::SI), - ) - .arg( - Arg::new(options::size::KIBIBYTES) - .short('k') - .long(options::size::KIBIBYTES) - .help("default to 1024-byte blocks for file system usage; used only with -s and per directory totals"), - ) - .arg( - Arg::new(options::size::SI) - .long(options::size::SI) - .help("Print human readable file sizes using powers of 1000 instead of 1024."), - ) - .arg( - Arg::new(options::size::BLOCK_SIZE) - .long(options::size::BLOCK_SIZE) - .takes_value(true) - .require_equals(true) - .value_name("BLOCK_SIZE") - .help("scale sizes by BLOCK_SIZE when printing them"), - ) - .arg( - Arg::new(options::INODE) - .short('i') - .long(options::INODE) - .help("print the index number of each file"), - ) - .arg( - Arg::new(options::REVERSE) - .short('r') - .long(options::REVERSE) - .help( - "Reverse whatever the sorting method is e.g., list files in reverse \ - alphabetical order, youngest first, smallest first, or whatever.", - ), - ) - .arg( - Arg::new(options::RECURSIVE) - .short('R') - .long(options::RECURSIVE) - .help("List the contents of all directories recursively."), - ) - .arg( - Arg::new(options::WIDTH) - .long(options::WIDTH) - .short('w') - .help("Assume that the terminal is COLS columns wide.") - .value_name("COLS") - .takes_value(true), - ) - .arg( - Arg::new(options::size::ALLOCATION_SIZE) - .short('s') - .long(options::size::ALLOCATION_SIZE) - .help("print the allocated size of each file, in blocks"), - ) - .arg( - Arg::new(options::COLOR) - .long(options::COLOR) - .help("Color output based on file type.") - .takes_value(true) - .possible_values(&[ - "always", "yes", "force", "auto", "tty", "if-tty", "never", "no", "none", - ]) - .require_equals(true) - .min_values(0), - ) - .arg( - Arg::new(options::INDICATOR_STYLE) - .long(options::INDICATOR_STYLE) - .help( - "Append indicator with style WORD to entry names: \ - none (default), slash (-p), file-type (--file-type), classify (-F)", - ) - .takes_value(true) - .possible_values(&["none", "slash", "file-type", "classify"]) - .overrides_with_all(&[ - options::indicator_style::FILE_TYPE, - options::indicator_style::SLASH, - options::indicator_style::CLASSIFY, - options::INDICATOR_STYLE, - ]), - ) - .arg( - // The --classify flag can take an optional when argument to - // control its behavior from version 9 of GNU coreutils. - // There is currently an inconsistency where GNU coreutils allows only - // the long form of the flag to take the argument while we allow it - // for both the long and short form of the flag. - Arg::new(options::indicator_style::CLASSIFY) - .short('F') - .long(options::indicator_style::CLASSIFY) - .help( - "Append a character to each file name indicating the file type. Also, for \ - regular files that are executable, append '*'. The file type indicators are \ - '/' for directories, '@' for symbolic links, '|' for FIFOs, '=' for sockets, \ - '>' for doors, and nothing for regular files. when may be omitted, or one of:\n\ - \tnone - Do not classify. This is the default.\n\ - \tauto - Only classify if standard output is a terminal.\n\ - \talways - Always classify.\n\ - Specifying --classify and no when is equivalent to --classify=always. This will not follow\ - symbolic links listed on the command line unless the --dereference-command-line (-H),\ - --dereference (-L), or --dereference-command-line-symlink-to-dir options are specified.", - ) - .takes_value(true) - .value_name("when") - .possible_values(&[ - "always", "yes", "force", "auto", "tty", "if-tty", "never", "no", "none", - ]) - .default_missing_value("always") - .require_equals(true) - .min_values(0) - .overrides_with_all(&[ - options::indicator_style::FILE_TYPE, - options::indicator_style::SLASH, - options::indicator_style::CLASSIFY, - options::INDICATOR_STYLE, - ]), - ) - .arg( - Arg::new(options::indicator_style::FILE_TYPE) - .long(options::indicator_style::FILE_TYPE) - .help("Same as --classify, but do not append '*'") - .overrides_with_all(&[ - options::indicator_style::FILE_TYPE, - options::indicator_style::SLASH, - options::indicator_style::CLASSIFY, - options::INDICATOR_STYLE, - ]), - ) - .arg( - Arg::new(options::indicator_style::SLASH) - .short('p') - .help("Append / indicator to directories.") - .overrides_with_all(&[ - options::indicator_style::FILE_TYPE, - options::indicator_style::SLASH, - options::indicator_style::CLASSIFY, - options::INDICATOR_STYLE, - ]), - ) - .arg( - //This still needs support for posix-*, +FORMAT - Arg::new(options::TIME_STYLE) - .long(options::TIME_STYLE) - .help("time/date format with -l; see TIME_STYLE below") - .value_name("TIME_STYLE") - .env("TIME_STYLE") - .possible_values(&["full-iso", "long-iso", "iso", "locale"]) - .overrides_with_all(&[options::TIME_STYLE]), - ) - .arg( - Arg::new(options::FULL_TIME) - .long(options::FULL_TIME) - .overrides_with(options::FULL_TIME) - .help("like -l --time-style=full-iso"), - ) - .arg( - Arg::new(options::CONTEXT) - .short('Z') - .long(options::CONTEXT) - .help(CONTEXT_HELP_TEXT), - ) - // Positional arguments - .arg( - Arg::new(options::PATHS) - .multiple_occurrences(true) - .takes_value(true) - .allow_invalid_utf8(true), - ) - .after_help( - "The TIME_STYLE argument can be full-iso, long-iso, iso. \ - Also the TIME_STYLE environment variable sets the default style to use.", - ) + .override_usage(format_usage(USAGE)) + .about("List directory contents. Ignore files and directories starting with a '.' by default") + .infer_long_args(true) + .arg( + Arg::new(options::HELP) + .long(options::HELP) + .help("Print help information.") + ) + // Format arguments + .arg( + Arg::new(options::FORMAT) + .long(options::FORMAT) + .help("Set the display format.") + .takes_value(true) + .possible_values(&[ + "long", + "verbose", + "single-column", + "columns", + "vertical", + "across", + "horizontal", + "commas", + ]) + .hide_possible_values(true) + .require_equals(true) + .overrides_with_all(&[ + options::FORMAT, + options::format::COLUMNS, + options::format::LONG, + options::format::ACROSS, + options::format::COLUMNS, + ]), + ) + .arg( + Arg::new(options::format::COLUMNS) + .short('C') + .help("Display the files in columns.") + .overrides_with_all(&[ + options::FORMAT, + options::format::COLUMNS, + options::format::LONG, + options::format::ACROSS, + options::format::COLUMNS, + ]), + ) + .arg( + Arg::new(options::format::LONG) + .short('l') + .long(options::format::LONG) + .help("Display detailed information.") + .overrides_with_all(&[ + options::FORMAT, + options::format::COLUMNS, + options::format::LONG, + options::format::ACROSS, + options::format::COLUMNS, + ]), + ) + .arg( + Arg::new(options::format::ACROSS) + .short('x') + .help("List entries in rows instead of in columns.") + .overrides_with_all(&[ + options::FORMAT, + options::format::COLUMNS, + options::format::LONG, + options::format::ACROSS, + options::format::COLUMNS, + ]), + ) + .arg( + Arg::new(options::format::COMMAS) + .short('m') + .help("List entries separated by commas.") + .overrides_with_all(&[ + options::FORMAT, + options::format::COLUMNS, + options::format::LONG, + options::format::ACROSS, + options::format::COLUMNS, + ]), + ) + // The next four arguments do not override with the other format + // options, see the comment in Config::from for the reason. + // Ideally, they would use Arg::override_with, with their own name + // but that doesn't seem to work in all cases. Example: + // ls -1g1 + // even though `ls -11` and `ls -1 -g -1` work. + .arg( + Arg::new(options::format::ONE_LINE) + .short('1') + .help("List one file per line.") + .multiple_occurrences(true), + ) + .arg( + Arg::new(options::format::LONG_NO_GROUP) + .short('o') + .help( + "Long format without group information. \ + Identical to --format=long with --no-group.", + ) + .multiple_occurrences(true), + ) + .arg( + Arg::new(options::format::LONG_NO_OWNER) + .short('g') + .help("Long format without owner information.") + .multiple_occurrences(true), + ) + .arg( + Arg::new(options::format::LONG_NUMERIC_UID_GID) + .short('n') + .long(options::format::LONG_NUMERIC_UID_GID) + .help("-l with numeric UIDs and GIDs.") + .multiple_occurrences(true), + ) + // Quoting style + .arg( + Arg::new(options::QUOTING_STYLE) + .long(options::QUOTING_STYLE) + .takes_value(true) + .help("Set quoting style.") + .possible_values(&[ + "literal", + "shell", + "shell-always", + "shell-escape", + "shell-escape-always", + "c", + "escape", + ]) + .overrides_with_all(&[ + options::QUOTING_STYLE, + options::quoting::LITERAL, + options::quoting::ESCAPE, + options::quoting::C, + ]), + ) + .arg( + Arg::new(options::quoting::LITERAL) + .short('N') + .long(options::quoting::LITERAL) + .help("Use literal quoting style. Equivalent to `--quoting-style=literal`") + .overrides_with_all(&[ + options::QUOTING_STYLE, + options::quoting::LITERAL, + options::quoting::ESCAPE, + options::quoting::C, + ]), + ) + .arg( + Arg::new(options::quoting::ESCAPE) + .short('b') + .long(options::quoting::ESCAPE) + .help("Use escape quoting style. Equivalent to `--quoting-style=escape`") + .overrides_with_all(&[ + options::QUOTING_STYLE, + options::quoting::LITERAL, + options::quoting::ESCAPE, + options::quoting::C, + ]), + ) + .arg( + Arg::new(options::quoting::C) + .short('Q') + .long(options::quoting::C) + .help("Use C quoting style. Equivalent to `--quoting-style=c`") + .overrides_with_all(&[ + options::QUOTING_STYLE, + options::quoting::LITERAL, + options::quoting::ESCAPE, + options::quoting::C, + ]), + ) + // Control characters + .arg( + Arg::new(options::HIDE_CONTROL_CHARS) + .short('q') + .long(options::HIDE_CONTROL_CHARS) + .help("Replace control characters with '?' if they are not escaped.") + .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]), + ) + .arg( + Arg::new(options::SHOW_CONTROL_CHARS) + .long(options::SHOW_CONTROL_CHARS) + .help("Show control characters 'as is' if they are not escaped.") + .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]), + ) + // Time arguments + .arg( + Arg::new(options::TIME) + .long(options::TIME) + .help( + "Show time in :\n\ + \taccess time (-u): atime, access, use;\n\ + \tchange time (-t): ctime, status.\n\ + \tbirth time: birth, creation;", + ) + .value_name("field") + .takes_value(true) + .possible_values(&[ + "atime", "access", "use", "ctime", "status", "birth", "creation", + ]) + .hide_possible_values(true) + .require_equals(true) + .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), + ) + .arg( + Arg::new(options::time::CHANGE) + .short('c') + .help( + "If the long listing format (e.g., -l, -o) is being used, print the status \ + change time (the 'ctime' in the inode) instead of the modification time. When \ + explicitly sorting by time (--sort=time or -t) or when not using a long listing \ + format, sort according to the status change time.", + ) + .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), + ) + .arg( + Arg::new(options::time::ACCESS) + .short('u') + .help( + "If the long listing format (e.g., -l, -o) is being used, print the status \ + access time instead of the modification time. When explicitly sorting by time \ + (--sort=time or -t) or when not using a long listing format, sort according to the \ + access time.", + ) + .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), + ) + // Hide and ignore + .arg( + Arg::new(options::HIDE) + .long(options::HIDE) + .takes_value(true) + .multiple_occurrences(true) + .value_name("PATTERN") + .help( + "do not list implied entries matching shell PATTERN (overridden by -a or -A)", + ), + ) + .arg( + Arg::new(options::IGNORE) + .short('I') + .long(options::IGNORE) + .takes_value(true) + .multiple_occurrences(true) + .value_name("PATTERN") + .help("do not list implied entries matching shell PATTERN"), + ) + .arg( + Arg::new(options::IGNORE_BACKUPS) + .short('B') + .long(options::IGNORE_BACKUPS) + .help("Ignore entries which end with ~."), + ) + // Sort arguments + .arg( + Arg::new(options::SORT) + .long(options::SORT) + .help("Sort by : name, none (-U), time (-t), size (-S) or extension (-X)") + .value_name("field") + .takes_value(true) + .possible_values(&["name", "none", "time", "size", "version", "extension"]) + .require_equals(true) + .overrides_with_all(&[ + options::SORT, + options::sort::SIZE, + options::sort::TIME, + options::sort::NONE, + options::sort::VERSION, + options::sort::EXTENSION, + ]), + ) + .arg( + Arg::new(options::sort::SIZE) + .short('S') + .help("Sort by file size, largest first.") + .overrides_with_all(&[ + options::SORT, + options::sort::SIZE, + options::sort::TIME, + options::sort::NONE, + options::sort::VERSION, + options::sort::EXTENSION, + ]), + ) + .arg( + Arg::new(options::sort::TIME) + .short('t') + .help("Sort by modification time (the 'mtime' in the inode), newest first.") + .overrides_with_all(&[ + options::SORT, + options::sort::SIZE, + options::sort::TIME, + options::sort::NONE, + options::sort::VERSION, + options::sort::EXTENSION, + ]), + ) + .arg( + Arg::new(options::sort::VERSION) + .short('v') + .help("Natural sort of (version) numbers in the filenames.") + .overrides_with_all(&[ + options::SORT, + options::sort::SIZE, + options::sort::TIME, + options::sort::NONE, + options::sort::VERSION, + options::sort::EXTENSION, + ]), + ) + .arg( + Arg::new(options::sort::EXTENSION) + .short('X') + .help("Sort alphabetically by entry extension.") + .overrides_with_all(&[ + options::SORT, + options::sort::SIZE, + options::sort::TIME, + options::sort::NONE, + options::sort::VERSION, + options::sort::EXTENSION, + ]), + ) + .arg( + Arg::new(options::sort::NONE) + .short('U') + .help( + "Do not sort; list the files in whatever order they are stored in the \ + directory. This is especially useful when listing very large directories, \ + since not doing any sorting can be noticeably faster.", + ) + .overrides_with_all(&[ + options::SORT, + options::sort::SIZE, + options::sort::TIME, + options::sort::NONE, + options::sort::VERSION, + options::sort::EXTENSION, + ]), + ) + // Dereferencing + .arg( + Arg::new(options::dereference::ALL) + .short('L') + .long(options::dereference::ALL) + .help( + "When showing file information for a symbolic link, show information for the \ + file the link references rather than the link itself.", + ) + .overrides_with_all(&[ + options::dereference::ALL, + options::dereference::DIR_ARGS, + options::dereference::ARGS, + ]), + ) + .arg( + Arg::new(options::dereference::DIR_ARGS) + .long(options::dereference::DIR_ARGS) + .help( + "Do not dereference symlinks except when they link to directories and are \ + given as command line arguments.", + ) + .overrides_with_all(&[ + options::dereference::ALL, + options::dereference::DIR_ARGS, + options::dereference::ARGS, + ]), + ) + .arg( + Arg::new(options::dereference::ARGS) + .short('H') + .long(options::dereference::ARGS) + .help("Do not dereference symlinks except when given as command line arguments.") + .overrides_with_all(&[ + options::dereference::ALL, + options::dereference::DIR_ARGS, + options::dereference::ARGS, + ]), + ) + // Long format options + .arg( + Arg::new(options::NO_GROUP) + .long(options::NO_GROUP) + .short('G') + .help("Do not show group in long format."), + ) + .arg(Arg::new(options::AUTHOR).long(options::AUTHOR).help( + "Show author in long format. \ + On the supported platforms, the author always matches the file owner.", + )) + // Other Flags + .arg( + Arg::new(options::files::ALL) + .short('a') + .long(options::files::ALL) + // Overrides -A (as the order matters) + .overrides_with(options::files::ALMOST_ALL) + .multiple_occurrences(true) + .help("Do not ignore hidden files (files with names that start with '.')."), + ) + .arg( + Arg::new(options::files::ALMOST_ALL) + .short('A') + .long(options::files::ALMOST_ALL) + // Overrides -a (as the order matters) + .overrides_with(options::files::ALL) + .multiple_occurrences(true) + .help( + "In a directory, do not ignore all file names that start with '.', \ + only ignore '.' and '..'.", + ), + ) + .arg( + Arg::new(options::DIRECTORY) + .short('d') + .long(options::DIRECTORY) + .help( + "Only list the names of directories, rather than listing directory contents. \ + This will not follow symbolic links unless one of `--dereference-command-line \ + (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is \ + specified.", + ), + ) + .arg( + Arg::new(options::size::HUMAN_READABLE) + .short('h') + .long(options::size::HUMAN_READABLE) + .help("Print human readable file sizes (e.g. 1K 234M 56G).") + .overrides_with(options::size::SI), + ) + .arg( + Arg::new(options::size::KIBIBYTES) + .short('k') + .long(options::size::KIBIBYTES) + .help("default to 1024-byte blocks for file system usage; used only with -s and per directory totals"), + ) + .arg( + Arg::new(options::size::SI) + .long(options::size::SI) + .help("Print human readable file sizes using powers of 1000 instead of 1024."), + ) + .arg( + Arg::new(options::size::BLOCK_SIZE) + .long(options::size::BLOCK_SIZE) + .takes_value(true) + .require_equals(true) + .value_name("BLOCK_SIZE") + .help("scale sizes by BLOCK_SIZE when printing them"), + ) + .arg( + Arg::new(options::INODE) + .short('i') + .long(options::INODE) + .help("print the index number of each file"), + ) + .arg( + Arg::new(options::REVERSE) + .short('r') + .long(options::REVERSE) + .help( + "Reverse whatever the sorting method is e.g., list files in reverse \ + alphabetical order, youngest first, smallest first, or whatever.", + ), + ) + .arg( + Arg::new(options::RECURSIVE) + .short('R') + .long(options::RECURSIVE) + .help("List the contents of all directories recursively."), + ) + .arg( + Arg::new(options::WIDTH) + .long(options::WIDTH) + .short('w') + .help("Assume that the terminal is COLS columns wide.") + .value_name("COLS") + .takes_value(true), + ) + .arg( + Arg::new(options::size::ALLOCATION_SIZE) + .short('s') + .long(options::size::ALLOCATION_SIZE) + .help("print the allocated size of each file, in blocks"), + ) + .arg( + Arg::new(options::COLOR) + .long(options::COLOR) + .help("Color output based on file type.") + .takes_value(true) + .possible_values(&[ + "always", "yes", "force", "auto", "tty", "if-tty", "never", "no", "none", + ]) + .require_equals(true) + .min_values(0), + ) + .arg( + Arg::new(options::INDICATOR_STYLE) + .long(options::INDICATOR_STYLE) + .help( + "Append indicator with style WORD to entry names: \ + none (default), slash (-p), file-type (--file-type), classify (-F)", + ) + .takes_value(true) + .possible_values(&["none", "slash", "file-type", "classify"]) + .overrides_with_all(&[ + options::indicator_style::FILE_TYPE, + options::indicator_style::SLASH, + options::indicator_style::CLASSIFY, + options::INDICATOR_STYLE, + ]), + ) + .arg( + // The --classify flag can take an optional when argument to + // control its behavior from version 9 of GNU coreutils. + // There is currently an inconsistency where GNU coreutils allows only + // the long form of the flag to take the argument while we allow it + // for both the long and short form of the flag. + Arg::new(options::indicator_style::CLASSIFY) + .short('F') + .long(options::indicator_style::CLASSIFY) + .help( + "Append a character to each file name indicating the file type. Also, for \ + regular files that are executable, append '*'. The file type indicators are \ + '/' for directories, '@' for symbolic links, '|' for FIFOs, '=' for sockets, \ + '>' for doors, and nothing for regular files. when may be omitted, or one of:\n\ + \tnone - Do not classify. This is the default.\n\ + \tauto - Only classify if standard output is a terminal.\n\ + \talways - Always classify.\n\ + Specifying --classify and no when is equivalent to --classify=always. This will not follow\ + symbolic links listed on the command line unless the --dereference-command-line (-H),\ + --dereference (-L), or --dereference-command-line-symlink-to-dir options are specified.", + ) + .takes_value(true) + .value_name("when") + .possible_values(&[ + "always", "yes", "force", "auto", "tty", "if-tty", "never", "no", "none", + ]) + .default_missing_value("always") + .require_equals(true) + .min_values(0) + .overrides_with_all(&[ + options::indicator_style::FILE_TYPE, + options::indicator_style::SLASH, + options::indicator_style::CLASSIFY, + options::INDICATOR_STYLE, + ]), + ) + .arg( + Arg::new(options::indicator_style::FILE_TYPE) + .long(options::indicator_style::FILE_TYPE) + .help("Same as --classify, but do not append '*'") + .overrides_with_all(&[ + options::indicator_style::FILE_TYPE, + options::indicator_style::SLASH, + options::indicator_style::CLASSIFY, + options::INDICATOR_STYLE, + ]), + ) + .arg( + Arg::new(options::indicator_style::SLASH) + .short('p') + .help("Append / indicator to directories.") + .overrides_with_all(&[ + options::indicator_style::FILE_TYPE, + options::indicator_style::SLASH, + options::indicator_style::CLASSIFY, + options::INDICATOR_STYLE, + ]), + ) + .arg( + //This still needs support for posix-*, +FORMAT + Arg::new(options::TIME_STYLE) + .long(options::TIME_STYLE) + .help("time/date format with -l; see TIME_STYLE below") + .value_name("TIME_STYLE") + .env("TIME_STYLE") + .possible_values(&["full-iso", "long-iso", "iso", "locale"]) + .overrides_with_all(&[options::TIME_STYLE]), + ) + .arg( + Arg::new(options::FULL_TIME) + .long(options::FULL_TIME) + .overrides_with(options::FULL_TIME) + .help("like -l --time-style=full-iso"), + ) + .arg( + Arg::new(options::CONTEXT) + .short('Z') + .long(options::CONTEXT) + .help(CONTEXT_HELP_TEXT), + ) + // Positional arguments + .arg( + Arg::new(options::PATHS) + .multiple_occurrences(true) + .takes_value(true) + .allow_invalid_utf8(true), + ) + .after_help( + "The TIME_STYLE argument can be full-iso, long-iso, iso. \ + Also the TIME_STYLE environment variable sets the default style to use.", + ) } /// Represents a Path along with it's associated data. @@ -1543,7 +1542,7 @@ impl PathData { } } -fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> { +pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> { let mut files = Vec::::new(); let mut dirs = Vec::::new(); let mut out = BufWriter::new(stdout()); diff --git a/src/uu/ls/src/quoting_style.rs b/src/uu/ls/src/quoting_style.rs index 4900dc566..9ff689273 100644 --- a/src/uu/ls/src/quoting_style.rs +++ b/src/uu/ls/src/quoting_style.rs @@ -6,7 +6,7 @@ use std::ffi::OsStr; const SPECIAL_SHELL_CHARS_START: &[char] = &['~', '#']; const SPECIAL_SHELL_CHARS: &str = "`$&*()|[]{};\\'\"<>?! "; -pub(super) enum QuotingStyle { +pub enum QuotingStyle { Shell { escape: bool, always_quote: bool, @@ -21,7 +21,7 @@ pub(super) enum QuotingStyle { } #[derive(Clone, Copy)] -pub(super) enum Quotes { +pub enum Quotes { None, Single, Double, diff --git a/src/uu/mkdir/Cargo.toml b/src/uu/mkdir/Cargo.toml index 08b2f1aff..11210d0ce 100644 --- a/src/uu/mkdir/Cargo.toml +++ b/src/uu/mkdir/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mkdir" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/mkdir.rs" diff --git a/src/uu/mkdir/src/mkdir.rs b/src/uu/mkdir/src/mkdir.rs index 7c8d4e413..b1d7583d3 100644 --- a/src/uu/mkdir/src/mkdir.rs +++ b/src/uu/mkdir/src/mkdir.rs @@ -64,12 +64,15 @@ fn get_mode(matches: &ArgMatches, mode_had_minus_prefix: bool) -> Result Ok(DEFAULT_PERM), + None => { + // If no mode argument is specified return the mode derived from umask + Ok(!mode::get_umask() & 0o0777) + } } } #[cfg(windows)] -fn strip_minus_from_mode(_args: &mut Vec) -> bool { +fn strip_minus_from_mode(_args: &mut [String]) -> bool { false } @@ -115,7 +118,7 @@ pub fn uu_app<'a>() -> Command<'a> { .short('m') .long(options::MODE) .help("set file mode (not implemented on windows)") - .default_value("755"), + .takes_value(true), ) .arg( Arg::new(options::PARENTS) diff --git a/src/uu/mkfifo/Cargo.toml b/src/uu/mkfifo/Cargo.toml index 1c16043ae..bb2ced83e 100644 --- a/src/uu/mkfifo/Cargo.toml +++ b/src/uu/mkfifo/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mkfifo" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/mkfifo.rs" diff --git a/src/uu/mknod/Cargo.toml b/src/uu/mknod/Cargo.toml index 68de0443b..2f9a5cea0 100644 --- a/src/uu/mknod/Cargo.toml +++ b/src/uu/mknod/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mknod" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] name = "uu_mknod" diff --git a/src/uu/mktemp/Cargo.toml b/src/uu/mktemp/Cargo.toml index 19af4f20e..c0c3366dc 100644 --- a/src/uu/mktemp/Cargo.toml +++ b/src/uu/mktemp/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mktemp" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/mktemp.rs" diff --git a/src/uu/more/Cargo.toml b/src/uu/more/Cargo.toml index 230276938..9cc69f3c5 100644 --- a/src/uu/more/Cargo.toml +++ b/src/uu/more/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/more" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/more.rs" diff --git a/src/uu/mv/Cargo.toml b/src/uu/mv/Cargo.toml index 861d96c7f..da1b8efe6 100644 --- a/src/uu/mv/Cargo.toml +++ b/src/uu/mv/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/mv" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/mv.rs" diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index 60cff5dfb..1c2390f80 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -258,6 +258,16 @@ fn exec(files: &[OsString], b: &Behavior) -> UResult<()> { move_files_into_dir(&[source.clone()], target, b) } } 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( source.quote().to_string(), target.quote().to_string(), @@ -275,7 +285,23 @@ fn exec(files: &[OsString], b: &Behavior) -> UResult<()> { )); } 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) } } } diff --git a/src/uu/nice/Cargo.toml b/src/uu/nice/Cargo.toml index 37d88e8a8..eeec708af 100644 --- a/src/uu/nice/Cargo.toml +++ b/src/uu/nice/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nice" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/nice.rs" diff --git a/src/uu/nl/Cargo.toml b/src/uu/nl/Cargo.toml index 8901cf34a..35357b422 100644 --- a/src/uu/nl/Cargo.toml +++ b/src/uu/nl/Cargo.toml @@ -9,14 +9,14 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nl" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/nl.rs" [dependencies] 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" } [[bin]] diff --git a/src/uu/nohup/Cargo.toml b/src/uu/nohup/Cargo.toml index fd2b5e82d..fb2aed634 100644 --- a/src/uu/nohup/Cargo.toml +++ b/src/uu/nohup/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nohup" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/nohup.rs" diff --git a/src/uu/nproc/Cargo.toml b/src/uu/nproc/Cargo.toml index c44c9883d..7980f5c2a 100644 --- a/src/uu/nproc/Cargo.toml +++ b/src/uu/nproc/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/nproc" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/nproc.rs" diff --git a/src/uu/numfmt/Cargo.toml b/src/uu/numfmt/Cargo.toml index 216503aae..c59924f1f 100644 --- a/src/uu/numfmt/Cargo.toml +++ b/src/uu/numfmt/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/numfmt" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/numfmt.rs" diff --git a/src/uu/od/Cargo.toml b/src/uu/od/Cargo.toml index d6cb3235d..a0a983f48 100644 --- a/src/uu/od/Cargo.toml +++ b/src/uu/od/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/od" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/od.rs" diff --git a/src/uu/od/src/od.rs b/src/uu/od/src/od.rs index 81cfb94de..33fac39d3 100644 --- a/src/uu/od/src/od.rs +++ b/src/uu/od/src/od.rs @@ -29,7 +29,6 @@ mod prn_float; mod prn_int; use std::cmp; -use std::convert::TryFrom; use crate::byteorder_io::*; use crate::formatteriteminfo::*; diff --git a/src/uu/paste/Cargo.toml b/src/uu/paste/Cargo.toml index e741c1485..a07d32af8 100644 --- a/src/uu/paste/Cargo.toml +++ b/src/uu/paste/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/paste" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/paste.rs" diff --git a/src/uu/pathchk/Cargo.toml b/src/uu/pathchk/Cargo.toml index 88417a5a1..09a14e0a6 100644 --- a/src/uu/pathchk/Cargo.toml +++ b/src/uu/pathchk/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pathchk" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/pathchk.rs" diff --git a/src/uu/pinky/Cargo.toml b/src/uu/pinky/Cargo.toml index a4562562f..2dab34491 100644 --- a/src/uu/pinky/Cargo.toml +++ b/src/uu/pinky/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pinky" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/pinky.rs" diff --git a/src/uu/pr/Cargo.toml b/src/uu/pr/Cargo.toml index 7ed902cb0..78fa9e28e 100644 --- a/src/uu/pr/Cargo.toml +++ b/src/uu/pr/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pr" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/pr.rs" @@ -20,7 +20,7 @@ uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=[" chrono = "0.4.19" quick-error = "2.0.1" itertools = "0.10.0" -regex = "1.0" +regex = "1.5" [[bin]] name = "pr" diff --git a/src/uu/printenv/Cargo.toml b/src/uu/printenv/Cargo.toml index 7c708602d..a44a5a5c1 100644 --- a/src/uu/printenv/Cargo.toml +++ b/src/uu/printenv/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/printenv" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/printenv.rs" diff --git a/src/uu/printf/Cargo.toml b/src/uu/printf/Cargo.toml index 02167bcbb..c23263085 100644 --- a/src/uu/printf/Cargo.toml +++ b/src/uu/printf/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/printf" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/printf.rs" diff --git a/src/uu/ptx/Cargo.toml b/src/uu/ptx/Cargo.toml index 73f4bad16..be76d8df4 100644 --- a/src/uu/ptx/Cargo.toml +++ b/src/uu/ptx/Cargo.toml @@ -9,14 +9,14 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/ptx" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/ptx.rs" [dependencies] 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" } [[bin]] diff --git a/src/uu/pwd/Cargo.toml b/src/uu/pwd/Cargo.toml index d045d6179..3d993bd70 100644 --- a/src/uu/pwd/Cargo.toml +++ b/src/uu/pwd/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/pwd" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/pwd.rs" diff --git a/src/uu/readlink/Cargo.toml b/src/uu/readlink/Cargo.toml index 5a2e42004..0d02d5115 100644 --- a/src/uu/readlink/Cargo.toml +++ b/src/uu/readlink/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/readlink" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/readlink.rs" diff --git a/src/uu/realpath/Cargo.toml b/src/uu/realpath/Cargo.toml index 77d8ccacb..d19eea0dc 100644 --- a/src/uu/realpath/Cargo.toml +++ b/src/uu/realpath/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/realpath" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/realpath.rs" diff --git a/src/uu/relpath/Cargo.toml b/src/uu/relpath/Cargo.toml index 4ac8ca0cd..2954ac0e8 100644 --- a/src/uu/relpath/Cargo.toml +++ b/src/uu/relpath/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/relpath" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/relpath.rs" diff --git a/src/uu/rm/Cargo.toml b/src/uu/rm/Cargo.toml index adef3eeab..630f3a294 100644 --- a/src/uu/rm/Cargo.toml +++ b/src/uu/rm/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/rm" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/rm.rs" diff --git a/src/uu/rmdir/Cargo.toml b/src/uu/rmdir/Cargo.toml index 34ad36819..5a6ccee6d 100644 --- a/src/uu/rmdir/Cargo.toml +++ b/src/uu/rmdir/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/rmdir" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/rmdir.rs" diff --git a/src/uu/runcon/Cargo.toml b/src/uu/runcon/Cargo.toml index 4cce3c504..30406d820 100644 --- a/src/uu/runcon/Cargo.toml +++ b/src/uu/runcon/Cargo.toml @@ -8,7 +8,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/runcon" keywords = ["coreutils", "uutils", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/runcon.rs" diff --git a/src/uu/seq/Cargo.toml b/src/uu/seq/Cargo.toml index b6573a792..ad8bba5b6 100644 --- a/src/uu/seq/Cargo.toml +++ b/src/uu/seq/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/seq" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/seq.rs" diff --git a/src/uu/seq/src/numberparse.rs b/src/uu/seq/src/numberparse.rs index 06f553478..c3f3656a8 100644 --- a/src/uu/seq/src/numberparse.rs +++ b/src/uu/seq/src/numberparse.rs @@ -3,7 +3,6 @@ //! //! This module provides an implementation of [`FromStr`] for the //! [`PreciseNumber`] struct. -use std::convert::TryInto; use std::str::FromStr; use bigdecimal::BigDecimal; diff --git a/src/uu/shred/Cargo.toml b/src/uu/shred/Cargo.toml index 6f92de22a..658abf598 100644 --- a/src/uu/shred/Cargo.toml +++ b/src/uu/shred/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/shred" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/shred.rs" diff --git a/src/uu/shuf/Cargo.toml b/src/uu/shuf/Cargo.toml index 61326e985..26577d0d5 100644 --- a/src/uu/shuf/Cargo.toml +++ b/src/uu/shuf/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/shuf" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/shuf.rs" diff --git a/src/uu/sleep/Cargo.toml b/src/uu/sleep/Cargo.toml index 0542b3ec8..bf1a4a5c5 100644 --- a/src/uu/sleep/Cargo.toml +++ b/src/uu/sleep/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/sleep" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/sleep.rs" diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index 4523c0748..69f7f7468 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/sort" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/sort.rs" diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index a1aa92a2b..77d81c54c 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -33,7 +33,6 @@ use numeric_str_cmp::{human_numeric_str_cmp, numeric_str_cmp, NumInfo, NumInfoPa use rand::{thread_rng, Rng}; use rayon::prelude::*; use std::cmp::Ordering; -use std::convert::TryFrom; use std::env; use std::error::Error; use std::ffi::{OsStr, OsString}; @@ -1637,7 +1636,7 @@ fn get_leading_gen(input: &str) -> Range { let leading_whitespace_len = input.len() - trimmed.len(); // check for inf, -inf and nan - for allowed_prefix in &["inf", "-inf", "nan"] { + for allowed_prefix in ["inf", "-inf", "nan"] { if trimmed.is_char_boundary(allowed_prefix.len()) && trimmed[..allowed_prefix.len()].eq_ignore_ascii_case(allowed_prefix) { diff --git a/src/uu/split/Cargo.toml b/src/uu/split/Cargo.toml index 316774621..75e080dfd 100644 --- a/src/uu/split/Cargo.toml +++ b/src/uu/split/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/split" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/split.rs" diff --git a/src/uu/split/src/split.rs b/src/uu/split/src/split.rs index b64b92898..c90c7a6b2 100644 --- a/src/uu/split/src/split.rs +++ b/src/uu/split/src/split.rs @@ -14,7 +14,6 @@ mod platform; use crate::filenames::FilenameIterator; use crate::filenames::SuffixType; use clap::{crate_version, Arg, ArgMatches, Command}; -use std::convert::TryInto; use std::env; use std::fmt; use std::fs::{metadata, File}; diff --git a/src/uu/stat/Cargo.toml b/src/uu/stat/Cargo.toml index 23087e2df..28ca9c51b 100644 --- a/src/uu/stat/Cargo.toml +++ b/src/uu/stat/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/stat" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/stat.rs" diff --git a/src/uu/stat/src/stat.rs b/src/uu/stat/src/stat.rs index 7d1073020..cebc6c108 100644 --- a/src/uu/stat/src/stat.rs +++ b/src/uu/stat/src/stat.rs @@ -471,11 +471,24 @@ impl Stater { } fn new(matches: &ArgMatches) -> UResult { - let files: Vec = matches + let mut files: Vec = matches .values_of(ARG_FILES) .map(|v| v.map(ToString::to_string).collect()) .unwrap_or_default(); - + #[cfg(unix)] + if files.contains(&String::from("-")) { + let redirected_path = Path::new("/dev/stdin") + .canonicalize() + .expect("unable to canonicalize /dev/stdin") + .into_os_string() + .into_string() + .unwrap(); + for file in &mut files { + if file == "-" { + *file = redirected_path.clone(); + } + } + } let format_str = if matches.is_present(options::PRINTF) { matches .value_of(options::PRINTF) diff --git a/src/uu/stdbuf/Cargo.toml b/src/uu/stdbuf/Cargo.toml index 98cdadf9f..4e6ea21eb 100644 --- a/src/uu/stdbuf/Cargo.toml +++ b/src/uu/stdbuf/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/stdbuf" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/stdbuf.rs" diff --git a/src/uu/stdbuf/src/libstdbuf/Cargo.toml b/src/uu/stdbuf/src/libstdbuf/Cargo.toml index 72c6b3e03..aacfe8524 100644 --- a/src/uu/stdbuf/src/libstdbuf/Cargo.toml +++ b/src/uu/stdbuf/src/libstdbuf/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/stdbuf" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] name = "libstdbuf" diff --git a/src/uu/stdbuf/src/stdbuf.rs b/src/uu/stdbuf/src/stdbuf.rs index 2eedb038b..5e0e71789 100644 --- a/src/uu/stdbuf/src/stdbuf.rs +++ b/src/uu/stdbuf/src/stdbuf.rs @@ -11,7 +11,6 @@ extern crate uucore; use clap::{crate_version, Arg, ArgMatches, Command}; -use std::convert::{TryFrom, TryInto}; use std::fs::File; use std::io::{self, Write}; use std::os::unix::process::ExitStatusExt; diff --git a/src/uu/sum/Cargo.toml b/src/uu/sum/Cargo.toml index dab660574..7e7894769 100644 --- a/src/uu/sum/Cargo.toml +++ b/src/uu/sum/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/sum" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/sum.rs" diff --git a/src/uu/sync/Cargo.toml b/src/uu/sync/Cargo.toml index 01400448a..a4d66aff5 100644 --- a/src/uu/sync/Cargo.toml +++ b/src/uu/sync/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/sync" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/sync.rs" diff --git a/src/uu/tac/Cargo.toml b/src/uu/tac/Cargo.toml index b63790a9f..b6c5d62b8 100644 --- a/src/uu/tac/Cargo.toml +++ b/src/uu/tac/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/tac" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/tac.rs" diff --git a/src/uu/tail/Cargo.toml b/src/uu/tail/Cargo.toml index bfa72c143..122a9ce84 100644 --- a/src/uu/tail/Cargo.toml +++ b/src/uu/tail/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/tail" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/tail.rs" diff --git a/src/uu/tail/src/platform/windows.rs b/src/uu/tail/src/platform/windows.rs index c63040a2a..b5c139bbd 100644 --- a/src/uu/tail/src/platform/windows.rs +++ b/src/uu/tail/src/platform/windows.rs @@ -34,6 +34,7 @@ impl ProcessChecker { } } + #[allow(clippy::wrong_self_convention)] pub fn is_dead(&mut self) -> bool { if !self.dead { self.dead = unsafe { diff --git a/src/uu/tail/src/tail.rs b/src/uu/tail/src/tail.rs index 5734fa79c..2f107d310 100644 --- a/src/uu/tail/src/tail.rs +++ b/src/uu/tail/src/tail.rs @@ -31,7 +31,6 @@ use clap::{Arg, Command}; use notify::{RecommendedWatcher, RecursiveMode, Watcher, WatcherKind}; use std::collections::HashMap; use std::collections::VecDeque; -use std::convert::TryInto; use std::ffi::OsString; use std::fmt; use std::fs::{File, Metadata}; diff --git a/src/uu/tee/Cargo.toml b/src/uu/tee/Cargo.toml index 1fd255fcf..80af45ea6 100644 --- a/src/uu/tee/Cargo.toml +++ b/src/uu/tee/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/tee" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/tee.rs" diff --git a/src/uu/test/Cargo.toml b/src/uu/test/Cargo.toml index 002eda823..6e2f4f789 100644 --- a/src/uu/test/Cargo.toml +++ b/src/uu/test/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/test" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/test.rs" diff --git a/src/uu/timeout/Cargo.toml b/src/uu/timeout/Cargo.toml index fa515913c..930185320 100644 --- a/src/uu/timeout/Cargo.toml +++ b/src/uu/timeout/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/timeout" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/timeout.rs" diff --git a/src/uu/touch/Cargo.toml b/src/uu/touch/Cargo.toml index 521c4c151..646b65f50 100644 --- a/src/uu/touch/Cargo.toml +++ b/src/uu/touch/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/touch" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/touch.rs" diff --git a/src/uu/tr/Cargo.toml b/src/uu/tr/Cargo.toml index cabf74556..9d757e276 100644 --- a/src/uu/tr/Cargo.toml +++ b/src/uu/tr/Cargo.toml @@ -9,13 +9,13 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/tr" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/tr.rs" [dependencies] -nom = "7.1.0" +nom = "7.1.1" clap = { version = "3.1", features = ["wrap_help", "cargo"] } uucore = { version=">=0.0.11", package="uucore", path="../../uucore" } diff --git a/src/uu/true/Cargo.toml b/src/uu/true/Cargo.toml index bd3bda2ba..bb35c63f5 100644 --- a/src/uu/true/Cargo.toml +++ b/src/uu/true/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/true" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/true.rs" diff --git a/src/uu/truncate/Cargo.toml b/src/uu/truncate/Cargo.toml index 348b1498f..3defee473 100644 --- a/src/uu/truncate/Cargo.toml +++ b/src/uu/truncate/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/truncate" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/truncate.rs" diff --git a/src/uu/tsort/Cargo.toml b/src/uu/tsort/Cargo.toml index 61fe36903..e9d236247 100644 --- a/src/uu/tsort/Cargo.toml +++ b/src/uu/tsort/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/tsort" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/tsort.rs" diff --git a/src/uu/tty/Cargo.toml b/src/uu/tty/Cargo.toml index d99a8e762..c27309008 100644 --- a/src/uu/tty/Cargo.toml +++ b/src/uu/tty/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/tty" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/tty.rs" diff --git a/src/uu/uname/Cargo.toml b/src/uu/uname/Cargo.toml index 8717d210f..66b9a3eb8 100644 --- a/src/uu/uname/Cargo.toml +++ b/src/uu/uname/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/uname" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/uname.rs" diff --git a/src/uu/unexpand/Cargo.toml b/src/uu/unexpand/Cargo.toml index 6a9c81864..beee39daf 100644 --- a/src/uu/unexpand/Cargo.toml +++ b/src/uu/unexpand/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/unexpand" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/unexpand.rs" diff --git a/src/uu/uniq/Cargo.toml b/src/uu/uniq/Cargo.toml index 2d72e6177..1d534140b 100644 --- a/src/uu/uniq/Cargo.toml +++ b/src/uu/uniq/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/uniq" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/uniq.rs" diff --git a/src/uu/uniq/src/uniq.rs b/src/uu/uniq/src/uniq.rs index 020de0230..32e0783ce 100644 --- a/src/uu/uniq/src/uniq.rs +++ b/src/uu/uniq/src/uniq.rs @@ -12,7 +12,7 @@ use std::path::Path; use std::str::FromStr; use strum_macros::{AsRefStr, EnumString}; use uucore::display::Quotable; -use uucore::error::{FromIo, UResult, USimpleError}; +use uucore::error::{FromIo, UResult, USimpleError, UUsageError}; use uucore::format_usage; static ABOUT: &str = "Report or omit repeated lines."; @@ -284,6 +284,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { ignore_case: matches.is_present(options::IGNORE_CASE), zero_terminated: matches.is_present(options::ZERO_TERMINATED), }; + + if uniq.show_counts && uniq.all_repeated { + return Err(UUsageError::new( + 1, + "printing all duplicated lines and repeat counts is meaningless", + )); + } + uniq.print_uniq( &mut open_input_file(&in_file_name)?, &mut open_output_file(&out_file_name)?, diff --git a/src/uu/unlink/Cargo.toml b/src/uu/unlink/Cargo.toml index 7342fa5b4..75cba4472 100644 --- a/src/uu/unlink/Cargo.toml +++ b/src/uu/unlink/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/unlink" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/unlink.rs" diff --git a/src/uu/uptime/Cargo.toml b/src/uu/uptime/Cargo.toml index b199fb24a..f08cb4d11 100644 --- a/src/uu/uptime/Cargo.toml +++ b/src/uu/uptime/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/uptime" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/uptime.rs" diff --git a/src/uu/users/Cargo.toml b/src/uu/users/Cargo.toml index 3b660f304..2796a5a46 100644 --- a/src/uu/users/Cargo.toml +++ b/src/uu/users/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/users" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/users.rs" diff --git a/src/uu/vdir/Cargo.toml b/src/uu/vdir/Cargo.toml new file mode 100644 index 000000000..10dc07a25 --- /dev/null +++ b/src/uu/vdir/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "uu_vdir" +version = "0.0.13" +authors = ["uutils developers"] +license = "MIT" +description = "shortcut to ls -l -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/vdir.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 = "vdir" +path = "src/main.rs" diff --git a/src/uu/vdir/LICENSE b/src/uu/vdir/LICENSE new file mode 120000 index 000000000..5853aaea5 --- /dev/null +++ b/src/uu/vdir/LICENSE @@ -0,0 +1 @@ +../../../LICENSE \ No newline at end of file diff --git a/src/uu/vdir/src/main.rs b/src/uu/vdir/src/main.rs new file mode 100644 index 000000000..9d9ba9de0 --- /dev/null +++ b/src/uu/vdir/src/main.rs @@ -0,0 +1 @@ +uucore::bin!(uu_vdir); diff --git a/src/uu/vdir/src/vdir.rs b/src/uu/vdir/src/vdir.rs new file mode 100644 index 000000000..b2af0b332 --- /dev/null +++ b/src/uu/vdir/src/vdir.rs @@ -0,0 +1,68 @@ +// * This file is part of the uutils coreutils package. +// * +// * (c) gmnsii +// * +// * 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::Long; + } + + 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()) +} diff --git a/src/uu/wc/Cargo.toml b/src/uu/wc/Cargo.toml index 02b009dde..d8b589388 100644 --- a/src/uu/wc/Cargo.toml +++ b/src/uu/wc/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/wc" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/wc.rs" diff --git a/src/uu/who/Cargo.toml b/src/uu/who/Cargo.toml index aa9ba27d6..3e3ee496e 100644 --- a/src/uu/who/Cargo.toml +++ b/src/uu/who/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/who" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/who.rs" diff --git a/src/uu/whoami/Cargo.toml b/src/uu/whoami/Cargo.toml index 67893b185..2400801a4 100644 --- a/src/uu/whoami/Cargo.toml +++ b/src/uu/whoami/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/whoami" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/whoami.rs" diff --git a/src/uu/yes/Cargo.toml b/src/uu/yes/Cargo.toml index 91f6cfb3e..d756f28f9 100644 --- a/src/uu/yes/Cargo.toml +++ b/src/uu/yes/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/uutils/coreutils" repository = "https://github.com/uutils/coreutils/tree/main/src/uu/yes" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path = "src/yes.rs" diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index a326402c5..0f28d9acb 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/uutils/coreutils/tree/main/src/uucore" # readme = "README.md" keywords = ["coreutils", "uutils", "cross-platform", "cli", "utility"] categories = ["command-line-utilities"] -edition = "2018" +edition = "2021" [lib] path="src/lib/lib.rs" @@ -31,7 +31,7 @@ data-encoding-macro = { version="0.1.12", optional=true } z85 = { version="3.0.3", optional=true } libc = { version="0.2.121", optional=true } once_cell = "1.10.0" -os_display = "0.1.0" +os_display = "0.1.3" [target.'cfg(unix)'.dependencies] walkdir = { version="2.3.2", optional=true } diff --git a/src/uucore/src/lib/features/entries.rs b/src/uucore/src/lib/features/entries.rs index 90f3134ab..0366355d4 100644 --- a/src/uucore/src/lib/features/entries.rs +++ b/src/uucore/src/lib/features/entries.rs @@ -41,7 +41,6 @@ use libc::{c_char, c_int, gid_t, uid_t}; use libc::{getgrgid, getgrnam, getgroups}; use libc::{getpwnam, getpwuid, group, passwd}; -use std::convert::TryInto; use std::ffi::{CStr, CString}; use std::io::Error as IOError; use std::io::ErrorKind; diff --git a/src/uucore/src/lib/features/fs.rs b/src/uucore/src/lib/features/fs.rs index 5cd6d253d..3963d865c 100644 --- a/src/uucore/src/lib/features/fs.rs +++ b/src/uucore/src/lib/features/fs.rs @@ -99,8 +99,6 @@ impl FileInformation { pub fn file_size(&self) -> u64 { #[cfg(unix)] { - use std::convert::TryInto; - assert!(self.0.st_size >= 0, "File size is negative"); self.0.st_size.try_into().unwrap() } diff --git a/src/uucore/src/lib/features/tokenize/num_format/formatters/base_conv/mod.rs b/src/uucore/src/lib/features/tokenize/num_format/formatters/base_conv/mod.rs index e6b1ea770..3df9f7129 100644 --- a/src/uucore/src/lib/features/tokenize/num_format/formatters/base_conv/mod.rs +++ b/src/uucore/src/lib/features/tokenize/num_format/formatters/base_conv/mod.rs @@ -179,7 +179,7 @@ pub fn str_to_arrnum(src: &str, radix_def_src: &dyn RadixDef) -> Vec { let mut intermed_in: Vec = Vec::new(); for c in src.chars() { #[allow(clippy::single_match)] - match radix_def_src.from_char(c) { + match radix_def_src.parse_char(c) { Some(u) => { intermed_in.push(u); } @@ -193,7 +193,7 @@ pub fn arrnum_to_str(src: &[u8], radix_def_dest: &dyn RadixDef) -> String { let mut str_out = String::new(); for u in src.iter() { #[allow(clippy::single_match)] - match radix_def_dest.from_u8(*u) { + match radix_def_dest.format_u8(*u) { Some(c) => { str_out.push(c); } @@ -219,8 +219,8 @@ pub fn base_conv_str( pub trait RadixDef { fn get_max(&self) -> u8; - fn from_char(&self, x: char) -> Option; - fn from_u8(&self, x: u8) -> Option; + fn parse_char(&self, x: char) -> Option; + fn format_u8(&self, x: u8) -> Option; } pub struct RadixTen; @@ -232,13 +232,13 @@ impl RadixDef for RadixTen { fn get_max(&self) -> u8 { 10 } - fn from_char(&self, c: char) -> Option { + fn parse_char(&self, c: char) -> Option { match c { '0'..='9' => Some(c as u8 - ZERO_ASC), _ => None, } } - fn from_u8(&self, u: u8) -> Option { + fn format_u8(&self, u: u8) -> Option { match u { 0..=9 => Some((ZERO_ASC + u) as char), _ => None, @@ -250,7 +250,7 @@ impl RadixDef for RadixHex { fn get_max(&self) -> u8 { 16 } - fn from_char(&self, c: char) -> Option { + fn parse_char(&self, c: char) -> Option { match c { '0'..='9' => Some(c as u8 - ZERO_ASC), 'A'..='F' => Some(c as u8 + 10 - UPPER_A_ASC), @@ -258,7 +258,7 @@ impl RadixDef for RadixHex { _ => None, } } - fn from_u8(&self, u: u8) -> Option { + fn format_u8(&self, u: u8) -> Option { match u { 0..=9 => Some((ZERO_ASC + u) as char), 10..=15 => Some((UPPER_A_ASC + (u - 10)) as char), diff --git a/src/uucore/src/lib/parser/parse_size.rs b/src/uucore/src/lib/parser/parse_size.rs index e68c04e5c..28a898825 100644 --- a/src/uucore/src/lib/parser/parse_size.rs +++ b/src/uucore/src/lib/parser/parse_size.rs @@ -5,7 +5,6 @@ // spell-checker:ignore (ToDO) hdsf ghead gtail -use std::convert::TryFrom; use std::error::Error; use std::fmt; diff --git a/src/uucore_procs/Cargo.toml b/src/uucore_procs/Cargo.toml index 151c308cf..4547beb8c 100644 --- a/src/uucore_procs/Cargo.toml +++ b/src/uucore_procs/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/uutils/coreutils/tree/main/src/uucore_procs" # readme = "README.md" keywords = ["cross-platform", "proc-macros", "uucore", "uutils"] # categories = ["os"] -edition = "2018" +edition = "2021" [lib] proc-macro = true diff --git a/tests/benches/factor/Cargo.toml b/tests/benches/factor/Cargo.toml index eb3d69105..efada4b00 100644 --- a/tests/benches/factor/Cargo.toml +++ b/tests/benches/factor/Cargo.toml @@ -5,7 +5,7 @@ authors = ["nicoo "] license = "MIT" description = "Benchmarks for the uu_factor integer factorization tool" homepage = "https://github.com/uutils/coreutils" -edition = "2018" +edition = "2021" [dependencies] uu_factor = { path = "../../../src/uu/factor" } diff --git a/tests/benches/factor/benches/table.rs b/tests/benches/factor/benches/table.rs index 9090c7d51..7f749a10f 100644 --- a/tests/benches/factor/benches/table.rs +++ b/tests/benches/factor/benches/table.rs @@ -1,6 +1,5 @@ use array_init::array_init; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; -use std::convert::TryInto; use uu_factor::{table::*, Factors}; fn table(c: &mut Criterion) { diff --git a/tests/by-util/test_base32.rs b/tests/by-util/test_base32.rs index 0eceb4a66..ed1468abd 100644 --- a/tests/by-util/test_base32.rs +++ b/tests/by-util/test_base32.rs @@ -34,7 +34,7 @@ fn test_base32_encode_file() { #[test] fn test_decode() { - for decode_param in &["-d", "--decode", "--dec"] { + for decode_param in ["-d", "--decode", "--dec"] { let input = "JBSWY3DPFQQFO33SNRSCC===\n"; // spell-checker:disable-line new_ucmd!() .arg(decode_param) @@ -56,7 +56,7 @@ fn test_garbage() { #[test] fn test_ignore_garbage() { - for ignore_garbage_param in &["-i", "--ignore-garbage", "--ig"] { + for ignore_garbage_param in ["-i", "--ignore-garbage", "--ig"] { let input = "JBSWY\x013DPFQ\x02QFO33SNRSCC===\n"; // spell-checker:disable-line new_ucmd!() .arg("-d") @@ -69,7 +69,7 @@ fn test_ignore_garbage() { #[test] fn test_wrap() { - for wrap_param in &["-w", "--wrap", "--wr"] { + for wrap_param in ["-w", "--wrap", "--wr"] { let input = "The quick brown fox jumps over the lazy dog."; new_ucmd!() .arg(wrap_param) @@ -84,7 +84,7 @@ fn test_wrap() { #[test] fn test_wrap_no_arg() { - for wrap_param in &["-w", "--wrap"] { + for wrap_param in ["-w", "--wrap"] { let ts = TestScenario::new(util_name!()); let expected_stderr = &format!( "error: The argument '--wrap \' requires a value but none was \ @@ -102,7 +102,7 @@ fn test_wrap_no_arg() { #[test] fn test_wrap_bad_arg() { - for wrap_param in &["-w", "--wrap"] { + for wrap_param in ["-w", "--wrap"] { new_ucmd!() .arg(wrap_param) .arg("b") diff --git a/tests/by-util/test_base64.rs b/tests/by-util/test_base64.rs index a4b461f91..11d345347 100644 --- a/tests/by-util/test_base64.rs +++ b/tests/by-util/test_base64.rs @@ -26,7 +26,7 @@ fn test_base64_encode_file() { #[test] fn test_decode() { - for decode_param in &["-d", "--decode", "--dec"] { + for decode_param in ["-d", "--decode", "--dec"] { let input = "aGVsbG8sIHdvcmxkIQ=="; // spell-checker:disable-line new_ucmd!() .arg(decode_param) @@ -48,7 +48,7 @@ fn test_garbage() { #[test] fn test_ignore_garbage() { - for ignore_garbage_param in &["-i", "--ignore-garbage", "--ig"] { + for ignore_garbage_param in ["-i", "--ignore-garbage", "--ig"] { let input = "aGVsbG8sIHdvcmxkIQ==\0"; // spell-checker:disable-line new_ucmd!() .arg("-d") @@ -61,7 +61,7 @@ fn test_ignore_garbage() { #[test] fn test_wrap() { - for wrap_param in &["-w", "--wrap", "--wr"] { + for wrap_param in ["-w", "--wrap", "--wr"] { let input = "The quick brown fox jumps over the lazy dog."; new_ucmd!() .arg(wrap_param) @@ -75,7 +75,7 @@ fn test_wrap() { #[test] fn test_wrap_no_arg() { - for wrap_param in &["-w", "--wrap"] { + for wrap_param in ["-w", "--wrap"] { new_ucmd!().arg(wrap_param).fails().stderr_contains( &"The argument '--wrap ' requires a value but none was supplied", ); @@ -84,7 +84,7 @@ fn test_wrap_no_arg() { #[test] fn test_wrap_bad_arg() { - for wrap_param in &["-w", "--wrap"] { + for wrap_param in ["-w", "--wrap"] { new_ucmd!() .arg(wrap_param) .arg("b") diff --git a/tests/by-util/test_basename.rs b/tests/by-util/test_basename.rs index 1250ba76f..0c7249b32 100644 --- a/tests/by-util/test_basename.rs +++ b/tests/by-util/test_basename.rs @@ -6,7 +6,7 @@ use std::ffi::OsStr; #[test] fn test_help() { - for help_flg in &["-h", "--help"] { + for help_flg in ["-h", "--help"] { new_ucmd!() .arg(&help_flg) .succeeds() @@ -17,7 +17,7 @@ fn test_help() { #[test] fn test_version() { - for version_flg in &["-V", "--version"] { + for version_flg in ["-V", "--version"] { assert!(new_ucmd!() .arg(&version_flg) .succeeds() @@ -61,7 +61,7 @@ fn test_do_not_remove_suffix() { #[test] fn test_multiple_param() { - for &multiple_param in &["-a", "--multiple", "--mul"] { + for multiple_param in ["-a", "--multiple", "--mul"] { let path = "/foo/bar/baz"; new_ucmd!() .args(&[multiple_param, path, path]) @@ -72,7 +72,7 @@ fn test_multiple_param() { #[test] fn test_suffix_param() { - for &suffix_param in &["-s", "--suffix", "--suf"] { + for suffix_param in ["-s", "--suffix", "--suf"] { let path = "/foo/bar/baz.exe"; new_ucmd!() .args(&[suffix_param, ".exe", path, path]) @@ -83,7 +83,7 @@ fn test_suffix_param() { #[test] fn test_zero_param() { - for &zero_param in &["-z", "--zero", "--ze"] { + for zero_param in ["-z", "--zero", "--ze"] { let path = "/foo/bar/baz"; new_ucmd!() .args(&[zero_param, "-a", path, path]) diff --git a/tests/by-util/test_cat.rs b/tests/by-util/test_cat.rs index 64a511656..96c77a40e 100644 --- a/tests/by-util/test_cat.rs +++ b/tests/by-util/test_cat.rs @@ -19,7 +19,7 @@ fn test_output_simple() { #[test] fn test_no_options() { // spell-checker:disable-next-line - for fixture in &["empty.txt", "alpha.txt", "nonewline.txt"] { + for fixture in ["empty.txt", "alpha.txt", "nonewline.txt"] { // Give fixture through command line file argument new_ucmd!() .args(&[fixture]) @@ -36,7 +36,7 @@ fn test_no_options() { #[test] #[cfg(any(target_vendor = "apple", target_os = "linux", target_os = "android"))] fn test_no_options_big_input() { - for &n in &[ + for n in [ 0, 1, 42, @@ -114,7 +114,7 @@ fn test_closes_file_descriptors() { fn test_piped_to_regular_file() { use std::fs::read_to_string; - for &append in &[true, false] { + for append in [true, false] { let s = TestScenario::new(util_name!()); let file_path = s.fixtures.plus("file.txt"); @@ -139,7 +139,7 @@ fn test_piped_to_regular_file() { #[test] #[cfg(unix)] fn test_piped_to_dev_null() { - for &append in &[true, false] { + for append in [true, false] { let s = TestScenario::new(util_name!()); { let dev_null = OpenOptions::new() @@ -159,7 +159,7 @@ fn test_piped_to_dev_null() { #[test] #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))] fn test_piped_to_dev_full() { - for &append in &[true, false] { + for append in [true, false] { let s = TestScenario::new(util_name!()); { let dev_full = OpenOptions::new() @@ -192,7 +192,7 @@ fn test_directory_and_file() { let s = TestScenario::new(util_name!()); s.fixtures.mkdir("test_directory2"); // spell-checker:disable-next-line - for fixture in &["empty.txt", "alpha.txt", "nonewline.txt"] { + for fixture in ["empty.txt", "alpha.txt", "nonewline.txt"] { s.ucmd() .args(&["test_directory2", fixture]) .fails() @@ -264,7 +264,7 @@ fn test_numbered_lines_no_trailing_newline() { #[test] fn test_stdin_show_nonprinting() { - for same_param in &["-v", "--show-nonprinting", "--show-non"] { + for same_param in ["-v", "--show-nonprinting", "--show-non"] { new_ucmd!() .args(&[same_param]) .pipe_in("\t\0\n") @@ -275,7 +275,7 @@ fn test_stdin_show_nonprinting() { #[test] fn test_stdin_show_tabs() { - for same_param in &["-T", "--show-tabs", "--show-ta"] { + for same_param in ["-T", "--show-tabs", "--show-ta"] { new_ucmd!() .args(&[same_param]) .pipe_in("\t\0\n") @@ -286,7 +286,7 @@ fn test_stdin_show_tabs() { #[test] fn test_stdin_show_ends() { - for &same_param in &["-E", "--show-ends", "--show-e"] { + for same_param in ["-E", "--show-ends", "--show-e"] { new_ucmd!() .args(&[same_param, "-"]) .pipe_in("\t\0\n\t") @@ -317,7 +317,7 @@ fn test_show_ends_crlf() { #[test] fn test_stdin_show_all() { - for same_param in &["-A", "--show-all", "--show-a"] { + for same_param in ["-A", "--show-all", "--show-a"] { new_ucmd!() .args(&[same_param]) .pipe_in("\t\0\n") @@ -346,7 +346,7 @@ fn test_stdin_nonprinting_and_tabs() { #[test] fn test_stdin_squeeze_blank() { - for same_param in &["-s", "--squeeze-blank", "--squeeze"] { + for same_param in ["-s", "--squeeze-blank", "--squeeze"] { new_ucmd!() .arg(same_param) .pipe_in("\n\na\n\n\n\n\nb\n\n\n") @@ -358,7 +358,7 @@ fn test_stdin_squeeze_blank() { #[test] fn test_stdin_number_non_blank() { // spell-checker:disable-next-line - for same_param in &["-b", "--number-nonblank", "--number-non"] { + for same_param in ["-b", "--number-nonblank", "--number-non"] { new_ucmd!() .arg(same_param) .arg("-") @@ -371,7 +371,7 @@ fn test_stdin_number_non_blank() { #[test] fn test_non_blank_overrides_number() { // spell-checker:disable-next-line - for &same_param in &["-b", "--number-nonblank"] { + for same_param in ["-b", "--number-nonblank"] { new_ucmd!() .args(&[same_param, "-"]) .pipe_in("\na\nb\n\n\nc") @@ -382,7 +382,7 @@ fn test_non_blank_overrides_number() { #[test] fn test_squeeze_blank_before_numbering() { - for &same_param in &["-s", "--squeeze-blank"] { + for same_param in ["-s", "--squeeze-blank"] { new_ucmd!() .args(&[same_param, "-n", "-"]) .pipe_in("a\n\n\nb") diff --git a/tests/by-util/test_chcon.rs b/tests/by-util/test_chcon.rs index 82dab9ae3..bea5462b4 100644 --- a/tests/by-util/test_chcon.rs +++ b/tests/by-util/test_chcon.rs @@ -23,7 +23,7 @@ fn help() { #[test] fn reference_errors() { - for args in &[ + for args in [ &["--verbose", "--reference"] as &[&str], &["--verbose", "--reference=/dev/null"], &["--verbose", "--reference=/inexistent", "/dev/null"], @@ -34,7 +34,7 @@ fn reference_errors() { #[test] fn recursive_errors() { - for args in &[ + for args in [ &["--verbose", "-P"] as &[&str], &["--verbose", "-H"], &["--verbose", "-L"], diff --git a/tests/by-util/test_chgrp.rs b/tests/by-util/test_chgrp.rs index 6c0aa46ad..1d89caca7 100644 --- a/tests/by-util/test_chgrp.rs +++ b/tests/by-util/test_chgrp.rs @@ -60,7 +60,7 @@ fn test_1() { #[test] fn test_fail_silently() { if get_effective_gid() != 0 { - for opt in &["-f", "--silent", "--quiet", "--sil", "--qui"] { + for opt in ["-f", "--silent", "--quiet", "--sil", "--qui"] { new_ucmd!() .arg(opt) .arg("bin") @@ -74,7 +74,7 @@ fn test_fail_silently() { #[test] fn test_preserve_root() { // It's weird that on OS X, `realpath /etc/..` returns '/private' - for d in &[ + for d in [ "/", "/////tmp///../../../../", "../../../../../../../../../../../../../../", @@ -92,7 +92,7 @@ fn test_preserve_root() { #[test] fn test_preserve_root_symlink() { let file = "test_chgrp_symlink2root"; - for d in &[ + for d in [ "/", "////tmp//../../../../", "..//../../..//../..//../../../../../../../../", @@ -299,7 +299,7 @@ fn test_traverse_symlinks() { } let (first_group, second_group) = (groups[0], groups[1]); - for &(args, traverse_first, traverse_second) in &[ + for (args, traverse_first, traverse_second) in [ (&[][..] as &[&str], false, false), (&["-H"][..], true, false), (&["-P"][..], false, false), diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index 373ad97ce..8f6b7fb52 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -532,7 +532,7 @@ fn test_chmod_strip_minus_from_mode() { #[test] fn test_chmod_keep_setgid() { - for &(from, arg, to) in &[ + for (from, arg, to) in [ (0o7777, "777", 0o46777), (0o7777, "=777", 0o40777), (0o7777, "0777", 0o46777), diff --git a/tests/by-util/test_comm.rs b/tests/by-util/test_comm.rs index d5b72b1e9..ebfc9c6f9 100644 --- a/tests/by-util/test_comm.rs +++ b/tests/by-util/test_comm.rs @@ -76,7 +76,7 @@ fn output_delimiter_require_arg() { #[cfg_attr(not(feature = "test_unimplemented"), ignore)] #[test] fn zero_terminated() { - for ¶m in &["-z", "--zero-terminated"] { + for param in ["-z", "--zero-terminated"] { new_ucmd!() .args(&[param, "a", "b"]) .fails() diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 11afa469e..7bb11306d 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -1469,7 +1469,7 @@ fn test_canonicalize_symlink() { #[test] fn test_copy_through_just_created_symlink() { - for &create_t in &[true, false] { + for create_t in [true, false] { let (at, mut ucmd) = at_and_ucmd!(); at.mkdir("a"); at.mkdir("b"); @@ -1606,7 +1606,7 @@ fn test_cp_dir_vs_file() { fn test_cp_overriding_arguments() { let s = TestScenario::new(util_name!()); s.fixtures.touch("file1"); - for (arg1, arg2) in &[ + for (arg1, arg2) in [ #[cfg(not(windows))] ("--remove-destination", "--force"), #[cfg(not(windows))] diff --git a/tests/by-util/test_cut.rs b/tests/by-util/test_cut.rs index da707ac3a..0fe222b06 100644 --- a/tests/by-util/test_cut.rs +++ b/tests/by-util/test_cut.rs @@ -41,7 +41,7 @@ static COMPLEX_SEQUENCE: &TestedSequence = &TestedSequence { #[test] fn test_byte_sequence() { - for ¶m in &["-b", "--bytes", "--byt"] { + for param in ["-b", "--bytes", "--byt"] { for example_seq in EXAMPLE_SEQUENCES { new_ucmd!() .args(&[param, example_seq.sequence, INPUT]) @@ -53,7 +53,7 @@ fn test_byte_sequence() { #[test] fn test_char_sequence() { - for ¶m in &["-c", "--characters", "--char"] { + for param in ["-c", "--characters", "--char"] { for example_seq in EXAMPLE_SEQUENCES { //as of coreutils 8.25 a char range is effectively the same as a byte range; there is no distinct treatment of utf8 chars. new_ucmd!() @@ -66,7 +66,7 @@ fn test_char_sequence() { #[test] fn test_field_sequence() { - for ¶m in &["-f", "--fields", "--fie"] { + for param in ["-f", "--fields", "--fie"] { for example_seq in EXAMPLE_SEQUENCES { new_ucmd!() .args(&[param, example_seq.sequence, INPUT]) @@ -78,7 +78,7 @@ fn test_field_sequence() { #[test] fn test_specify_delimiter() { - for ¶m in &["-d", "--delimiter", "--del"] { + for param in ["-d", "--delimiter", "--del"] { new_ucmd!() .args(&[param, ":", "-f", COMPLEX_SEQUENCE.sequence, INPUT]) .succeeds() @@ -115,7 +115,7 @@ fn test_output_delimiter() { #[test] fn test_complement() { - for param in &["--complement", "--com"] { + for param in ["--complement", "--com"] { new_ucmd!() .args(&["-d_", param, "-f", "2"]) .pipe_in("9_1\n8_2\n7_3") @@ -135,7 +135,7 @@ fn test_zero_terminated() { #[test] fn test_only_delimited() { - for param in &["-s", "--only-delimited", "--only-del"] { + for param in ["-s", "--only-delimited", "--only-del"] { new_ucmd!() .args(&["-d_", param, "-f", "1"]) .pipe_in("91\n82\n7_3") diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 05c6f89db..a04de9b59 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -7,7 +7,7 @@ use rust_users::*; #[test] fn test_date_email() { - for param in &["--rfc-email", "--rfc-e", "-R"] { + for param in ["--rfc-email", "--rfc-e", "-R"] { new_ucmd!().arg(param).succeeds(); } } @@ -23,7 +23,7 @@ fn test_date_rfc_3339() { let re = Regex::new(rfc_regexp).unwrap(); // Check that the output matches the regexp - for param in &["--rfc-3339", "--rfc-3"] { + for param in ["--rfc-3339", "--rfc-3"] { scene .ucmd() .arg(format!("{}=ns", param)) @@ -40,21 +40,21 @@ fn test_date_rfc_3339() { #[test] fn test_date_rfc_8601() { - for param in &["--iso-8601", "--i"] { + for param in ["--iso-8601", "--i"] { new_ucmd!().arg(format!("{}=ns", param)).succeeds(); } } #[test] fn test_date_rfc_8601_second() { - for param in &["--iso-8601", "--i"] { + for param in ["--iso-8601", "--i"] { new_ucmd!().arg(format!("{}=second", param)).succeeds(); } } #[test] fn test_date_utc() { - for param in &["--universal", "--utc", "--uni", "--u"] { + for param in ["--universal", "--utc", "--uni", "--u"] { new_ucmd!().arg(param).succeeds(); } } diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index f6287a940..71049a2af 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -463,7 +463,7 @@ fn test_zeros_to_stdout() { #[cfg(target_pointer_width = "32")] #[test] fn test_oversized_bs_32_bit() { - for bs_param in &["bs", "ibs", "obs", "cbs"] { + for bs_param in ["bs", "ibs", "obs", "cbs"] { new_ucmd!() .args(&[format!("{}=5GB", bs_param)]) .run() diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index b0ee8a2b3..223dc4efc 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -1,4 +1,4 @@ -// spell-checker:ignore udev pcent +// spell-checker:ignore udev pcent iuse itotal iused ipcent use crate::common::util::*; #[test] @@ -26,18 +26,117 @@ fn test_df_compatible_si() { new_ucmd!().arg("-aH").succeeds(); } +#[test] +fn test_df_arguments_override_themselves() { + new_ucmd!().args(&["--help", "--help"]).succeeds(); + new_ucmd!().arg("-aa").succeeds(); + new_ucmd!() + .args(&["--block-size=3000", "--block-size=1000"]) + .succeeds(); + new_ucmd!().args(&["--total", "--total"]).succeeds(); + new_ucmd!().arg("-hh").succeeds(); + new_ucmd!().arg("-HH").succeeds(); + new_ucmd!().arg("-ii").succeeds(); + new_ucmd!().arg("-kk").succeeds(); + new_ucmd!().arg("-ll").succeeds(); + new_ucmd!().args(&["--no-sync", "--no-sync"]).succeeds(); + new_ucmd!().arg("-PP").succeeds(); + new_ucmd!().args(&["--sync", "--sync"]).succeeds(); + new_ucmd!().arg("-TT").succeeds(); +} + +#[test] +fn test_df_conflicts_overriding() { + new_ucmd!().arg("-hH").succeeds(); + new_ucmd!().arg("-Hh").succeeds(); + new_ucmd!().args(&["--no-sync", "--sync"]).succeeds(); + new_ucmd!().args(&["--sync", "--no-sync"]).succeeds(); + new_ucmd!().args(&["-k", "--block-size=3000"]).succeeds(); + new_ucmd!().args(&["--block-size=3000", "-k"]).succeeds(); +} + +#[test] +fn test_df_output_arg() { + new_ucmd!().args(&["--output=source", "-iPT"]).fails(); + new_ucmd!().args(&["-iPT", "--output=source"]).fails(); + new_ucmd!() + .args(&["--output=source", "--output=source"]) + .fails(); +} + #[test] fn test_df_output() { - // TODO These should fail because `-total` should have two dashes, - // not just one. But they don't fail. - if cfg!(target_os = "macos") { - new_ucmd!().arg("-H").arg("-total").succeeds(). - stdout_only("Filesystem Size Used Available Capacity Use% Mounted on \n"); + let expected = if cfg!(target_os = "macos") { + vec![ + "Filesystem", + "Size", + "Used", + "Available", + "Capacity", + "Use%", + "Mounted", + "on", + ] } else { - new_ucmd!().arg("-H").arg("-total").succeeds().stdout_only( - "Filesystem Size Used Available Use% Mounted on \n", - ); - } + vec![ + "Filesystem", + "Size", + "Used", + "Available", + "Use%", + "Mounted", + "on", + ] + }; + let output = new_ucmd!() + .arg("-H") + .arg("--total") + .succeeds() + .stdout_move_str(); + let actual = output.lines().take(1).collect::>()[0]; + let actual = actual.split_whitespace().collect::>(); + assert_eq!(actual, expected); +} + +#[test] +fn test_df_output_overridden() { + let expected = if cfg!(target_os = "macos") { + vec![ + "Filesystem", + "Size", + "Used", + "Available", + "Capacity", + "Use%", + "Mounted", + "on", + ] + } else { + vec![ + "Filesystem", + "Size", + "Used", + "Available", + "Use%", + "Mounted", + "on", + ] + }; + let output = new_ucmd!() + .arg("-hH") + .arg("--total") + .succeeds() + .stdout_move_str(); + let actual = output.lines().take(1).collect::>()[0]; + let actual = actual.split_whitespace().collect::>(); + assert_eq!(actual, expected); +} + +#[test] +fn test_total_option_with_single_dash() { + // These should fail because `-total` should have two dashes, + // not just one. + new_ucmd!().arg("-total").fails(); } /// Test that the order of rows in the table does not change across executions. @@ -87,7 +186,17 @@ fn test_output_option_without_equals_sign() { #[test] fn test_type_option() { - new_ucmd!().args(&["-t", "ext4", "-t", "ext3"]).succeeds(); + let fs_types = new_ucmd!() + .arg("--output=fstype") + .succeeds() + .stdout_move_str(); + let fs_type = fs_types.lines().nth(1).unwrap().trim(); + + new_ucmd!().args(&["-t", fs_type]).succeeds(); + new_ucmd!() + .args(&["-t", fs_type, "-t", "nonexisting"]) + .succeeds(); + new_ucmd!().args(&["-t", "nonexisting"]).fails(); } #[test] @@ -95,6 +204,21 @@ fn test_exclude_type_option() { new_ucmd!().args(&["-x", "ext4", "-x", "ext3"]).succeeds(); } +#[test] +fn test_include_exclude_same_type() { + new_ucmd!() + .args(&["-t", "ext4", "-x", "ext4"]) + .fails() + .stderr_is("df: file system type 'ext4' both selected and excluded"); + new_ucmd!() + .args(&["-t", "ext4", "-x", "ext4", "-t", "ext3", "-x", "ext3"]) + .fails() + .stderr_is( + "df: file system type 'ext4' both selected and excluded\n\ + df: file system type 'ext3' both selected and excluded", + ); +} + #[test] fn test_total() { // Example output: @@ -162,6 +286,36 @@ fn test_use_percentage() { } } +#[test] +fn test_iuse_percentage() { + let output = new_ucmd!() + .args(&["--total", "--output=itotal,iused,ipcent"]) + .succeeds() + .stdout_move_str(); + + // Skip the header line. + let lines: Vec<&str> = output.lines().skip(1).collect(); + + for line in lines { + let mut iter = line.split_whitespace(); + let reported_inodes = iter.next().unwrap().parse::().unwrap(); + let reported_iused = iter.next().unwrap().parse::().unwrap(); + let reported_percentage = iter.next().unwrap(); + + if reported_percentage == "-" { + assert_eq!(0.0, reported_inodes); + assert_eq!(0.0, reported_iused); + } else { + let reported_percentage = reported_percentage[..reported_percentage.len() - 1] + .parse::() + .unwrap(); + let computed_percentage = (100.0 * (reported_iused / reported_inodes)).ceil() as u8; + + assert_eq!(computed_percentage, reported_percentage); + } + } +} + #[test] fn test_block_size_1024() { fn get_header(block_size: u64) -> String { @@ -189,23 +343,26 @@ fn test_block_size_1024() { assert_eq!(get_header(34 * 1024 * 1024 * 1024), "34G-blocks"); } -// TODO The spacing does not match GNU df. Also we need to remove -// trailing spaces from the heading row. #[test] fn test_output_selects_columns() { let output = new_ucmd!() .args(&["--output=source"]) .succeeds() .stdout_move_str(); - assert_eq!(output.lines().next().unwrap(), "Filesystem "); + assert_eq!(output.lines().next().unwrap().trim_end(), "Filesystem"); let output = new_ucmd!() .args(&["--output=source,target"]) .succeeds() .stdout_move_str(); assert_eq!( - output.lines().next().unwrap(), - "Filesystem Mounted on " + output + .lines() + .next() + .unwrap() + .split_whitespace() + .collect::>(), + vec!["Filesystem", "Mounted", "on"] ); let output = new_ucmd!() @@ -213,8 +370,13 @@ fn test_output_selects_columns() { .succeeds() .stdout_move_str(); assert_eq!( - output.lines().next().unwrap(), - "Filesystem Mounted on Used " + output + .lines() + .next() + .unwrap() + .split_whitespace() + .collect::>(), + vec!["Filesystem", "Mounted", "on", "Used"] ); } @@ -225,12 +387,16 @@ fn test_output_multiple_occurrences() { .succeeds() .stdout_move_str(); assert_eq!( - output.lines().next().unwrap(), - "Filesystem Mounted on " + output + .lines() + .next() + .unwrap() + .split_whitespace() + .collect::>(), + vec!["Filesystem", "Mounted", "on"] ); } -// TODO Fix the spacing. #[test] fn test_output_file_all_filesystems() { // When run with no positional arguments, `df` lets "-" represent @@ -240,13 +406,12 @@ fn test_output_file_all_filesystems() { .succeeds() .stdout_move_str(); let mut lines = output.lines(); - assert_eq!(lines.next().unwrap(), "File "); + assert_eq!(lines.next().unwrap(), "File"); for line in lines { - assert_eq!(line, "- "); + assert_eq!(line, "- "); } } -// TODO Fix the spacing. #[test] fn test_output_file_specific_files() { // Create three files. @@ -262,15 +427,7 @@ fn test_output_file_specific_files() { .succeeds() .stdout_move_str(); let actual: Vec<&str> = output.lines().collect(); - assert_eq!( - actual, - vec![ - "File ", - "a ", - "b ", - "c " - ] - ); + assert_eq!(actual, vec!["File", "a ", "b ", "c "]); } #[test] @@ -280,3 +437,16 @@ fn test_output_field_no_more_than_once() { .fails() .usage_error("option --output: field 'target' used more than once"); } + +#[test] +fn test_nonexistent_file() { + new_ucmd!() + .arg("does-not-exist") + .fails() + .stderr_only("df: does-not-exist: No such file or directory"); + new_ucmd!() + .args(&["--output=file", "does-not-exist", "."]) + .fails() + .stderr_is("df: does-not-exist: No such file or directory\n") + .stdout_is("File\n. \n"); +} diff --git a/tests/by-util/test_dir.rs b/tests/by-util/test_dir.rs new file mode 100644 index 000000000..3ec416bb2 --- /dev/null +++ b/tests/by-util/test_dir.rs @@ -0,0 +1,55 @@ +#[cfg(not(windows))] +extern crate libc; +extern crate regex; +#[cfg(not(windows))] +extern crate tempfile; +#[cfg(unix)] +extern crate unix_socket; + +use self::regex::Regex; +use crate::common::util::*; + +/* + * As dir use the same functions than ls, we don't have to retest them here. + * We just test the default and the long output +*/ + +#[test] +fn test_dir() { + new_ucmd!().succeeds(); +} + +#[test] +fn test_default_output() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("some-dir1"); + at.touch("some-file1"); + + scene.ucmd().succeeds().stdout_contains("some-file1"); + + scene + .ucmd() + .succeeds() + .stdout_does_not_match(&Regex::new("[rwx][^some-file1]").unwrap()); +} + +#[test] +fn test_long_output() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("some-dir1"); + at.touch("some-file1"); + + scene + .ucmd() + .arg("-l") + .succeeds() + .stdout_contains("some-file1"); + + scene + .ucmd() + .arg("-l") + .succeeds() + .stdout_matches(&Regex::new("[rwx][^some-file1]").unwrap()); +} diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index b0506d071..1deddb77f 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -3,7 +3,11 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -// spell-checker:ignore (paths) sublink subwords +// spell-checker:ignore (paths) sublink subwords azerty azeaze xcwww azeaz amaz azea qzerty tazerty +#[cfg(not(windows))] +use regex::Regex; +#[cfg(not(windows))] +use std::io::Write; use crate::common::util::*; @@ -429,7 +433,7 @@ fn test_du_no_permission() { ts.ccmd("chmod").arg("-r").arg(SUB_DIR_LINKS).succeeds(); - let result = ts.ucmd().arg(SUB_DIR_LINKS).run(); // TODO: replace with ".fails()" once `du` is fixed + let result = ts.ucmd().arg(SUB_DIR_LINKS).fails(); result.stderr_contains( "du: cannot read directory 'subdir/links': Permission denied (os error 13)", ); @@ -449,6 +453,21 @@ fn test_du_no_permission() { _du_no_permission(result.stdout_str()); } +#[cfg(not(target_os = "windows"))] +#[cfg(feature = "chmod")] +#[test] +fn test_du_no_exec_permission() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + at.mkdir_all("d/no-x/y"); + + ts.ccmd("chmod").arg("u=rw").arg("d/no-x").succeeds(); + + let result = ts.ucmd().arg("d/no-x").fails(); + result.stderr_contains("du: cannot access 'd/no-x/y': Permission denied"); +} + #[cfg(target_vendor = "apple")] fn _du_no_permission(s: &str) { assert_eq!(s, "0\tsubdir/links\n"); @@ -587,3 +606,171 @@ fn test_du_bytes() { ))] result.stdout_contains("21529\t./subdir\n"); } + +#[test] +fn test_du_exclude() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + at.symlink_dir(SUB_DEEPER_DIR, SUB_DIR_LINKS_DEEPER_SYM_DIR); + at.mkdir_all(SUB_DIR_LINKS); + + ts.ucmd() + .arg("--exclude=subdir") + .arg(SUB_DEEPER_DIR) + .succeeds() + .stdout_contains("subdir/deeper/deeper_dir"); + ts.ucmd() + .arg("--exclude=subdir") + .arg("subdir") + .succeeds() + .stdout_is(""); + ts.ucmd() + .arg("--exclude=subdir") + .arg("--verbose") + .arg("subdir") + .succeeds() + .stdout_contains("'subdir' ignored"); +} + +#[test] +// Disable on Windows because we are looking for / +// And the tests would be more complex if we have to support \ too +#[cfg(not(target_os = "windows"))] +fn test_du_exclude_2() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + at.mkdir_all("azerty/xcwww/azeaze"); + + let result = ts.ucmd().arg("azerty").succeeds(); + + let path_regexp = r"(.*)azerty/xcwww/azeaze(.*)azerty/xcwww(.*)azerty"; + let re = Regex::new(path_regexp).unwrap(); + assert!(re.is_match(result.stdout_str().replace('\n', "").trim())); + + // Exact match + ts.ucmd() + .arg("--exclude=azeaze") + .arg("azerty") + .succeeds() + .stdout_does_not_contain("azerty/xcwww/azeaze"); + // Partial match and NOT a glob + ts.ucmd() + .arg("--exclude=azeaz") + .arg("azerty") + .succeeds() + .stdout_contains("azerty/xcwww/azeaze"); + // Partial match and a various glob + ts.ucmd() + .arg("--exclude=azea?") + .arg("azerty") + .succeeds() + .stdout_contains("azerty/xcwww/azeaze"); + ts.ucmd() + .arg("--exclude=azea{z,b}") + .arg("azerty") + .succeeds() + .stdout_contains("azerty/xcwww/azeaze"); + ts.ucmd() + .arg("--exclude=azea*") + .arg("azerty") + .succeeds() + .stdout_does_not_contain("azerty/xcwww/azeaze"); + ts.ucmd() + .arg("--exclude=azeaz?") + .arg("azerty") + .succeeds() + .stdout_does_not_contain("azerty/xcwww/azeaze"); +} + +#[test] +// Disable on Windows because we are looking for / +// And the tests would be more complex if we have to support \ too +#[cfg(not(target_os = "windows"))] +fn test_du_exclude_mix() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + let mut file1 = at.make_file("file-ignore1"); + file1.write_all(b"azeaze").unwrap(); + let mut file2 = at.make_file("file-ignore2"); + file2.write_all(b"amaz?ng").unwrap(); + + at.mkdir_all("azerty/xcwww/azeaze"); + at.mkdir_all("azerty/xcwww/qzerty"); + at.mkdir_all("azerty/xcwww/amazing"); + + ts.ucmd() + .arg("azerty") + .succeeds() + .stdout_contains("azerty/xcwww/azeaze"); + ts.ucmd() + .arg("--exclude=azeaze") + .arg("azerty") + .succeeds() + .stdout_does_not_contain("azerty/xcwww/azeaze"); + + // Just exclude one file name + let result = ts.ucmd().arg("--exclude=qzerty").arg("azerty").succeeds(); + assert!(!result.stdout_str().contains("qzerty")); + assert!(result.stdout_str().contains("azerty")); + assert!(result.stdout_str().contains("xcwww")); + + // Exclude from file + let result = ts + .ucmd() + .arg("--exclude-from=file-ignore1") + .arg("azerty") + .succeeds(); + assert!(!result.stdout_str().contains("azeaze")); + assert!(result.stdout_str().contains("qzerty")); + assert!(result.stdout_str().contains("xcwww")); + + // Mix two files and string + let result = ts + .ucmd() + .arg("--exclude=qzerty") + .arg("--exclude-from=file-ignore1") + .arg("--exclude-from=file-ignore2") + .arg("azerty") + .succeeds(); + assert!(!result.stdout_str().contains("amazing")); + assert!(!result.stdout_str().contains("qzerty")); + assert!(!result.stdout_str().contains("azeaze")); + assert!(result.stdout_str().contains("xcwww")); +} + +#[test] +fn test_du_exclude_several_components() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + at.mkdir_all("a/b/c"); + at.mkdir_all("a/x/y"); + at.mkdir_all("a/u/y"); + + // Exact match + let result = ts + .ucmd() + .arg("--exclude=a/u") + .arg("--exclude=a/b") + .arg("a") + .succeeds(); + assert!(!result.stdout_str().contains("a/u")); + assert!(!result.stdout_str().contains("a/b")); +} + +#[test] +fn test_du_exclude_invalid_syntax() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + + at.mkdir_all("azerty/xcwww/azeaze"); + + ts.ucmd() + .arg("--exclude=a[ze") + .arg("azerty") + .fails() + .stderr_contains("du: Invalid exclude syntax"); +} diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index 3559e74cd..395e6d157 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -83,7 +83,7 @@ fn test_unset_invalid_variables() { // Cannot test input with \0 in it, since output will also contain \0. rlimit::prlimit fails // with this error: Error { kind: InvalidInput, message: "nul byte found in provided data" } - for var in &["", "a=b"] { + for var in ["", "a=b"] { new_ucmd!().arg("-u").arg(var).run().stderr_only(format!( "env: cannot unset {}: Invalid argument", var.quote() diff --git a/tests/by-util/test_hashsum.rs b/tests/by-util/test_hashsum.rs index 293270a77..160798f36 100644 --- a/tests/by-util/test_hashsum.rs +++ b/tests/by-util/test_hashsum.rs @@ -1,4 +1,4 @@ -// spell-checker:ignore checkfile +// spell-checker:ignore checkfile, nonames macro_rules! get_hash( ($str:expr) => ( $str.split(' ').collect::>()[0] @@ -29,6 +29,16 @@ macro_rules! test_digest { get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).pipe_in_fixture("input.txt").succeeds().no_stderr().stdout_str())); } + #[test] + fn test_nonames() { + let ts = TestScenario::new("hashsum"); + // EXPECTED_FILE has no newline character at the end + assert_eq!(format!("{0}\n{0}\n", ts.fixtures.read(EXPECTED_FILE)), + ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).arg("--no-names").arg("input.txt").arg("-").pipe_in_fixture("input.txt") + .succeeds().no_stderr().stdout_str() + ); + } + #[test] fn test_check() { let ts = TestScenario::new("hashsum"); diff --git a/tests/by-util/test_id.rs b/tests/by-util/test_id.rs index db918aa33..8606678e9 100644 --- a/tests/by-util/test_id.rs +++ b/tests/by-util/test_id.rs @@ -49,7 +49,7 @@ fn test_id_single_user() { .code_is(exp_result.code()); // u/g/G z/n - for &opt in &["--user", "--group", "--groups"] { + for opt in ["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); exp_result = unwrap_or_return!(expected_result(&ts, &args)); @@ -108,7 +108,7 @@ fn test_id_single_user_non_existing() { #[cfg(unix)] fn test_id_name() { let ts = TestScenario::new(util_name!()); - for &opt in &["--user", "--group", "--groups"] { + for opt in ["--user", "--group", "--groups"] { let args = [opt, "--name"]; let result = ts.ucmd().args(&args).run(); let exp_result = unwrap_or_return!(expected_result(&ts, &args)); @@ -127,7 +127,7 @@ fn test_id_name() { #[cfg(unix)] fn test_id_real() { let ts = TestScenario::new(util_name!()); - for &opt in &["--user", "--group", "--groups"] { + for opt in ["--user", "--group", "--groups"] { let args = [opt, "--real"]; let result = ts.ucmd().args(&args).run(); let exp_result = unwrap_or_return!(expected_result(&ts, &args)); @@ -188,7 +188,7 @@ fn test_id_multiple_users() { .code_is(exp_result.code()); // u/g/G z/n - for &opt in &["--user", "--group", "--groups"] { + for opt in ["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); exp_result = unwrap_or_return!(expected_result(&ts, &args)); @@ -256,7 +256,7 @@ fn test_id_multiple_users_non_existing() { .code_is(exp_result.code()); // u/g/G z/n - for &opt in &["--user", "--group", "--groups"] { + for opt in ["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); exp_result = unwrap_or_return!(expected_result(&ts, &args)); @@ -297,14 +297,14 @@ fn test_id_multiple_users_non_existing() { #[cfg(unix)] fn test_id_default_format() { let ts = TestScenario::new(util_name!()); - for &opt1 in &["--name", "--real"] { + for opt1 in ["--name", "--real"] { // id: cannot print only names or real IDs in default format let args = [opt1]; ts.ucmd() .args(&args) .fails() .stderr_only(unwrap_or_return!(expected_result(&ts, &args)).stderr_str()); - for &opt2 in &["--user", "--group", "--groups"] { + for opt2 in ["--user", "--group", "--groups"] { // u/g/G n/r let args = [opt2, opt1]; let result = ts.ucmd().args(&args).run(); @@ -315,7 +315,7 @@ fn test_id_default_format() { .code_is(exp_result.code()); } } - for &opt2 in &["--user", "--group", "--groups"] { + for opt2 in ["--user", "--group", "--groups"] { // u/g/G let args = [opt2]; ts.ucmd() @@ -329,20 +329,20 @@ fn test_id_default_format() { #[cfg(unix)] fn test_id_zero() { let ts = TestScenario::new(util_name!()); - for z_flag in &["-z", "--zero"] { + for z_flag in ["-z", "--zero"] { // id: option --zero not permitted in default format ts.ucmd() .args(&[z_flag]) .fails() .stderr_only(unwrap_or_return!(expected_result(&ts, &[z_flag])).stderr_str()); - for &opt1 in &["--name", "--real"] { + for opt1 in ["--name", "--real"] { // id: cannot print only names or real IDs in default format let args = [opt1, z_flag]; ts.ucmd() .args(&args) .fails() .stderr_only(unwrap_or_return!(expected_result(&ts, &args)).stderr_str()); - for &opt2 in &["--user", "--group", "--groups"] { + for opt2 in ["--user", "--group", "--groups"] { // u/g/G n/r z let args = [opt2, z_flag, opt1]; let result = ts.ucmd().args(&args).run(); @@ -353,7 +353,7 @@ fn test_id_zero() { .code_is(exp_result.code()); } } - for &opt2 in &["--user", "--group", "--groups"] { + for opt2 in ["--user", "--group", "--groups"] { // u/g/G z let args = [opt2, z_flag]; ts.ucmd() @@ -373,18 +373,18 @@ fn test_id_context() { return; } let ts = TestScenario::new(util_name!()); - for c_flag in &["-Z", "--context"] { + for c_flag in ["-Z", "--context"] { ts.ucmd() .args(&[c_flag]) .succeeds() .stdout_only(unwrap_or_return!(expected_result(&ts, &[c_flag])).stdout_str()); - for &z_flag in &["-z", "--zero"] { + for z_flag in ["-z", "--zero"] { let args = [c_flag, z_flag]; ts.ucmd() .args(&args) .succeeds() .stdout_only(unwrap_or_return!(expected_result(&ts, &args)).stdout_str()); - for &opt1 in &["--name", "--real"] { + for opt1 in ["--name", "--real"] { // id: cannot print only names or real IDs in default format let args = [opt1, c_flag]; ts.ucmd() @@ -396,7 +396,7 @@ fn test_id_context() { .args(&args) .succeeds() .stdout_only(unwrap_or_return!(expected_result(&ts, &args)).stdout_str()); - for &opt2 in &["--user", "--group", "--groups"] { + for opt2 in ["--user", "--group", "--groups"] { // u/g/G n/r z Z // for now, we print clap's standard response for "conflicts_with" instead of: // id: cannot print "only" of more than one choice @@ -409,7 +409,7 @@ fn test_id_context() { // .code_is(exp_result.code()); } } - for &opt2 in &["--user", "--group", "--groups"] { + for opt2 in ["--user", "--group", "--groups"] { // u/g/G z Z // for now, we print clap's standard response for "conflicts_with" instead of: // id: cannot print "only" of more than one choice diff --git a/tests/by-util/test_install.rs b/tests/by-util/test_install.rs index 0c775d145..a0e18c19a 100644 --- a/tests/by-util/test_install.rs +++ b/tests/by-util/test_install.rs @@ -1,4 +1,4 @@ -// spell-checker:ignore (words) helloworld objdump +// spell-checker:ignore (words) helloworld objdump n'source use crate::common::util::*; use filetime::FileTime; @@ -607,7 +607,11 @@ fn test_install_and_strip_with_program() { #[test] #[cfg(not(windows))] fn test_install_and_strip_with_invalid_program() { - new_ucmd!() + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + scene + .ucmd() .arg("-s") .arg("--strip-program") .arg("/bin/date") @@ -615,12 +619,17 @@ fn test_install_and_strip_with_invalid_program() { .arg(STRIP_TARGET_FILE) .fails() .stderr_contains("strip program failed"); + assert!(!at.file_exists(STRIP_TARGET_FILE)); } #[test] #[cfg(not(windows))] fn test_install_and_strip_with_non_existent_program() { - new_ucmd!() + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + scene + .ucmd() .arg("-s") .arg("--strip-program") .arg("/usr/bin/non_existent_program") @@ -628,6 +637,7 @@ fn test_install_and_strip_with_non_existent_program() { .arg(STRIP_TARGET_FILE) .fails() .stderr_contains("No such file or directory"); + assert!(!at.file_exists(STRIP_TARGET_FILE)); } #[test] @@ -1164,3 +1174,29 @@ fn test_install_dir_dot() { assert!(at.dir_exists("dir4/cal")); assert!(at.dir_exists("dir5/cali")); } + +#[test] +fn test_install_dir_req_verbose() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + let file_1 = "source_file1"; + let dest_dir = "sub4"; + at.touch(file_1); + scene + .ucmd() + .arg("-Dv") + .arg(file_1) + .arg("sub3/a/b/c/file") + .succeeds() + .stdout_contains("install: creating directory 'sub3'\ninstall: creating directory 'sub3/a'\ninstall: creating directory 'sub3/a/b'\ninstall: creating directory 'sub3/a/b/c'\n'source_file1' -> 'sub3/a/b/c/file'"); + + at.mkdir(dest_dir); + scene + .ucmd() + .arg("-Dv") + .arg(file_1) + .arg("sub4/a/b/c/file") + .succeeds() + .stdout_contains("install: creating directory 'sub4/a'\ninstall: creating directory 'sub4/a/b'\ninstall: creating directory 'sub4/a/b/c'\n'source_file1' -> 'sub4/a/b/c/file'"); +} diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index f60d53b6e..f979d1e14 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -604,7 +604,7 @@ fn test_ls_width() { at.touch(&at.plus_as_string("test-width-3")); at.touch(&at.plus_as_string("test-width-4")); - for option in &[ + for option in [ "-w 100", "-w=100", "--width=100", @@ -619,7 +619,7 @@ fn test_ls_width() { .stdout_only("test-width-1 test-width-2 test-width-3 test-width-4\n"); } - for option in &["-w 50", "-w=50", "--width=50", "--width 50", "--wid=50"] { + for option in ["-w 50", "-w=50", "--width=50", "--width 50", "--wid=50"] { scene .ucmd() .args(&option.split(' ').collect::>()) @@ -628,7 +628,7 @@ fn test_ls_width() { .stdout_only("test-width-1 test-width-3\ntest-width-2 test-width-4\n"); } - for option in &["-w 25", "-w=25", "--width=25", "--width 25", "--wid=25"] { + for option in ["-w 25", "-w=25", "--width=25", "--width 25", "--wid=25"] { scene .ucmd() .args(&option.split(' ').collect::>()) @@ -637,7 +637,7 @@ fn test_ls_width() { .stdout_only("test-width-1\ntest-width-2\ntest-width-3\ntest-width-4\n"); } - for option in &["-w 0", "-w=0", "--width=0", "--width 0", "--wid=0"] { + for option in ["-w 0", "-w=0", "--width=0", "--width 0", "--wid=0"] { scene .ucmd() .args(&option.split(' ').collect::>()) @@ -653,7 +653,7 @@ fn test_ls_width() { .fails() .stderr_contains("invalid line width"); - for option in &["-w 1a", "-w=1a", "--width=1a", "--width 1a", "--wid 1a"] { + for option in ["-w 1a", "-w=1a", "--width=1a", "--width 1a", "--wid 1a"] { scene .ucmd() .args(&option.split(' ').collect::>()) @@ -894,7 +894,7 @@ fn test_ls_long_symlink_color() { (Some([0, 0]), "ln-file1", None, "dir1/file1"), (Some([1, 1]), "ln-dir-invalid", Some([1, 1]), "dir1/dir2"), (Some([0, 0]), "ln-root", Some([0, 1]), "/"), - (Some([0, 0]), "ln-up2", Some([0, 1]), "../.."), + (Some([0, 0]), "ln-up2", None, "../.."), ]; // We are only interested in lines or the ls output that are symlinks. These start with "lrwx". @@ -912,6 +912,8 @@ fn test_ls_long_symlink_color() { while let Some((i, name, target)) = get_index_name_target(&mut result_lines) { // The unwraps within capture_colored_string will panic if the name/target's color // format is invalid. + dbg!(&name); + dbg!(&target); let (matched_name_color, matched_name) = capture_colored_string(&name); let (matched_target_color, matched_target) = capture_colored_string(&target); @@ -934,6 +936,7 @@ fn test_ls_long_symlink_color() { // Keep in mind an expected color `Option<&str>` of None can mean either that we // don't expect any color here, as in `expected_output[2], or don't know what specific // color to expect yet, as in expected_output[0:1]. + dbg!(&colors); assert_names_and_colors_are_equal( matched_name_color, expected_name_color, @@ -1088,9 +1091,9 @@ fn test_ls_long_total_size() { let result = scene.ucmd().arg(arg).succeeds(); result.stdout_contains(expected_prints["long_vanilla"]); - for arg2 in &["-h", "--human-readable", "--si"] { + for arg2 in ["-h", "--human-readable", "--si"] { let result = scene.ucmd().arg(arg).arg(arg2).succeeds(); - result.stdout_contains(if *arg2 == "--si" { + result.stdout_contains(if arg2 == "--si" { expected_prints["long_si"] } else { expected_prints["long_human_readable"] @@ -1158,7 +1161,7 @@ fn test_ls_long_formats() { .stdout_matches(&re_three_num); } - for arg in &[ + for arg in [ "-l", // only group and owner "-g --author", // only author and group "-o --author", // only author and owner @@ -1184,7 +1187,7 @@ fn test_ls_long_formats() { } } - for arg in &[ + for arg in [ "-g", // only group "-gl", // only group "-o", // only owner @@ -1213,7 +1216,7 @@ fn test_ls_long_formats() { } } - for arg in &[ + for arg in [ "-og", "-ogl", "-lgo", @@ -1255,7 +1258,7 @@ fn test_ls_oneline() { // Bit of a weird situation: in the tests oneline and columns have the same output, // except on Windows. - for option in &["-1", "--format=single-column"] { + for option in ["-1", "--format=single-column"] { scene .ucmd() .arg(option) @@ -1376,7 +1379,7 @@ fn test_ls_long_ctime() { at.touch("test-long-ctime-1"); - for arg in &["-c", "--time=ctime", "--time=status"] { + for arg in ["-c", "--time=ctime", "--time=status"] { let result = scene.ucmd().arg("-l").arg(arg).succeeds(); // Should show the time on Unix, but question marks on windows. @@ -1537,7 +1540,7 @@ fn test_ls_order_time() { // 3 was accessed last in the read // So the order should be 2 3 4 1 - for arg in &["-u", "--time=atime", "--time=access", "--time=use"] { + for arg in ["-u", "--time=atime", "--time=access", "--time=use"] { let result = scene.ucmd().arg("-t").arg(arg).succeeds(); at.open("test-3").metadata().unwrap().accessed().unwrap(); at.open("test-4").metadata().unwrap().accessed().unwrap(); @@ -1656,7 +1659,7 @@ fn test_ls_color() { assert!(!result.stdout_str().contains(z_with_colors)); // Color should be enabled - for param in &["--color", "--col", "--color=always", "--col=always"] { + for param in ["--color", "--col", "--color=always", "--col=always"] { scene .ucmd() .arg(param) @@ -2034,7 +2037,7 @@ fn test_ls_success_on_c_drv_root_windows() { fn test_ls_version_sort() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - for filename in &[ + for filename in [ "a2", "b1", "b20", @@ -2130,7 +2133,7 @@ fn test_ls_quoting_style() { .succeeds() .stdout_only("'one'$'\\n''two'\n"); - for (arg, correct) in &[ + for (arg, correct) in [ ("--quoting-style=literal", "one?two"), ("-N", "one?two"), ("--literal", "one?two"), @@ -2154,7 +2157,7 @@ fn test_ls_quoting_style() { .stdout_only(format!("{}\n", correct)); } - for (arg, correct) in &[ + for (arg, correct) in [ ("--quoting-style=literal", "one\ntwo"), ("-N", "one\ntwo"), ("--literal", "one\ntwo"), @@ -2170,7 +2173,7 @@ fn test_ls_quoting_style() { .stdout_only(format!("{}\n", correct)); } - for (arg, correct) in &[ + for (arg, correct) in [ ("--quoting-style=literal", "one\\two"), ("-N", "one\\two"), ("--quoting-style=c", "\"one\\\\two\""), @@ -2195,7 +2198,7 @@ fn test_ls_quoting_style() { // Tests for a character that forces quotation in shell-style escaping // after a character in a dollar expression at.touch("one\n&two"); - for (arg, correct) in &[ + for (arg, correct) in [ ("--quoting-style=shell-escape", "'one'$'\\n''&two'"), ("--quoting-style=shell-escape-always", "'one'$'\\n''&two'"), ] { @@ -2215,7 +2218,7 @@ fn test_ls_quoting_style() { .succeeds() .stdout_only("'one two'\n"); - for (arg, correct) in &[ + for (arg, correct) in [ ("--quoting-style=literal", "one two"), ("-N", "one two"), ("--literal", "one two"), @@ -2241,7 +2244,7 @@ fn test_ls_quoting_style() { scene.ucmd().arg("one").succeeds().stdout_only("one\n"); - for (arg, correct) in &[ + for (arg, correct) in [ ("--quoting-style=literal", "one"), ("-N", "one"), ("--quoting-style=c", "\"one\""), @@ -2649,7 +2652,7 @@ fn test_ls_deref_command_line_dir() { fn test_ls_sort_extension() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; - for filename in &[ + for filename in [ "file1", "file2", "anotherFile", @@ -2831,7 +2834,7 @@ fn test_ls_context2() { return; } let ts = TestScenario::new(util_name!()); - for c_flag in &["-Z", "--context"] { + for c_flag in ["-Z", "--context"] { ts.ucmd() .args(&[c_flag, &"/"]) .succeeds() @@ -2851,7 +2854,7 @@ fn test_ls_context_format() { // NOTE: // --format=long/verbose matches the output of GNU's ls for --context // except for the size count which may differ to the size count reported by GNU's ls. - for word in &[ + for word in [ "across", "commas", "horizontal", diff --git a/tests/by-util/test_mkdir.rs b/tests/by-util/test_mkdir.rs index 675ca6bea..be7a95af2 100644 --- a/tests/by-util/test_mkdir.rs +++ b/tests/by-util/test_mkdir.rs @@ -1,6 +1,10 @@ use crate::common::util::*; #[cfg(not(windows))] use std::os::unix::fs::PermissionsExt; +#[cfg(not(windows))] +extern crate libc; +#[cfg(not(windows))] +use self::libc::{mode_t, umask}; static TEST_DIR1: &str = "mkdir_test1"; static TEST_DIR2: &str = "mkdir_test2"; @@ -13,6 +17,8 @@ static TEST_DIR8: &str = "mkdir_test8/mkdir_test8_1/mkdir_test8_2"; static TEST_DIR9: &str = "mkdir_test9/../mkdir_test9_1/../mkdir_test9_2"; static TEST_DIR10: &str = "mkdir_test10/."; static TEST_DIR11: &str = "mkdir_test11/.."; +#[cfg(not(windows))] +static TEST_DIR12: &str = "mkdir_test12"; #[test] fn test_mkdir_mkdir() { @@ -151,3 +157,26 @@ fn test_mkdir_trailing_dot() { let result = scene2.cmd("ls").arg("-al").run(); println!("ls dest {}", result.stdout_str()); } + +#[test] +#[cfg(not(windows))] +fn test_umask_compliance() { + fn test_single_case(umask_set: mode_t) { + let (at, mut ucmd) = at_and_ucmd!(); + + let original_umask = unsafe { umask(umask_set) }; + + ucmd.arg(TEST_DIR12).succeeds(); + let perms = at.metadata(TEST_DIR12).permissions().mode() as mode_t; + + assert_eq!(perms, (!umask_set & 0o0777) + 0o40000); // before compare, add the set GUID, UID bits + unsafe { + umask(original_umask); + } // set umask back to original + } + + for i in 0o0..0o027 { + // tests all permission combinations + test_single_case(i as mode_t); + } +} diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index a0bd0209d..314fd3a7f 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -800,6 +800,47 @@ fn test_mv_permission_error() { .stderr_contains("Permission denied"); } +#[test] +fn test_mv_interactive_error() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + let dir = "test_mv_errors_dir"; + let file_a = "test_mv_errors_file_a"; + at.mkdir(dir); + at.touch(file_a); + + // $ at.mkdir dir && at.touch file + // $ mv -i dir file + // err == mv: cannot overwrite non-directory 'file' with directory 'dir' + assert!(!scene + .ucmd() + .arg("-i") + .arg(dir) + .arg(file_a) + .pipe_in("y") + .fails() + .stderr_str() + .is_empty()); +} + +#[test] +fn test_mv_info_self() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + let dir1 = "dir1"; + let dir2 = "dir2"; + at.mkdir(dir1); + at.mkdir(dir2); + + scene + .ucmd() + .arg(dir1) + .arg(dir2) + .arg(dir2) + .fails() + .stderr_contains("mv: cannot move 'dir2' to a subdirectory of itself, 'dir2/dir2'"); +} + // Todo: // $ at.touch a b diff --git a/tests/by-util/test_nl.rs b/tests/by-util/test_nl.rs index ce3014311..1ed46c313 100644 --- a/tests/by-util/test_nl.rs +++ b/tests/by-util/test_nl.rs @@ -42,7 +42,7 @@ fn test_padding_with_overflow() { #[test] fn test_sections_and_styles() { // spell-checker:disable - for &(fixture, output) in &[ + for (fixture, output) in [ ( "section.txt", "\nHEADER1\nHEADER2\n\n1 |BODY1\n2 \ diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index 0086c25e1..38faacdc5 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -484,7 +484,7 @@ fn test_delimiter_with_padding_and_fields() { #[test] fn test_round() { - for (method, exp) in &[ + for (method, exp) in [ ("from-zero", ["9.1K", "-9.1K", "9.1K", "-9.1K"]), ("towards-zero", ["9.0K", "-9.0K", "9.0K", "-9.0K"]), ("up", ["9.1K", "-9.0K", "9.1K", "-9.0K"]), diff --git a/tests/by-util/test_od.rs b/tests/by-util/test_od.rs index a6a81d1d6..3272971d7 100644 --- a/tests/by-util/test_od.rs +++ b/tests/by-util/test_od.rs @@ -70,12 +70,12 @@ fn test_2files() { let file1 = tmpdir.join("test1"); let file2 = tmpdir.join("test2"); - for &(n, a) in &[(1, "a"), (2, "b")] { + for (n, a) in [(1, "a"), (2, "b")] { println!("number: {} letter:{}", n, a); } // spell-checker:disable-next-line - for &(path, data) in &[(&file1, "abcdefghijklmnop"), (&file2, "qrstuvwxyz\n")] { + for (path, data) in [(&file1, "abcdefghijklmnop"), (&file2, "qrstuvwxyz\n")] { let mut f = File::create(&path).unwrap(); assert!( f.write_all(data.as_bytes()).is_ok(), @@ -127,7 +127,7 @@ fn test_from_mixed() { // spell-checker:disable-next-line let (data1, data2, data3) = ("abcdefg", "hijklmnop", "qrstuvwxyz\n"); - for &(path, data) in &[(&file1, data1), (&file3, data3)] { + for (path, data) in [(&file1, data1), (&file3, data3)] { let mut f = File::create(&path).unwrap(); assert!( f.write_all(data.as_bytes()).is_ok(), diff --git a/tests/by-util/test_paste.rs b/tests/by-util/test_paste.rs index 09401ec59..6d539e45e 100644 --- a/tests/by-util/test_paste.rs +++ b/tests/by-util/test_paste.rs @@ -82,8 +82,8 @@ static EXAMPLE_DATA: &[TestData] = &[ #[test] fn test_combine_pairs_of_lines() { - for &s in &["-s", "--serial"] { - for &d in &["-d", "--delimiters"] { + for s in ["-s", "--serial"] { + for d in ["-d", "--delimiters"] { new_ucmd!() .args(&[s, d, "\t\n", "html_colors.txt"]) .run() @@ -94,7 +94,7 @@ fn test_combine_pairs_of_lines() { #[test] fn test_multi_stdin() { - for &d in &["-d", "--delimiters"] { + for d in ["-d", "--delimiters"] { new_ucmd!() .args(&[d, "\t\n", "-", "-"]) .pipe_in_fixture("html_colors.txt") diff --git a/tests/by-util/test_pr.rs b/tests/by-util/test_pr.rs index 2e72aaed7..cd832cf68 100644 --- a/tests/by-util/test_pr.rs +++ b/tests/by-util/test_pr.rs @@ -69,7 +69,7 @@ fn test_with_long_header_option() { let test_file_path = "test_one_page.log"; let expected_test_file_path = "test_one_page_header.log.expected"; let header = "new file"; - for args in &[&["-h", header][..], &["--header=new file"][..]] { + for args in [&["-h", header][..], &["--header=new file"][..]] { let mut scenario = new_ucmd!(); let value = file_last_modified_time(&scenario, test_file_path); scenario @@ -87,7 +87,7 @@ fn test_with_long_header_option() { fn test_with_double_space_option() { let test_file_path = "test_one_page.log"; let expected_test_file_path = "test_one_page_double_line.log.expected"; - for &arg in &["-d", "--double-space"] { + for arg in ["-d", "--double-space"] { let mut scenario = new_ucmd!(); let value = file_last_modified_time(&scenario, test_file_path); scenario @@ -183,7 +183,7 @@ fn test_with_page_range() { let test_file_path = "test.log"; let expected_test_file_path = "test_page_range_1.log.expected"; let expected_test_file_path1 = "test_page_range_2.log.expected"; - for &arg in &["--pages=15", "+15"] { + for arg in ["--pages=15", "+15"] { let mut scenario = new_ucmd!(); let value = file_last_modified_time(&scenario, test_file_path); scenario @@ -194,7 +194,7 @@ fn test_with_page_range() { &[("{last_modified_time}", &value)], ); } - for &arg in &["--pages=15:17", "+15:17"] { + for arg in ["--pages=15:17", "+15:17"] { let mut scenario = new_ucmd!(); let value = file_last_modified_time(&scenario, test_file_path); scenario @@ -222,7 +222,7 @@ fn test_with_no_header_trailer_option() { #[test] fn test_with_page_length_option() { let test_file_path = "test.log"; - for (arg, expected) in &[ + for (arg, expected) in [ ("100", "test_page_length.log.expected"), ("5", "test_page_length1.log.expected"), ] { @@ -265,7 +265,7 @@ fn test_with_stdin() { fn test_with_column() { let test_file_path = "column.log"; let expected_test_file_path = "column.log.expected"; - for arg in &["-3", "--column=3"] { + for arg in ["-3", "--column=3"] { let mut scenario = new_ucmd!(); let value = file_last_modified_time(&scenario, test_file_path); scenario @@ -293,7 +293,7 @@ fn test_with_column_across_option() { #[test] fn test_with_column_across_option_and_column_separator() { let test_file_path = "column.log"; - for (arg, expected) in &[ + for (arg, expected) in [ ("-s|", "column_across_sep.log.expected"), ("-Sdivide", "column_across_sep1.log.expected"), ] { diff --git a/tests/by-util/test_pwd.rs b/tests/by-util/test_pwd.rs index bc08ddbb0..950a148a3 100644 --- a/tests/by-util/test_pwd.rs +++ b/tests/by-util/test_pwd.rs @@ -26,7 +26,7 @@ fn test_deleted_dir() { let output = Command::new("sh") .arg("-c") .arg(format!( - "cd '{}'; mkdir foo; cd foo; rmdir ../foo; exec {} {}", + "cd '{}'; mkdir foo; cd foo; rmdir ../foo; exec '{}' {}", at.root_dir_resolved(), ts.bin_path.to_str().unwrap(), ts.util_name, diff --git a/tests/by-util/test_runcon.rs b/tests/by-util/test_runcon.rs index 047ce5769..dd4445625 100644 --- a/tests/by-util/test_runcon.rs +++ b/tests/by-util/test_runcon.rs @@ -22,11 +22,11 @@ fn help() { fn print() { new_ucmd!().succeeds(); - for &flag in &["-c", "--compute"] { + for flag in ["-c", "--compute"] { new_ucmd!().arg(flag).succeeds(); } - for &flag in &[ + for flag in [ "-t", "--type", "-u", "--user", "-r", "--role", "-l", "--range", ] { new_ucmd!().args(&[flag, "example"]).succeeds(); @@ -57,7 +57,7 @@ fn invalid() { // TODO: Enable this code once the issue is fixed in the clap version we're using. //new_ucmd!().arg("--compute=example").fails().code_is(1); - for &flag in &[ + for flag in [ "-t", "--type", "-u", "--user", "-r", "--role", "-l", "--range", ] { new_ucmd!().arg(flag).fails().code_is(1); @@ -119,7 +119,7 @@ fn custom_context() { let args = &["--compute", "--range=s0", "/bin/true"]; new_ucmd!().args(args).succeeds(); - for &(ctx, u, r) in &[ + for (ctx, u, r) in [ ("unconfined_u:unconfined_r:unconfined_t:s0", u_ud, r_ud), ("system_u:unconfined_r:unconfined_t:s0", "system_u", r_ud), ("unconfined_u:system_r:unconfined_t:s0", u_ud, "system_r"), diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index c33d1a986..4975ceff4 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -220,7 +220,7 @@ fn test_random_shuffle_contains_all_lines() { #[test] fn test_random_shuffle_two_runs_not_the_same() { - for arg in &["-R", "-k1,1R"] { + for arg in ["-R", "-k1,1R"] { // check to verify that two random shuffles are not equal; this has the // potential to fail in the very unlikely event that the random order is the same // as the starting order, or if both random sorts end up having the same order. @@ -407,7 +407,7 @@ fn test_mixed_floats_ints_chars_numeric_stable() { #[test] fn test_numeric_floats_and_ints2() { - for numeric_sort_param in &["-n", "--numeric-sort"] { + for numeric_sort_param in ["-n", "--numeric-sort"] { let input = "1.444\n8.013\n1\n-8\n1.04\n-1"; new_ucmd!() .arg(numeric_sort_param) @@ -419,7 +419,7 @@ fn test_numeric_floats_and_ints2() { #[test] fn test_numeric_floats2() { - for numeric_sort_param in &["-n", "--numeric-sort"] { + for numeric_sort_param in ["-n", "--numeric-sort"] { let input = "1.444\n8.013\n1.58590\n-8.90880\n1.040000000\n-.05"; new_ucmd!() .arg(numeric_sort_param) @@ -439,7 +439,7 @@ fn test_numeric_floats_with_nan2() { #[test] fn test_human_block_sizes2() { - for human_numeric_sort_param in &["-h", "--human-numeric-sort", "--sort=human-numeric"] { + for human_numeric_sort_param in ["-h", "--human-numeric-sort", "--sort=human-numeric"] { let input = "8981K\n909991M\n-8T\n21G\n0.8M"; new_ucmd!() .arg(human_numeric_sort_param) @@ -461,7 +461,7 @@ fn test_human_numeric_zero_stable() { #[test] fn test_month_default2() { - for month_sort_param in &["-M", "--month-sort", "--sort=month"] { + for month_sort_param in ["-M", "--month-sort", "--sort=month"] { let input = "JAn\nMAY\n000may\nJun\nFeb"; new_ucmd!() .arg(month_sort_param) @@ -555,7 +555,7 @@ fn test_keys_invalid_char_zero() { #[test] fn test_keys_with_options() { let input = "aa 3 cc\ndd 1 ff\ngg 2 cc\n"; - for param in &[ + for param in [ &["-k", "2,2n"][..], &["-k", "2n,2"][..], &["-k", "2,2", "-n"][..], @@ -571,7 +571,7 @@ fn test_keys_with_options() { #[test] fn test_keys_with_options_blanks_start() { let input = "aa 3 cc\ndd 1 ff\ngg 2 cc\n"; - for param in &[&["-k", "2b,2"][..], &["-k", "2,2", "-b"][..]] { + for param in [&["-k", "2b,2"][..], &["-k", "2,2", "-b"][..]] { new_ucmd!() .args(param) .pipe_in(input) @@ -761,7 +761,7 @@ fn test_pipe() { #[test] fn test_check() { - for diagnose_arg in &["-c", "--check", "--check=diagnose-first"] { + for diagnose_arg in ["-c", "--check", "--check=diagnose-first"] { new_ucmd!() .arg(diagnose_arg) .arg("check_fail.txt") @@ -779,7 +779,7 @@ fn test_check() { #[test] fn test_check_silent() { - for silent_arg in &["-C", "--check=silent", "--check=quiet"] { + for silent_arg in ["-C", "--check=silent", "--check=quiet"] { new_ucmd!() .arg(silent_arg) .arg("check_fail.txt") @@ -803,7 +803,7 @@ fn test_check_unique() { #[test] fn test_dictionary_and_nonprinting_conflicts() { let conflicting_args = ["n", "h", "g", "M"]; - for restricted_arg in &["d", "i"] { + for restricted_arg in ["d", "i"] { for conflicting_arg in &conflicting_args { new_ucmd!() .arg(&format!("-{}{}", restricted_arg, conflicting_arg)) diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 65db4804e..b8445543f 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -236,7 +236,7 @@ fn test_symlinks() { let mut tested: bool = false; // arbitrarily chosen symlinks with hope that the CI environment provides at least one of them - for file in &[ + for file in [ "/bin/sh", "/bin/sudoedit", "/usr/bin/ex", diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index fed77e806..5abf3a8f0 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -676,7 +676,7 @@ fn test_bytes_for_funny_files() { // gnu/tests/tail-2/tail-c.sh let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - for &file in &["/proc/version", "/sys/kernel/profiling"] { + for file in ["/proc/version", "/sys/kernel/profiling"] { if !at.file_exists(file) { continue; } diff --git a/tests/by-util/test_tee.rs b/tests/by-util/test_tee.rs index 17e3c05cf..e89b9d438 100644 --- a/tests/by-util/test_tee.rs +++ b/tests/by-util/test_tee.rs @@ -9,7 +9,7 @@ fn test_tee_processing_multiple_operands() { // POSIX says: "Processing of at least 13 file operands shall be supported." let content = "tee_sample_content"; - for &n in &[1, 2, 12, 13] { + for n in [1, 2, 12, 13] { let files = (1..=n).map(|x| x.to_string()).collect::>(); let (at, mut ucmd) = at_and_ucmd!(); diff --git a/tests/by-util/test_timeout.rs b/tests/by-util/test_timeout.rs index fef5fd4ae..5d77e1fa0 100644 --- a/tests/by-util/test_timeout.rs +++ b/tests/by-util/test_timeout.rs @@ -39,7 +39,7 @@ fn test_command_with_args() { #[test] fn test_verbose() { - for &verbose_flag in &["-v", "--verbose"] { + for verbose_flag in ["-v", "--verbose"] { new_ucmd!() .args(&[verbose_flag, ".1", "sleep", "10"]) .fails() diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index d7a0df129..6e5d656c4 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -333,7 +333,7 @@ fn test_touch_reference() { at.touch(file_a); set_file_times(&at, file_a, start_of_year, start_of_year); assert!(at.file_exists(file_a)); - for &opt in &["-r", "--ref", "--reference"] { + for opt in ["-r", "--ref", "--reference"] { scenario .ccmd("touch") .args(&[opt, file_a, file_b]) diff --git a/tests/by-util/test_uniq.rs b/tests/by-util/test_uniq.rs index cd013891b..b3f5fcd68 100644 --- a/tests/by-util/test_uniq.rs +++ b/tests/by-util/test_uniq.rs @@ -1,3 +1,4 @@ +// spell-checker:ignore nabcd use crate::common::util::*; static INPUT: &str = "sorted.txt"; @@ -194,3 +195,713 @@ fn test_group_separate() { .run() .stdout_is_fixture("group.expected"); } + +#[test] +fn test_case2() { + new_ucmd!().pipe_in("a\na\n").run().stdout_is("a\n"); +} + +struct TestCase { + name: &'static str, + args: &'static [&'static str], + input: &'static str, + stdout: Option<&'static str>, + stderr: Option<&'static str>, + exit: Option, +} + +#[test] +fn gnu_tests() { + let cases = [ + TestCase { + name: "1", + args: &[], + input: "", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "2", + args: &[], + input: "a\na\n", + stdout: Some("a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "3", + args: &[], + input: "a\na", + stdout: Some("a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "4", + args: &[], + input: "a\nb", + stdout: Some("a\nb\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "5", + args: &[], + input: "a\na\nb", + stdout: Some("a\nb\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "6", + args: &[], + input: "b\na\na\n", + stdout: Some("b\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "7", + args: &[], + input: "a\nb\nc\n", + stdout: Some("a\nb\nc\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "2z", + args: &["-z"], + input: "a\na\n", + stdout: Some("a\na\n\0"), + stderr: None, + exit: None, + }, + TestCase { + name: "3z", + args: &["-z"], + input: "a\na", + stdout: Some("a\na\0"), + stderr: None, + exit: None, + }, + TestCase { + name: "4z", + args: &["-z"], + input: "a\nb", + stdout: Some("a\nb\0"), + stderr: None, + exit: None, + }, + TestCase { + name: "5z", + args: &["-z"], + input: "a\na\nb", + stdout: Some("a\na\nb\0"), + stderr: None, + exit: None, + }, + TestCase { + name: "10z", + args: &["-z", "-f1"], + input: "a\nb\n\0c\nb\n\0", + stdout: Some("a\nb\n\0"), + stderr: None, + exit: None, + }, + TestCase { + name: "20z", + args: &["-dz"], + input: "a\na\n", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "8", + args: &[], + input: "ö\nv\n", + stdout: Some("ö\nv\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "9", + args: &["-u"], + input: "a\na\n", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "10", + args: &["-u"], + input: "a\nb\n", + stdout: Some("a\nb\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "11", + args: &["-u"], + input: "a\nb\na\n", + stdout: Some("a\nb\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "12", + args: &["-u"], + input: "a\na\n", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "13", + args: &["-u"], + input: "a\na\n", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "20", + args: &["-d"], + input: "a\na\n", + stdout: Some("a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "21", + args: &["-d"], + input: "a\nb\n", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "22", + args: &["-d"], + input: "a\nb\na\n", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "23", + args: &["-d"], + input: "a\na\nb\n", + stdout: Some("a\n"), + stderr: None, + exit: None, + }, + // // Obsolete syntax for "-f 1" + // TestCase { + // name: "obs30", + // args: &["-1"], + // input: "a a\nb a\n", + // stdout: Some("a a\n"), + // stderr: None, + // exit: None, + // }, + TestCase { + name: "31", + args: &["-f", "1"], + input: "a a\nb a\n", + stdout: Some("a a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "32", + args: &["-f", "1"], + input: "a a\nb b\n", + stdout: Some("a a\nb b\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "33", + args: &["-f", "1"], + input: "a a a\nb a c\n", + stdout: Some("a a a\nb a c\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "34", + args: &["-f", "1"], + input: "b a\na a\n", + stdout: Some("b a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "35", + args: &["-f", "2"], + input: "a a c\nb a c\n", + stdout: Some("a a c\n"), + stderr: None, + exit: None, + }, + // // Obsolete syntax for "-s 1" + // TestCase { + // name: "obs-plus40", + // args: &["+1"], + // input: "aaa\naaa\n", + // stdout: Some("aaa\n"), + // stderr: None, + // exit: None, + // }, + // TestCase { + // name: "obs-plus41", + // args: &["+1"], + // input: "baa\naaa\n", + // stdout: Some("baa\n"), + // stderr: None, + // exit: None, + // }, + TestCase { + name: "42", + args: &["-s", "1"], + input: "aaa\naaa\n", + stdout: Some("aaa\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "43", + args: &["-s", "2"], + input: "baa\naaa\n", + stdout: Some("baa\n"), + stderr: None, + exit: None, + }, + // // Obsolete syntax for "-s 1" + // TestCase { + // name: "obs-plus44", + // args: &["+1", "--"], + // input: "aaa\naaa\n", + // stdout: Some("aaa\n"), + // stderr: None, + // exit: None, + // }, + // TestCase { + // name: "obs-plus45", + // args: &["+1", "--"], + // input: "baa\naaa\n", + // stdout: Some("baa\n"), + // stderr: None, + // exit: None, + // }, + TestCase { + name: "50", + args: &["-f", "1", "-s", "1"], + input: "a aaa\nb ab\n", + stdout: Some("a aaa\nb ab\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "51", + args: &["-f", "1", "-s", "1"], + input: "a aaa\nb aaa\n", + stdout: Some("a aaa\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "52", + args: &["-s", "1", "-f", "1"], + input: "a aaa\nb ab\n", + stdout: Some("a aaa\nb ab\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "53", + args: &["-s", "1", "-f", "1"], + input: "a aaa\nb aaa\n", + stdout: Some("a aaa\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "54", + args: &["-s", "4"], + input: "abc\nabcd\n", + stdout: Some("abc\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "55", + args: &["-s", "0"], + input: "abc\nabcd\n", + stdout: Some("abc\nabcd\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "56", + args: &["-s", "0"], + input: "abc\n", + stdout: Some("abc\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "57", + args: &["-w", "0"], + input: "abc\nabcd\n", + stdout: Some("abc\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "60", + args: &["-w", "1"], + input: "a a\nb a\n", + stdout: Some("a a\nb a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "61", + args: &["-w", "3"], + input: "a a\nb a\n", + stdout: Some("a a\nb a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "62", + args: &["-w", "1", "-f", "1"], + input: "a a a\nb a c\n", + stdout: Some("a a a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "63", + args: &["-f", "1", "-w", "1"], + input: "a a a\nb a c\n", + stdout: Some("a a a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "64", + args: &["-f", "1", "-w", "4"], + input: "a a a\nb a c\n", + stdout: Some("a a a\nb a c\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "65", + args: &["-f", "1", "-w", "3"], + input: "a a a\nb a c\n", + stdout: Some("a a a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "90", + args: &[], + input: "a\0a\na\n", + stdout: Some("a\0a\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "91", + args: &[], + input: "a\ta\na a\n", + stdout: Some("a\ta\na a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "92", + args: &["-f", "1"], + input: "a\ta\na a\n", + stdout: Some("a\ta\na a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "93", + args: &["-f", "2"], + input: "a\ta a\na a a\n", + stdout: Some("a\ta a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "94", + args: &["-f", "1"], + input: "a\ta\na\ta\n", + stdout: Some("a\ta\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "101", + args: &["-c"], + input: "a\nb\n", + stdout: Some(" 1 a\n 1 b\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "102", + args: &["-c"], + input: "a\na\n", + stdout: Some(" 2 a\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "110", + args: &["-D"], + input: "a\na\n", + stdout: Some("a\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "111", + args: &["-D", "-w1"], + input: "a a\na b\n", + stdout: Some("a a\na b\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "112", + args: &["-D", "-c"], + input: "a a\na b\n", + stdout: Some(""), + stderr: Some("uniq: printing all duplicated lines and repeat counts is meaningless"), + exit: Some(1), + }, + TestCase { + name: "113", + args: &["--all-repeated=separate"], + input: "a\na\n", + stdout: Some("a\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "114", + args: &["--all-repeated=separate"], + input: "a\na\nb\nc\nc\n", + stdout: Some("a\na\n\nc\nc\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "115", + args: &["--all-repeated=separate"], + input: "a\na\nb\nb\nc\n", + stdout: Some("a\na\n\nb\nb\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "116", + args: &["--all-repeated=prepend"], + input: "a\na\n", + stdout: Some("\na\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "117", + args: &["--all-repeated=prepend"], + input: "a\na\nb\nc\nc\n", + stdout: Some("\na\na\n\nc\nc\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "118", + args: &["--all-repeated=prepend"], + input: "a\nb\n", + stdout: Some(""), + stderr: None, + exit: None, + }, + // \x08 is the backspace char + TestCase { + name: "120", + args: &["-d", "-u"], + input: "a\na\n\x08", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "123", + args: &["--zero-terminated"], + input: "a\na\nb", + stdout: Some("a\na\nb\0"), + stderr: None, + exit: None, + }, + TestCase { + name: "124", + args: &["--zero-terminated"], + input: "a\0a\0b", + stdout: Some("a\0b\0"), + stderr: None, + exit: None, + }, + TestCase { + name: "125", + args: &[], + input: "A\na\n", + stdout: Some("A\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "126", + args: &["-i"], + input: "A\na\n", + stdout: Some("A\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "127", + args: &["--ignore-case"], + input: "A\na\n", + stdout: Some("A\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "128", + args: &["--group=prepend"], + input: "a\na\nb\n", + stdout: Some("\na\na\n\nb\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "129", + args: &["--group=append"], + input: "a\na\nb\n", + stdout: Some("a\na\n\nb\n\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "130", + args: &["--group=separate"], + input: "a\na\nb\n", + stdout: Some("a\na\n\nb\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "131", + args: &["--group"], + input: "a\na\nb\n", + stdout: Some("a\na\n\nb\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "132", + args: &["--group=both"], + input: "a\na\nb\n", + stdout: Some("\na\na\n\nb\n\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "133", + args: &["--group=prepend"], + input: "a\na\n", + stdout: Some("\na\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "134", + args: &["--group=append"], + input: "a\na\n", + stdout: Some("a\na\n\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "135", + args: &["--group=separate"], + input: "a\na\n", + stdout: Some("a\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "136", + args: &["--group"], + input: "a\na\n", + stdout: Some("a\na\n"), + stderr: None, + exit: None, + }, + TestCase { + name: "137", + args: &["--group=prepend"], + input: "", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "138", + args: &["--group=append"], + input: "", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "139", + args: &["--group=separate"], + input: "", + stdout: Some(""), + stderr: None, + exit: None, + }, + TestCase { + name: "140", + args: &["--group=both"], + input: "", + stdout: Some(""), + stderr: None, + exit: None, + }, + ]; + + for case in cases { + eprintln!("Test {}", case.name); + let result = new_ucmd!().args(case.args).run_piped_stdin(case.input); + if let Some(stdout) = case.stdout { + result.stdout_is(stdout); + } + if let Some(stderr) = case.stderr { + result.stderr_contains(stderr); + } + if let Some(exit) = case.exit { + result.code_is(exit); + } + } +} diff --git a/tests/by-util/test_vdir.rs b/tests/by-util/test_vdir.rs new file mode 100644 index 000000000..01c540095 --- /dev/null +++ b/tests/by-util/test_vdir.rs @@ -0,0 +1,55 @@ +#[cfg(not(windows))] +extern crate libc; +extern crate regex; +#[cfg(not(windows))] +extern crate tempfile; +#[cfg(unix)] +extern crate unix_socket; + +use self::regex::Regex; +use crate::common::util::*; + +/* + * As vdir use the same functions than ls, we don't have to retest them here. + * We just test the default and the column output +*/ + +#[test] +fn test_vdir() { + new_ucmd!().succeeds(); +} + +#[test] +fn test_default_output() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("some-dir1"); + at.touch("some-file1"); + + scene.ucmd().succeeds().stdout_contains("some-file1"); + + scene + .ucmd() + .succeeds() + .stdout_matches(&Regex::new("[rwx][^some-file1]").unwrap()); +} + +#[test] +fn test_column_output() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + at.mkdir("some-dir1"); + at.touch("some-file1"); + + scene + .ucmd() + .arg("-C") + .succeeds() + .stdout_contains("some-file1"); + + scene + .ucmd() + .arg("-C") + .succeeds() + .stdout_does_not_match(&Regex::new("[rwx][^some-file1]").unwrap()); +} diff --git a/tests/by-util/test_wc.rs b/tests/by-util/test_wc.rs index 1efbe81a7..3537f902d 100644 --- a/tests/by-util/test_wc.rs +++ b/tests/by-util/test_wc.rs @@ -7,7 +7,7 @@ use crate::common::util::*; #[test] fn test_count_bytes_large_stdin() { - for &n in &[ + for n in [ 0, 1, 42, diff --git a/tests/by-util/test_who.rs b/tests/by-util/test_who.rs index 65773655d..580d9ea6f 100644 --- a/tests/by-util/test_who.rs +++ b/tests/by-util/test_who.rs @@ -12,7 +12,7 @@ use crate::common::util::*; #[ignore = "issue #3219"] fn test_count() { let ts = TestScenario::new(util_name!()); - for opt in &["-q", "--count", "--c"] { + for opt in ["-q", "--count", "--c"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } @@ -22,7 +22,7 @@ fn test_count() { #[test] fn test_boot() { let ts = TestScenario::new(util_name!()); - for opt in &["-b", "--boot", "--b"] { + for opt in ["-b", "--boot", "--b"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } @@ -33,7 +33,7 @@ fn test_boot() { #[ignore = "issue #3219"] fn test_heading() { let ts = TestScenario::new(util_name!()); - for opt in &["-H", "--heading", "--head"] { + for opt in ["-H", "--heading", "--head"] { // allow whitespace variation // * minor whitespace differences occur between platform built-in outputs; // specifically number of TABs between "TIME" and "COMMENT" may be variant @@ -52,7 +52,7 @@ fn test_heading() { #[ignore = "issue #3219"] fn test_short() { let ts = TestScenario::new(util_name!()); - for opt in &["-s", "--short", "--s"] { + for opt in ["-s", "--short", "--s"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } @@ -62,7 +62,7 @@ fn test_short() { #[test] fn test_login() { let ts = TestScenario::new(util_name!()); - for opt in &["-l", "--login", "--log"] { + for opt in ["-l", "--login", "--log"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } @@ -80,7 +80,7 @@ fn test_m() { #[test] fn test_process() { let ts = TestScenario::new(util_name!()); - for opt in &["-p", "--process", "--p"] { + for opt in ["-p", "--process", "--p"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } @@ -90,7 +90,7 @@ fn test_process() { #[test] fn test_runlevel() { let ts = TestScenario::new(util_name!()); - for opt in &["-r", "--runlevel", "--r"] { + for opt in ["-r", "--runlevel", "--r"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); @@ -103,7 +103,7 @@ fn test_runlevel() { #[test] fn test_time() { let ts = TestScenario::new(util_name!()); - for opt in &["-t", "--time", "--t"] { + for opt in ["-t", "--time", "--t"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } @@ -120,7 +120,7 @@ fn test_mesg() { // --writable // same as -T let ts = TestScenario::new(util_name!()); - for opt in &[ + for opt in [ "-T", "-w", "--mesg", @@ -157,7 +157,7 @@ fn test_too_many_args() { #[ignore = "issue #3219"] fn test_users() { let ts = TestScenario::new(util_name!()); - for opt in &["-u", "--users", "--us"] { + for opt in ["-u", "--users", "--us"] { let actual = ts.ucmd().arg(opt).succeeds().stdout_move_str(); let expect = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); println!("actual: {:?}", actual); @@ -192,7 +192,7 @@ fn test_lookup() { #[test] fn test_dead() { let ts = TestScenario::new(util_name!()); - for opt in &["-d", "--dead", "--de"] { + for opt in ["-d", "--dead", "--de"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } @@ -226,7 +226,7 @@ fn test_all() { } let ts = TestScenario::new(util_name!()); - for opt in &["-a", "--all", "--a"] { + for opt in ["-a", "--all", "--a"] { let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } diff --git a/tests/by-util/test_yes.rs b/tests/by-util/test_yes.rs index 38165e92b..7325cb4bc 100644 --- a/tests/by-util/test_yes.rs +++ b/tests/by-util/test_yes.rs @@ -55,7 +55,7 @@ fn test_long_input() { fn test_piped_to_dev_full() { use std::fs::OpenOptions; - for &append in &[true, false] { + for append in [true, false] { { let dev_full = OpenOptions::new() .write(true) diff --git a/tests/common/util.rs b/tests/common/util.rs index 5e1424ca4..bf7143bb5 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -3,13 +3,13 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -//spell-checker: ignore (linux) rlimit prlimit Rlim coreutil ggroups +//spell-checker: ignore (linux) rlimit prlimit coreutil ggroups #![allow(dead_code)] use pretty_assertions::assert_eq; #[cfg(target_os = "linux")] -use rlimit::{prlimit, rlim}; +use rlimit::prlimit; #[cfg(unix)] use std::borrow::Cow; use std::env; @@ -221,7 +221,7 @@ impl CmdResult { assert!( self.stdout.is_empty(), "Expected stdout to be empty, but it's:\n{}", - self.stderr_str() + self.stdout_str() ); self } @@ -893,7 +893,7 @@ pub struct UCommand { stderr: Option, bytes_into_stdin: Option>, #[cfg(target_os = "linux")] - limits: Vec<(rlimit::Resource, rlim, rlim)>, + limits: Vec<(rlimit::Resource, u64, u64)>, } impl UCommand { @@ -1046,8 +1046,8 @@ impl UCommand { pub fn with_limit( &mut self, resource: rlimit::Resource, - soft_limit: rlim, - hard_limit: rlim, + soft_limit: u64, + hard_limit: u64, ) -> &mut Self { self.limits.push((resource, soft_limit, hard_limit)); self diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 924d14d25..0aad35ff1 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -171,13 +171,22 @@ sed -i "s/ {ERR_SUBST=>\"s\/(unrecognized|unknown) option \[-' \]\*foobar\[' \] # Remove the check whether a util was built. Otherwise tests against utils like "arch" are not run. sed -i "s|require_built_ |# require_built_ |g" init.cfg +# usage_vs_getopt.sh is heavily modified as it runs all the binaries # with the option -/ is used, clap is returning a better error than GNU's. Adjust the GNU test sed -i -e "s~ grep \" '\*/'\*\" err || framework_failure_~ grep \" '*-/'*\" err || framework_failure_~" tests/misc/usage_vs_getopt.sh sed -i -e "s~ sed -n \"1s/'\\\/'/'OPT'/p\" < err >> pat || framework_failure_~ sed -n \"1s/'-\\\/'/'OPT'/p\" < err >> pat || framework_failure_~" tests/misc/usage_vs_getopt.sh # Ignore some binaries (not built) # And change the default error code to 2 -# see issue #3331 -sed -i -e "s/rcexp=1$/rcexp=2\n case \"\$prg\" in chcon|dir|runcon|vdir) return;; esac/" tests/misc/usage_vs_getopt.sh +# see issue #3331 (clap limitation). +# Upstream returns 1 for most of the program. We do for cp, truncate & pr +# So, keep it as it +sed -i -e "s/rcexp=1$/rcexp=2\n case \"\$prg\" in chcon|runcon) return;; esac/" -e "s/rcexp=125 ;;/rcexp=2 ;;\ncp|truncate|pr) rcexp=1;;/" tests/misc/usage_vs_getopt.sh +# GNU has option=[SUFFIX], clap is +sed -i -e "s/cat opts/sed -i -e \"s| <.\*>$||g\" opts/" tests/misc/usage_vs_getopt.sh +# Strip empty lines for the diff - see https://github.com/uutils/coreutils/issues/3370 +sed -i -e "s~out 2>err1~out 2>err1\nsed '/^$/d' out > out\nsed '/^$/d' help > help~" tests/misc/usage_vs_getopt.sh +# for some reasons, some stuff are duplicated, strip that +sed -i -e "s/provoked error./provoked error\ncat pat |sort -u > pat/" tests/misc/usage_vs_getopt.sh # Update the GNU error message to match ours sed -i -e "s/ln: 'f' and 'f' are the same file/ln: failed to link 'f' to 'f': Same file/g" tests/ln/hard-backup.sh diff --git a/util/remaining-gnu-error.py b/util/remaining-gnu-error.py index 5be7e784c..edfb2a846 100755 --- a/util/remaining-gnu-error.py +++ b/util/remaining-gnu-error.py @@ -15,11 +15,11 @@ urllib.request.urlretrieve( "result.json", ) -tests = glob.glob(base + "/*/*.sh") -tests_pl = glob.glob(base + "/*/*.pl") -tests_xpl = glob.glob(base + "/*/*.xpl") -tests = tests + tests_pl + tests_xpl +types = ("/*/*.sh", "/*/*.pl", "/*/*.xpl") +tests = [] +for files in types: + tests.extend(glob.glob(base + files)) # sort by size list_of_files = sorted(tests, key=lambda x: os.stat(x).st_size) @@ -30,7 +30,7 @@ for d in data: for e in data[d]: # Not all the tests are .sh files, rename them if not. script = e.replace(".log", ".sh") - a = f"{base}{d}{script}" + a = f"{base}{d}/{script}" if not os.path.exists(a): a = a.replace(".sh", ".pl") if not os.path.exists(a):