mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge branch 'main' into ls_LZ
This commit is contained in:
commit
873c6c36f7
42 changed files with 509 additions and 303 deletions
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
github: uutils
|
2
.github/workflows/CICD.yml
vendored
2
.github/workflows/CICD.yml
vendored
|
@ -319,7 +319,7 @@ jobs:
|
|||
shell: bash
|
||||
run: |
|
||||
RUSTDOCFLAGS="-Dwarnings" cargo doc ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-deps --workspace --document-private-items
|
||||
- uses: DavidAnson/markdownlint-cli2-action@v10
|
||||
- uses: DavidAnson/markdownlint-cli2-action@v11
|
||||
with:
|
||||
command: fix
|
||||
globs: |
|
||||
|
|
2
.github/workflows/GnuTests.yml
vendored
2
.github/workflows/GnuTests.yml
vendored
|
@ -205,7 +205,7 @@ jobs:
|
|||
path_UUTILS='${{ steps.vars.outputs.path_UUTILS }}'
|
||||
# https://github.com/uutils/coreutils/issues/4294
|
||||
# https://github.com/uutils/coreutils/issues/4295
|
||||
IGNORE_INTERMITTENT='${path_UUTILS}/.github/workflows/ignore-intermittent.txt'
|
||||
IGNORE_INTERMITTENT="${path_UUTILS}/.github/workflows/ignore-intermittent.txt"
|
||||
|
||||
mkdir -p ${{ steps.vars.outputs.path_reference }}
|
||||
|
||||
|
|
4
.github/workflows/freebsd.yml
vendored
4
.github/workflows/freebsd.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
|||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
- name: Prepare, build and test
|
||||
uses: vmactions/freebsd-vm@v0.3.0
|
||||
uses: vmactions/freebsd-vm@v0.3.1
|
||||
with:
|
||||
usesh: true
|
||||
# We need jq to run show-utils.sh and bash to use inline shell string replacement
|
||||
|
@ -125,7 +125,7 @@ jobs:
|
|||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
- name: Prepare, build and test
|
||||
uses: vmactions/freebsd-vm@v0.3.0
|
||||
uses: vmactions/freebsd-vm@v0.3.1
|
||||
with:
|
||||
usesh: true
|
||||
# sync: sshfs
|
||||
|
|
201
Cargo.lock
generated
201
Cargo.lock
generated
|
@ -2,12 +2,6 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "Inflector"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
|
@ -43,12 +37,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aliasable"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
|
@ -192,9 +180,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.3.3"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef"
|
||||
checksum = "729b71f35bd3fa1a4c86b85d32c8b9069ea7fe14f7a53cfabb65f62d4265b888"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
|
@ -371,6 +359,28 @@ dependencies = [
|
|||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e"
|
||||
dependencies = [
|
||||
"const-random-macro",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"proc-macro-hack",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.2.4"
|
||||
|
@ -809,9 +819,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "dlv-list"
|
||||
version = "0.3.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
|
||||
checksum = "d529fd73d344663edfd598ccb3f344e46034db51ebd103518eae34338248ad73"
|
||||
dependencies = [
|
||||
"const-random",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dns-lookup"
|
||||
|
@ -956,9 +969,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fundu"
|
||||
version = "0.5.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a37cfff04a32112c22c5497b20b0b09100fca406e76afd47b2ba5ab33d7a851"
|
||||
checksum = "d579dcb632d86591bdd7fc445e705b96cb2a7fb5488d918d956f392b6148e898"
|
||||
dependencies = [
|
||||
"fundu-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fundu-core"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a363b75dd1e4b5bd2cdc305c47399c524cae24638b368b66b1a4c2a36482801f"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
|
@ -1073,9 +1095,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.8"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
@ -1106,6 +1128,12 @@ dependencies = [
|
|||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
|
@ -1154,16 +1182,6 @@ dependencies = [
|
|||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime_to_duration"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a80a233096ddccb74e62145f3a49cacea6a2669ee90f6e144e15fe28f4037c4"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.53"
|
||||
|
@ -1254,9 +1272,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
@ -1319,9 +1337,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.146"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
@ -1405,9 +1423,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
|||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f9ff02d2efdc645fca1ee55f45545b996e7da776b5b60c4e170334457551693"
|
||||
checksum = "180d4b35be83d33392d1d1bfbd2ae1eca7ff5de1a94d3fc87faaa99a069e7cbd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -1472,9 +1490,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "6.0.0"
|
||||
version = "6.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d9ba6c734de18ca27c8cef5cd7058aa4ac9f63596131e4c7e41e579319032a2"
|
||||
checksum = "5738a2795d57ea20abec2d6d76c6081186709c0024187cd5977265eda6598b51"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossbeam-channel",
|
||||
|
@ -1582,12 +1600,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ordered-multimap"
|
||||
version = "0.4.3"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
|
||||
checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e"
|
||||
dependencies = [
|
||||
"dlv-list",
|
||||
"hashbrown",
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1599,29 +1617,6 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ouroboros"
|
||||
version = "0.15.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db"
|
||||
dependencies = [
|
||||
"aliasable",
|
||||
"ouroboros_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ouroboros_macro"
|
||||
version = "0.15.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.3"
|
||||
|
@ -1654,6 +1649,16 @@ dependencies = [
|
|||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse_datetime"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fecceaede7767a9a98058687a321bc91742eff7670167a34104afb30fc8757df"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
|
@ -1662,18 +1667,18 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
|||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_codegen"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
|
||||
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
|
@ -1691,9 +1696,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
|
||||
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
@ -1751,28 +1756,10 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.20+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
|
@ -1973,9 +1960,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
|
||||
checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"ordered-multimap",
|
||||
|
@ -2045,6 +2032,12 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6"
|
||||
|
||||
[[package]]
|
||||
name = "selinux"
|
||||
version = "0.4.0"
|
||||
|
@ -2096,9 +2089,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.6"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
|
@ -2329,6 +2322,15 @@ dependencies = [
|
|||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.15.0"
|
||||
|
@ -2347,7 +2349,7 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
"regex",
|
||||
]
|
||||
|
||||
|
@ -2539,8 +2541,8 @@ version = "0.0.19"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"humantime_to_duration 0.3.1",
|
||||
"libc",
|
||||
"parse_datetime",
|
||||
"uucore",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
@ -2562,6 +2564,7 @@ name = "uu_df"
|
|||
version = "0.0.19"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"tempfile",
|
||||
"unicode-width",
|
||||
"uucore",
|
||||
]
|
||||
|
@ -3098,9 +3101,9 @@ dependencies = [
|
|||
"fnv",
|
||||
"itertools",
|
||||
"memchr",
|
||||
"ouroboros",
|
||||
"rand",
|
||||
"rayon",
|
||||
"self_cell",
|
||||
"tempfile",
|
||||
"unicode-width",
|
||||
"uucore",
|
||||
|
@ -3234,7 +3237,7 @@ version = "0.0.19"
|
|||
dependencies = [
|
||||
"clap",
|
||||
"filetime",
|
||||
"humantime_to_duration 0.2.1",
|
||||
"humantime_to_duration",
|
||||
"time",
|
||||
"uucore",
|
||||
"windows-sys 0.48.0",
|
||||
|
|
24
Cargo.toml
24
Cargo.toml
|
@ -1,7 +1,7 @@
|
|||
# coreutils (uutils)
|
||||
# * see the repository LICENSE, README, and CONTRIBUTING files for more information
|
||||
|
||||
# spell-checker:ignore (libs) libselinux gethostid procfs bigdecimal kqueue fundu mangen humantime uuhelp
|
||||
# spell-checker:ignore (libs) libselinux gethostid procfs bigdecimal kqueue fundu mangen datetime uuhelp
|
||||
|
||||
[package]
|
||||
name = "coreutils"
|
||||
|
@ -280,30 +280,29 @@ filetime = "0.2"
|
|||
fnv = "1.0.7"
|
||||
fs_extra = "1.3.0"
|
||||
fts-sys = "0.2"
|
||||
fundu = "0.5.1"
|
||||
fundu = "1.1.0"
|
||||
gcd = "2.3"
|
||||
glob = "0.3.1"
|
||||
half = "2.2"
|
||||
humantime_to_duration = "0.3.1"
|
||||
indicatif = "0.17"
|
||||
is-terminal = "0.4.7"
|
||||
itertools = "0.10.5"
|
||||
libc = "0.2.146"
|
||||
itertools = "0.11.0"
|
||||
libc = "0.2.147"
|
||||
lscolors = { version = "0.14.0", default-features = false, features = [
|
||||
"nu-ansi-term",
|
||||
] }
|
||||
memchr = "2"
|
||||
nix = { version = "0.26", default-features = false }
|
||||
nom = "7.1.3"
|
||||
notify = { version = "=6.0.0", features = ["macos_kqueue"] }
|
||||
notify = { version = "=6.0.1", features = ["macos_kqueue"] }
|
||||
num-bigint = "0.4.3"
|
||||
num-traits = "0.2.15"
|
||||
number_prefix = "0.4"
|
||||
once_cell = "1.18.0"
|
||||
onig = { version = "~6.4", default-features = false }
|
||||
ouroboros = "0.15.6"
|
||||
phf = "0.11.1"
|
||||
phf_codegen = "0.11.1"
|
||||
parse_datetime = "0.4.0"
|
||||
phf = "0.11.2"
|
||||
phf_codegen = "0.11.2"
|
||||
platform-info = "2.0.1"
|
||||
quick-error = "2.0.1"
|
||||
rand = { version = "0.8", features = ["small_rng"] }
|
||||
|
@ -312,8 +311,9 @@ rayon = "1.7"
|
|||
redox_syscall = "0.3"
|
||||
regex = "1.8.4"
|
||||
rstest = "0.17.0"
|
||||
rust-ini = "0.18.0"
|
||||
rust-ini = "0.19.0"
|
||||
same-file = "1.0.6"
|
||||
self_cell = "1.0.1"
|
||||
selinux = "0.4"
|
||||
signal-hook = "0.3.15"
|
||||
smallvec = { version = "1.10", features = ["union"] }
|
||||
|
@ -335,10 +335,10 @@ zip = { version = "0.6.6", default_features = false, features = ["deflate"] }
|
|||
hex = "0.4.3"
|
||||
md-5 = "0.10.5"
|
||||
sha1 = "0.10.5"
|
||||
sha2 = "0.10.6"
|
||||
sha2 = "0.10.7"
|
||||
sha3 = "0.10.8"
|
||||
blake2b_simd = "1.0.1"
|
||||
blake3 = "1.3.3"
|
||||
blake3 = "1.4.0"
|
||||
sm3 = "0.4.2"
|
||||
digest = "0.10.7"
|
||||
|
||||
|
|
13
deny.toml
13
deny.toml
|
@ -63,23 +63,32 @@ skip = [
|
|||
{ name = "hermit-abi", version = "0.3.1" },
|
||||
# procfs
|
||||
{ name = "rustix", version = "0.36.14" },
|
||||
# rustix
|
||||
{ name = "linux-raw-sys", version = "0.1.4" },
|
||||
# various crates
|
||||
{ name = "windows-sys", version = "0.45.0" },
|
||||
# windows-sys
|
||||
{ name = "windows-targets", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_aarch64_gnullvm", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_aarch64_msvc", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_i686_gnu", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_i686_msvc", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_x86_64_gnu", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_x86_64_gnullvm", version = "0.42.2" },
|
||||
# windows-targets
|
||||
{ name = "windows_x86_64_msvc", version = "0.42.2" },
|
||||
# tempfile
|
||||
{ name = "redox_syscall", version = "0.3.5" },
|
||||
# cpp_macros
|
||||
{ name = "aho-corasick", version = "0.7.19" },
|
||||
# touch, can be remove when touch switches from time to chrono
|
||||
{ name = "humantime_to_duration", version = "0.2.1" },
|
||||
# ordered-multimap (via rust-ini)
|
||||
{ name = "hashbrown", version = "0.13.2" },
|
||||
]
|
||||
# spell-checker: enable
|
||||
|
||||
|
|
|
@ -61,7 +61,11 @@ feature is adopted from [FreeBSD](https://www.freebsd.org/cgi/man.cgi?cut).
|
|||
|
||||
## `fmt`
|
||||
|
||||
`fmt` has additional flags for prefixes: `-P/--skip-prefix`, `-x/--exact-prefix`, and
|
||||
`-X/--exact-skip-prefix`. With `-m/--preserve-headers`, an attempt is made to detect and preserve
|
||||
mail headers in the input. `-q/--quick` breaks lines more quickly. And `-T/--tab-width` defines the
|
||||
`fmt` has additional flags for prefixes: `-P`/`--skip-prefix`, `-x`/`--exact-prefix`, and
|
||||
`-X`/`--exact-skip-prefix`. With `-m`/`--preserve-headers`, an attempt is made to detect and preserve
|
||||
mail headers in the input. `-q`/`--quick` breaks lines more quickly. And `-T`/`--tab-width` defines the
|
||||
number of spaces representing a tab when determining the line length.
|
||||
|
||||
## `seq`
|
||||
|
||||
`seq` provides `-t`/`--terminator` to set the terminator character.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# spell-checker:ignore humantime
|
||||
# spell-checker:ignore datetime
|
||||
[package]
|
||||
name = "uu_date"
|
||||
version = "0.0.19"
|
||||
|
@ -19,7 +19,7 @@ path = "src/date.rs"
|
|||
chrono = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
humantime_to_duration = { workspace = true }
|
||||
parse_datetime = { workspace = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = { workspace = true }
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes humantime
|
||||
// spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes
|
||||
|
||||
use chrono::format::{Item, StrftimeItems};
|
||||
use chrono::{DateTime, Duration, FixedOffset, Local, Offset, Utc};
|
||||
|
@ -170,7 +170,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
};
|
||||
|
||||
let date_source = if let Some(date) = matches.get_one::<String>(OPT_DATE) {
|
||||
if let Ok(duration) = humantime_to_duration::from_str(date.as_str()) {
|
||||
if let Ok(duration) = parse_datetime::from_str(date.as_str()) {
|
||||
DateSource::Human(duration)
|
||||
} else {
|
||||
DateSource::Custom(date.into())
|
||||
|
|
|
@ -36,9 +36,12 @@ use std::os::unix::{
|
|||
io::{AsRawFd, FromRawFd},
|
||||
};
|
||||
use std::path::Path;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering::Relaxed},
|
||||
mpsc, Arc,
|
||||
};
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use clap::{crate_version, Arg, Command};
|
||||
use gcd::Gcd;
|
||||
|
@ -75,6 +78,45 @@ struct Settings {
|
|||
status: Option<StatusLevel>,
|
||||
}
|
||||
|
||||
/// A timer which triggers on a given interval
|
||||
///
|
||||
/// After being constructed with [`Alarm::with_interval`], [`Alarm::is_triggered`]
|
||||
/// will return true once per the given [`Duration`].
|
||||
///
|
||||
/// Can be cloned, but the trigger status is shared across all instances so only
|
||||
/// the first caller each interval will yield true.
|
||||
///
|
||||
/// When all instances are dropped the background thread will exit on the next interval.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Alarm {
|
||||
interval: Duration,
|
||||
trigger: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Alarm {
|
||||
pub fn with_interval(interval: Duration) -> Self {
|
||||
let trigger = Arc::new(AtomicBool::default());
|
||||
|
||||
let weak_trigger = Arc::downgrade(&trigger);
|
||||
thread::spawn(move || {
|
||||
while let Some(trigger) = weak_trigger.upgrade() {
|
||||
thread::sleep(interval);
|
||||
trigger.store(true, Relaxed);
|
||||
}
|
||||
});
|
||||
|
||||
Self { interval, trigger }
|
||||
}
|
||||
|
||||
pub fn is_triggered(&self) -> bool {
|
||||
self.trigger.swap(false, Relaxed)
|
||||
}
|
||||
|
||||
pub fn get_interval(&self) -> Duration {
|
||||
self.interval
|
||||
}
|
||||
}
|
||||
|
||||
/// A number in blocks or bytes
|
||||
///
|
||||
/// Some values (seek, skip, iseek, oseek) can have values either in blocks or in bytes.
|
||||
|
@ -760,7 +802,7 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
|||
// of its report includes the throughput in bytes per second,
|
||||
// which requires knowing how long the process has been
|
||||
// running.
|
||||
let start = time::Instant::now();
|
||||
let start = Instant::now();
|
||||
|
||||
// A good buffer size for reading.
|
||||
//
|
||||
|
@ -780,7 +822,6 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
|||
// information.
|
||||
let (prog_tx, rx) = mpsc::channel();
|
||||
let output_thread = thread::spawn(gen_prog_updater(rx, i.settings.status));
|
||||
let mut progress_as_secs = 0;
|
||||
|
||||
// Optimization: if no blocks are to be written, then don't
|
||||
// bother allocating any buffers.
|
||||
|
@ -813,6 +854,12 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
|||
// This is the max size needed.
|
||||
let mut buf = vec![BUF_INIT_BYTE; bsize];
|
||||
|
||||
// Spawn a timer thread to provide a scheduled signal indicating when we
|
||||
// should send an update of our progress to the reporting thread.
|
||||
//
|
||||
// This avoids the need to query the OS monotonic clock for every block.
|
||||
let alarm = Alarm::with_interval(Duration::from_secs(1));
|
||||
|
||||
// Index in the input file where we are reading bytes and in
|
||||
// the output file where we are writing bytes.
|
||||
//
|
||||
|
@ -871,9 +918,8 @@ fn dd_copy(mut i: Input, mut o: Output) -> std::io::Result<()> {
|
|||
// error.
|
||||
rstat += rstat_update;
|
||||
wstat += wstat_update;
|
||||
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false);
|
||||
if prog_update.duration.as_secs() >= progress_as_secs {
|
||||
progress_as_secs = prog_update.duration.as_secs() + 1;
|
||||
if alarm.is_triggered() {
|
||||
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), false);
|
||||
prog_tx.send(prog_update).unwrap_or(());
|
||||
}
|
||||
}
|
||||
|
@ -885,7 +931,7 @@ fn finalize<T>(
|
|||
output: &mut Output,
|
||||
rstat: ReadStat,
|
||||
wstat: WriteStat,
|
||||
start: time::Instant,
|
||||
start: Instant,
|
||||
prog_tx: &mpsc::Sender<ProgUpdate>,
|
||||
output_thread: thread::JoinHandle<T>,
|
||||
) -> std::io::Result<()> {
|
||||
|
|
|
@ -19,6 +19,9 @@ clap = { workspace = true }
|
|||
uucore = { workspace = true, features = ["libc", "fsext"] }
|
||||
unicode-width = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
||||
[[bin]]
|
||||
name = "df"
|
||||
path = "src/main.rs"
|
||||
|
|
|
@ -42,7 +42,7 @@ pub(crate) struct Filesystem {
|
|||
/// This function returns the element of `mounts` on which `path` is
|
||||
/// mounted. If there are no matches, this function returns
|
||||
/// [`None`]. If there are two or more matches, then the single
|
||||
/// [`MountInfo`] with the longest mount directory is returned.
|
||||
/// [`MountInfo`] with the device name corresponding to the entered path.
|
||||
///
|
||||
/// If `canonicalize` is `true`, then the `path` is canonicalized
|
||||
/// before checking whether it matches any mount directories.
|
||||
|
@ -68,9 +68,19 @@ where
|
|||
path.as_ref().to_path_buf()
|
||||
};
|
||||
|
||||
// Find the potential mount point that matches entered path
|
||||
let maybe_mount_point = mounts
|
||||
.iter()
|
||||
.find(|mi| mi.dev_name.eq(&path.to_string_lossy()));
|
||||
// Create pair MountInfo, canonicalized device name
|
||||
// TODO Abstract from accessing real filesystem to
|
||||
// make code more testable
|
||||
.map(|m| (m, std::fs::canonicalize(&m.dev_name)))
|
||||
// Ignore non existing paths
|
||||
.filter(|m| m.1.is_ok())
|
||||
.map(|m| (m.0, m.1.ok().unwrap()))
|
||||
// Try to find canonicalized device name corresponding to entered path
|
||||
.find(|m| m.1.eq(&path))
|
||||
.map(|m| m.0);
|
||||
|
||||
maybe_mount_point.or_else(|| {
|
||||
mounts
|
||||
|
@ -211,10 +221,16 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_dev_name_match() {
|
||||
let tmp = tempfile::TempDir::new().expect("Failed to create temp dir");
|
||||
let dev_name = std::fs::canonicalize(tmp.path())
|
||||
.expect("Failed to canonicalize tmp path")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
let mut mount_info = mount_info("/foo");
|
||||
mount_info.dev_name = "/dev/sda2".to_string();
|
||||
mount_info.dev_name = dev_name.clone();
|
||||
let mounts = [mount_info];
|
||||
let actual = mount_info_from_path(&mounts, "/dev/sda2", false).unwrap();
|
||||
let actual = mount_info_from_path(&mounts, dev_name, false).unwrap();
|
||||
assert!(mount_info_eq(actual, &mounts[0]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ impl Stat {
|
|||
return Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
is_dir: metadata.is_dir(),
|
||||
size: metadata.len(),
|
||||
size: if path.is_dir() { 0 } else { metadata.len() },
|
||||
blocks: metadata.blocks(),
|
||||
inodes: 1,
|
||||
inode: Some(file_info),
|
||||
|
@ -162,7 +162,7 @@ impl Stat {
|
|||
Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
is_dir: metadata.is_dir(),
|
||||
size: metadata.len(),
|
||||
size: if path.is_dir() { 0 } else { metadata.len() },
|
||||
blocks: size_on_disk / 1024 * 2,
|
||||
inode: file_info,
|
||||
inodes: 1,
|
||||
|
|
|
@ -25,7 +25,7 @@ use std::path::{Path, PathBuf};
|
|||
use uucore::backup_control::{self, BackupMode};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{set_exit_code, FromIo, UError, UResult, USimpleError, UUsageError};
|
||||
use uucore::fs::are_hardlinks_to_same_file;
|
||||
use uucore::fs::{are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file};
|
||||
use uucore::update_control::{self, UpdateMode};
|
||||
use uucore::{format_usage, help_about, help_section, help_usage, prompt_yes, show};
|
||||
|
||||
|
@ -255,8 +255,10 @@ fn handle_two_paths(source: &Path, target: &Path, b: &Behavior) -> UResult<()> {
|
|||
return Err(MvError::NoSuchFile(source.quote().to_string()).into());
|
||||
}
|
||||
|
||||
if (source.eq(target) || are_hardlinks_to_same_file(source, target))
|
||||
&& b.backup != BackupMode::SimpleBackup
|
||||
if (source.eq(target)
|
||||
|| are_hardlinks_to_same_file(source, target)
|
||||
|| are_hardlinks_or_one_way_symlink_to_same_file(source, target))
|
||||
&& b.backup == BackupMode::NoBackup
|
||||
{
|
||||
if source.eq(Path::new(".")) || source.ends_with("/.") || source.is_file() {
|
||||
return Err(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#nl
|
||||
# nl
|
||||
|
||||
```
|
||||
nl [OPTION]... [FILE]...
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
// * file that was distributed with this source code.
|
||||
// *
|
||||
|
||||
// spell-checker:ignore (ToDO) corasick memchr
|
||||
|
||||
use clap::{crate_version, Arg, ArgAction, Command};
|
||||
use std::fs::File;
|
||||
use std::io::{stdin, BufRead, BufReader, Read};
|
||||
|
@ -18,8 +16,8 @@ use uucore::{format_usage, help_about, help_usage};
|
|||
|
||||
mod helper;
|
||||
|
||||
static ABOUT: &str = help_about!("nl.md");
|
||||
static USAGE: &str = help_usage!("nl.md");
|
||||
const ABOUT: &str = help_about!("nl.md");
|
||||
const USAGE: &str = help_usage!("nl.md");
|
||||
|
||||
// Settings store options used by nl to produce its output.
|
||||
pub struct Settings {
|
||||
|
@ -42,6 +40,24 @@ pub struct Settings {
|
|||
number_separator: String,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
header_numbering: NumberingStyle::NumberForNone,
|
||||
body_numbering: NumberingStyle::NumberForAll,
|
||||
footer_numbering: NumberingStyle::NumberForNone,
|
||||
section_delimiter: ['\\', ':'],
|
||||
starting_line_number: 1,
|
||||
line_increment: 1,
|
||||
join_blank_lines: 1,
|
||||
number_width: 6,
|
||||
number_format: NumberFormat::Right,
|
||||
renumber: true,
|
||||
number_separator: String::from("\t"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NumberingStyle stores which lines are to be numbered.
|
||||
// The possible options are:
|
||||
// 1. Number all lines
|
||||
|
@ -87,20 +103,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
|
||||
let matches = uu_app().try_get_matches_from(args)?;
|
||||
|
||||
// A mutable settings object, initialized with the defaults.
|
||||
let mut settings = Settings {
|
||||
header_numbering: NumberingStyle::NumberForNone,
|
||||
body_numbering: NumberingStyle::NumberForAll,
|
||||
footer_numbering: NumberingStyle::NumberForNone,
|
||||
section_delimiter: ['\\', ':'],
|
||||
starting_line_number: 1,
|
||||
line_increment: 1,
|
||||
join_blank_lines: 1,
|
||||
number_width: 6,
|
||||
number_format: NumberFormat::Right,
|
||||
renumber: true,
|
||||
number_separator: String::from("\t"),
|
||||
};
|
||||
let mut settings = Settings::default();
|
||||
|
||||
// Update the settings from the command line options, and terminate the
|
||||
// program if some options could not successfully be parsed.
|
||||
|
|
|
@ -43,7 +43,7 @@ pub fn parse_number_of_bytes(s: &str) -> Result<u64, ParseSizeError> {
|
|||
len -= 1;
|
||||
}
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
Some('E') => {
|
||||
Some('E') if radix != 16 => {
|
||||
multiply = 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
|
||||
len -= 1;
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ fn test_parse_number_of_bytes() {
|
|||
|
||||
// hex input
|
||||
assert_eq!(15, parse_number_of_bytes("0xf").unwrap());
|
||||
assert_eq!(14, parse_number_of_bytes("0XE").unwrap());
|
||||
assert_eq!(15, parse_number_of_bytes("0XF").unwrap());
|
||||
assert_eq!(27, parse_number_of_bytes("0x1b").unwrap());
|
||||
assert_eq!(16 * 1024, parse_number_of_bytes("0x10k").unwrap());
|
||||
|
|
|
@ -5,5 +5,5 @@ Display numbers from FIRST to LAST, in steps of INCREMENT.
|
|||
```
|
||||
seq [OPTION]... LAST
|
||||
seq [OPTION]... FIRST LAST
|
||||
seq [OPTION]... FIRST INCREMENT LAST";
|
||||
seq [OPTION]... FIRST INCREMENT LAST
|
||||
```
|
||||
|
|
|
@ -532,7 +532,9 @@ fn wipe_name(orig_path: &Path, verbose: bool) -> Option<PathBuf> {
|
|||
}
|
||||
|
||||
// Sync every file rename
|
||||
let new_file = File::open(new_path.clone())
|
||||
let new_file = OpenOptions::new()
|
||||
.write(true)
|
||||
.open(new_path.clone())
|
||||
.expect("Failed to open renamed file for syncing");
|
||||
new_file.sync_all().expect("Failed to sync renamed file");
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ use uucore::{
|
|||
};
|
||||
|
||||
use clap::{crate_version, Arg, ArgAction, Command};
|
||||
use fundu::{self, DurationParser, ParseError};
|
||||
use fundu::{self, DurationParser, ParseError, SaturatingInto};
|
||||
|
||||
static ABOUT: &str = help_about!("sleep.md");
|
||||
const USAGE: &str = help_usage!("sleep.md");
|
||||
|
@ -63,7 +63,7 @@ pub fn uu_app() -> Command {
|
|||
fn sleep(args: &[&str]) -> UResult<()> {
|
||||
let mut arg_error = false;
|
||||
|
||||
use fundu::TimeUnit::*;
|
||||
use fundu::TimeUnit::{Day, Hour, Minute, Second};
|
||||
let parser = DurationParser::with_time_units(&[Second, Minute, Hour, Day]);
|
||||
|
||||
let sleep_dur = args
|
||||
|
@ -91,7 +91,9 @@ fn sleep(args: &[&str]) -> UResult<()> {
|
|||
None
|
||||
}
|
||||
})
|
||||
.fold(Duration::ZERO, |acc, n| acc.saturating_add(n));
|
||||
.fold(Duration::ZERO, |acc, n| {
|
||||
acc.saturating_add(SaturatingInto::<std::time::Duration>::saturating_into(n))
|
||||
});
|
||||
|
||||
if arg_error {
|
||||
return Err(UUsageError::new(1, ""));
|
||||
|
|
|
@ -22,9 +22,9 @@ ctrlc = { workspace = true }
|
|||
fnv = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
ouroboros = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
self_cell = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
uucore = { workspace = true, features = ["fs"] }
|
||||
|
|
|
@ -16,21 +16,22 @@ use std::{
|
|||
};
|
||||
|
||||
use memchr::memchr_iter;
|
||||
use ouroboros::self_referencing;
|
||||
use self_cell::self_cell;
|
||||
use uucore::error::{UResult, USimpleError};
|
||||
|
||||
use crate::{numeric_str_cmp::NumInfo, GeneralF64ParseResult, GlobalSettings, Line, SortError};
|
||||
|
||||
/// The chunk that is passed around between threads.
|
||||
/// `lines` consist of slices into `buffer`.
|
||||
#[self_referencing(pub_extras)]
|
||||
#[derive(Debug)]
|
||||
pub struct Chunk {
|
||||
pub buffer: Vec<u8>,
|
||||
#[borrows(buffer)]
|
||||
#[covariant]
|
||||
pub contents: ChunkContents<'this>,
|
||||
}
|
||||
self_cell!(
|
||||
/// The chunk that is passed around between threads.
|
||||
pub struct Chunk {
|
||||
owner: Vec<u8>,
|
||||
|
||||
#[covariant]
|
||||
dependent: ChunkContents,
|
||||
}
|
||||
|
||||
impl {Debug}
|
||||
);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChunkContents<'a> {
|
||||
|
@ -48,7 +49,7 @@ pub struct LineData<'a> {
|
|||
impl Chunk {
|
||||
/// Destroy this chunk and return its components to be reused.
|
||||
pub fn recycle(mut self) -> RecycledChunk {
|
||||
let recycled_contents = self.with_contents_mut(|contents| {
|
||||
let recycled_contents = self.with_dependent_mut(|_, contents| {
|
||||
contents.lines.clear();
|
||||
contents.line_data.selections.clear();
|
||||
contents.line_data.num_infos.clear();
|
||||
|
@ -81,15 +82,15 @@ impl Chunk {
|
|||
selections: recycled_contents.1,
|
||||
num_infos: recycled_contents.2,
|
||||
parsed_floats: recycled_contents.3,
|
||||
buffer: self.into_heads().buffer,
|
||||
buffer: self.into_owner(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lines(&self) -> &Vec<Line> {
|
||||
&self.borrow_contents().lines
|
||||
&self.borrow_dependent().lines
|
||||
}
|
||||
pub fn line_data(&self) -> &LineData {
|
||||
&self.borrow_contents().line_data
|
||||
&self.borrow_dependent().line_data
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ fn reader_writer<
|
|||
/// The function that is executed on the sorter thread.
|
||||
fn sorter(receiver: &Receiver<Chunk>, sender: &SyncSender<Chunk>, settings: &GlobalSettings) {
|
||||
while let Ok(mut payload) = receiver.recv() {
|
||||
payload.with_contents_mut(|contents| {
|
||||
payload.with_dependent_mut(|_, contents| {
|
||||
sort_by(&mut contents.lines, settings, &contents.line_data);
|
||||
});
|
||||
if sender.send(payload).is_err() {
|
||||
|
|
|
@ -288,7 +288,7 @@ impl<'a> FileMerger<'a> {
|
|||
file_number: file.file_number,
|
||||
});
|
||||
|
||||
file.current_chunk.with_contents(|contents| {
|
||||
file.current_chunk.with_dependent(|_, contents| {
|
||||
let current_line = &contents.lines[file.line_idx];
|
||||
if settings.unique {
|
||||
if let Some(prev) = &prev {
|
||||
|
|
|
@ -173,7 +173,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let path = Path::new(&f);
|
||||
if let Err(e) = open(path, OFlag::O_NONBLOCK, Mode::empty()) {
|
||||
if e != Errno::EACCES || (e == Errno::EACCES && path.is_dir()) {
|
||||
return e.map_err_context(|| format!("cannot stat {}", f.quote()))?;
|
||||
return e.map_err_context(|| format!("error opening {}", f.quote()))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if !Path::new(&f).exists() {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("cannot stat {}: No such file or directory", f.quote()),
|
||||
format!("error opening {}: No such file or directory", f.quote()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ path = "src/tac.rs"
|
|||
|
||||
[dependencies]
|
||||
memchr = { workspace = true }
|
||||
memmap2 = "0.6"
|
||||
memmap2 = "0.7"
|
||||
regex = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::paths::Input;
|
|||
use crate::{parse, platform, Quotable};
|
||||
use clap::crate_version;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use fundu::DurationParser;
|
||||
use fundu::{DurationParser, SaturatingInto};
|
||||
use is_terminal::IsTerminal;
|
||||
use same_file::Handle;
|
||||
use std::collections::VecDeque;
|
||||
|
@ -235,12 +235,15 @@ impl Settings {
|
|||
// `DURATION::MAX` or `infinity` was given
|
||||
// * not applied here but it supports customizable time units and provides better error
|
||||
// messages
|
||||
settings.sleep_sec =
|
||||
DurationParser::without_time_units()
|
||||
.parse(source)
|
||||
.map_err(|_| {
|
||||
UUsageError::new(1, format!("invalid number of seconds: '{source}'"))
|
||||
})?;
|
||||
settings.sleep_sec = match DurationParser::without_time_units().parse(source) {
|
||||
Ok(duration) => SaturatingInto::<std::time::Duration>::saturating_into(duration),
|
||||
Err(_) => {
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
format!("invalid number of seconds: '{source}'"),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(s) = matches.get_one::<String>(options::MAX_UNCHANGED_STATS) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// For the full copyright and license information, please view the LICENSE file
|
||||
// that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm clapv PWSTR lpszfilepath hresult mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME YYYYMMDDHHMMS subsecond humantime
|
||||
// spell-checker:ignore (ToDO) filetime datetime MMDDhhmm lpszfilepath mktime YYYYMMDDHHMM YYMMDDHHMM DATETIME YYYYMMDDHHMMS subsecond humantime
|
||||
|
||||
use clap::builder::ValueParser;
|
||||
use clap::{crate_version, Arg, ArgAction, ArgGroup, Command};
|
||||
|
@ -29,7 +29,7 @@ pub mod options {
|
|||
pub mod sources {
|
||||
pub static DATE: &str = "date";
|
||||
pub static REFERENCE: &str = "reference";
|
||||
pub static CURRENT: &str = "current";
|
||||
pub static TIMESTAMP: &str = "timestamp";
|
||||
}
|
||||
pub static HELP: &str = "help";
|
||||
pub static ACCESS: &str = "access";
|
||||
|
@ -120,12 +120,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
(timestamp, timestamp)
|
||||
}
|
||||
(None, None) => {
|
||||
let timestamp =
|
||||
if let Some(current) = matches.get_one::<String>(options::sources::CURRENT) {
|
||||
parse_timestamp(current)?
|
||||
} else {
|
||||
local_dt_to_filetime(time::OffsetDateTime::now_local().unwrap())
|
||||
};
|
||||
let timestamp = if let Some(ts) = matches.get_one::<String>(options::sources::TIMESTAMP)
|
||||
{
|
||||
parse_timestamp(ts)?
|
||||
} else {
|
||||
local_dt_to_filetime(time::OffsetDateTime::now_local().unwrap())
|
||||
};
|
||||
(timestamp, timestamp)
|
||||
}
|
||||
};
|
||||
|
@ -243,7 +243,7 @@ pub fn uu_app() -> Command {
|
|||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::sources::CURRENT)
|
||||
Arg::new(options::sources::TIMESTAMP)
|
||||
.short('t')
|
||||
.help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
|
||||
.value_name("STAMP"),
|
||||
|
@ -255,7 +255,7 @@ pub fn uu_app() -> Command {
|
|||
.allow_hyphen_values(true)
|
||||
.help("parse argument and use it instead of current time")
|
||||
.value_name("STRING")
|
||||
.conflicts_with(options::sources::CURRENT),
|
||||
.conflicts_with(options::sources::TIMESTAMP),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::MODIFICATION)
|
||||
|
@ -288,7 +288,7 @@ pub fn uu_app() -> Command {
|
|||
.value_name("FILE")
|
||||
.value_parser(ValueParser::os_string())
|
||||
.value_hint(clap::ValueHint::AnyPath)
|
||||
.conflicts_with(options::sources::CURRENT),
|
||||
.conflicts_with(options::sources::TIMESTAMP),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::TIME)
|
||||
|
@ -311,7 +311,7 @@ pub fn uu_app() -> Command {
|
|||
.group(
|
||||
ArgGroup::new(options::SOURCES)
|
||||
.args([
|
||||
options::sources::CURRENT,
|
||||
options::sources::TIMESTAMP,
|
||||
options::sources::DATE,
|
||||
options::sources::REFERENCE,
|
||||
])
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
// cSpell:ignore strs
|
||||
|
||||
use clap::{builder::ValueParser, Arg, ArgAction, Command};
|
||||
use clap::{builder::ValueParser, crate_version, Arg, ArgAction, Command};
|
||||
use std::error::Error;
|
||||
use std::ffi::OsString;
|
||||
use std::io::{self, Write};
|
||||
|
@ -44,6 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
|
||||
pub fn uu_app() -> Command {
|
||||
Command::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.arg(
|
||||
|
|
|
@ -25,7 +25,7 @@ dunce = "1.0.4"
|
|||
wild = "2.1"
|
||||
glob = "0.3.1"
|
||||
# * optional
|
||||
itertools = { version = "0.10.5", optional = true }
|
||||
itertools = { version = "0.11.0", optional = true }
|
||||
thiserror = { workspace = true, optional = true }
|
||||
time = { workspace = true, optional = true, features = [
|
||||
"formatting",
|
||||
|
@ -36,7 +36,7 @@ time = { workspace = true, optional = true, features = [
|
|||
data-encoding = { version = "2.4", optional = true }
|
||||
data-encoding-macro = { version = "0.1.13", optional = true }
|
||||
z85 = { version = "3.0.5", optional = true }
|
||||
libc = { version = "0.2.146", optional = true }
|
||||
libc = { version = "0.2.147", optional = true }
|
||||
once_cell = { workspace = true }
|
||||
os_display = "0.1.3"
|
||||
|
||||
|
|
|
@ -635,12 +635,42 @@ pub fn are_hardlinks_to_same_file(_source: &Path, _target: &Path) -> bool {
|
|||
/// * `bool` - Returns `true` if the paths are hard links to the same file, and `false` otherwise.
|
||||
#[cfg(unix)]
|
||||
pub fn are_hardlinks_to_same_file(source: &Path, target: &Path) -> bool {
|
||||
let source_metadata = match fs::symlink_metadata(source) {
|
||||
Ok(metadata) => metadata,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
let target_metadata = match fs::symlink_metadata(target) {
|
||||
Ok(metadata) => metadata,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
source_metadata.ino() == target_metadata.ino() && source_metadata.dev() == target_metadata.dev()
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
pub fn are_hardlinks_or_one_way_symlink_to_same_file(_source: &Path, _target: &Path) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks if either two paths are hard links to the same file or if the source path is a symbolic link which when fully resolved points to target path
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `source` - A reference to a `Path` representing the source path.
|
||||
/// * `target` - A reference to a `Path` representing the target path.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `bool` - Returns `true` if either of above conditions are true, and `false` otherwise.
|
||||
#[cfg(unix)]
|
||||
pub fn are_hardlinks_or_one_way_symlink_to_same_file(source: &Path, target: &Path) -> bool {
|
||||
let source_metadata = match fs::metadata(source) {
|
||||
Ok(metadata) => metadata,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
let target_metadata = match fs::metadata(target) {
|
||||
let target_metadata = match fs::symlink_metadata(target) {
|
||||
Ok(metadata) => metadata,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
|
|
@ -396,7 +396,7 @@ impl Display for UIoError {
|
|||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
use std::io::ErrorKind::*;
|
||||
|
||||
let mut message;
|
||||
let message;
|
||||
let message = if self.inner.raw_os_error().is_some() {
|
||||
// These are errors that come directly from the OS.
|
||||
// We want to normalize their messages across systems,
|
||||
|
@ -424,7 +424,6 @@ impl Display for UIoError {
|
|||
// (https://github.com/rust-lang/rust/issues/86442)
|
||||
// are stabilized, we should add them to the match statement.
|
||||
message = strip_errno(&self.inner);
|
||||
capitalize(&mut message);
|
||||
&message
|
||||
}
|
||||
}
|
||||
|
@ -435,7 +434,6 @@ impl Display for UIoError {
|
|||
// a file that was not found.
|
||||
// There are also errors with entirely custom messages.
|
||||
message = self.inner.to_string();
|
||||
capitalize(&mut message);
|
||||
&message
|
||||
};
|
||||
if let Some(ctx) = &self.context {
|
||||
|
@ -446,13 +444,6 @@ impl Display for UIoError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Capitalize the first character of an ASCII string.
|
||||
fn capitalize(text: &mut str) {
|
||||
if let Some(first) = text.get_mut(..1) {
|
||||
first.make_ascii_uppercase();
|
||||
}
|
||||
}
|
||||
|
||||
/// Strip the trailing " (os error XX)" from io error strings.
|
||||
pub fn strip_errno(err: &std::io::Error) -> String {
|
||||
let mut msg = err.to_string();
|
||||
|
|
|
@ -2724,7 +2724,7 @@ fn test_copy_dir_preserve_permissions_inaccessible_file() {
|
|||
ucmd.args(&["-p", "-R", "d1", "d2"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only("cp: cannot open 'd1/f' for reading: Permission denied\n");
|
||||
.stderr_only("cp: cannot open 'd1/f' for reading: permission denied\n");
|
||||
assert!(at.dir_exists("d2"));
|
||||
assert!(!at.file_exists("d2/f"));
|
||||
|
||||
|
|
|
@ -580,97 +580,58 @@ fn test_du_invalid_threshold() {
|
|||
|
||||
#[test]
|
||||
fn test_du_apparent_size() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let result = ts.ucmd().arg("--apparent-size").succeeds();
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
at.mkdir_all("a/b");
|
||||
|
||||
at.write("a/b/file1", "foo");
|
||||
at.write("a/b/file2", "foobar");
|
||||
|
||||
let result = ucmd.args(&["--apparent-size", "--all", "a"]).succeeds();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let result_reference = unwrap_or_return!(expected_result(&ts, &["--apparent-size"]));
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
result.stdout_contains_line("1\ta/b/file2");
|
||||
result.stdout_contains_line("1\ta/b/file1");
|
||||
result.stdout_contains_line("1\ta/b");
|
||||
result.stdout_contains_line("1\ta");
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
_du_apparent_size(result.stdout_str());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn _du_apparent_size(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"1\t.\\subdir\\deeper\\deeper_dir
|
||||
1\t.\\subdir\\deeper
|
||||
6\t.\\subdir\\links
|
||||
6\t.\\subdir
|
||||
6\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
#[cfg(target_vendor = "apple")]
|
||||
fn _du_apparent_size(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"1\t./subdir/deeper/deeper_dir
|
||||
1\t./subdir/deeper
|
||||
6\t./subdir/links
|
||||
6\t./subdir
|
||||
6\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn _du_apparent_size(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"1\t./subdir/deeper/deeper_dir
|
||||
2\t./subdir/deeper
|
||||
6\t./subdir/links
|
||||
8\t./subdir
|
||||
8\t.
|
||||
"
|
||||
);
|
||||
}
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd")
|
||||
))]
|
||||
fn _du_apparent_size(s: &str) {
|
||||
assert_eq!(
|
||||
s,
|
||||
"5\t./subdir/deeper/deeper_dir
|
||||
9\t./subdir/deeper
|
||||
10\t./subdir/links
|
||||
22\t./subdir
|
||||
26\t.
|
||||
"
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
result.stdout_contains_line("1\ta\\b\\file2");
|
||||
result.stdout_contains_line("1\ta\\b\\file1");
|
||||
result.stdout_contains_line("1\ta\\b");
|
||||
result.stdout_contains_line("1\ta");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_bytes() {
|
||||
let ts = TestScenario::new(util_name!());
|
||||
let result = ts.ucmd().arg("--bytes").succeeds();
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
at.mkdir_all("a/b");
|
||||
|
||||
at.write("a/b/file1", "foo");
|
||||
at.write("a/b/file2", "foobar");
|
||||
|
||||
let result = ucmd.args(&["--bytes", "--all", "a"]).succeeds();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let result_reference = unwrap_or_return!(expected_result(&ts, &["--bytes"]));
|
||||
assert_eq!(result.stdout_str(), result_reference.stdout_str());
|
||||
result.stdout_contains_line("6\ta/b/file2");
|
||||
result.stdout_contains_line("3\ta/b/file1");
|
||||
result.stdout_contains_line("9\ta/b");
|
||||
result.stdout_contains_line("9\ta");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
result.stdout_contains("5145\t.\\subdir\n");
|
||||
#[cfg(target_vendor = "apple")]
|
||||
result.stdout_contains("5625\t./subdir\n");
|
||||
#[cfg(target_os = "freebsd")]
|
||||
result.stdout_contains("7193\t./subdir\n");
|
||||
#[cfg(all(
|
||||
not(target_vendor = "apple"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "freebsd"),
|
||||
not(target_os = "linux"),
|
||||
not(target_os = "android"),
|
||||
))]
|
||||
result.stdout_contains("21529\t./subdir\n");
|
||||
{
|
||||
result.stdout_contains_line("6\ta\\b\\file2");
|
||||
result.stdout_contains_line("3\ta\\b\\file1");
|
||||
result.stdout_contains_line("9\ta\\b");
|
||||
result.stdout_contains_line("9\ta");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -417,6 +417,83 @@ fn test_mv_same_hardlink() {
|
|||
.stderr_is(format!("mv: '{file_a}' and '{file_b}' are the same file\n",));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
fn test_mv_same_symlink() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file_a = "test_mv_same_file_a";
|
||||
let file_b = "test_mv_same_file_b";
|
||||
let file_c = "test_mv_same_file_c";
|
||||
|
||||
at.touch(file_a);
|
||||
|
||||
at.symlink_file(file_a, file_b);
|
||||
|
||||
ucmd.arg(file_b)
|
||||
.arg(file_a)
|
||||
.fails()
|
||||
.stderr_is(format!("mv: '{file_b}' and '{file_a}' are the same file\n",));
|
||||
|
||||
let (at2, mut ucmd2) = at_and_ucmd!();
|
||||
at2.touch(file_a);
|
||||
|
||||
at2.symlink_file(file_a, file_b);
|
||||
ucmd2.arg(file_a).arg(file_b).succeeds();
|
||||
assert!(at2.file_exists(file_b));
|
||||
assert!(!at2.file_exists(file_a));
|
||||
|
||||
let (at3, mut ucmd3) = at_and_ucmd!();
|
||||
at3.touch(file_a);
|
||||
|
||||
at3.symlink_file(file_a, file_b);
|
||||
at3.symlink_file(file_b, file_c);
|
||||
|
||||
ucmd3.arg(file_c).arg(file_b).succeeds();
|
||||
assert!(!at3.symlink_exists(file_c));
|
||||
assert!(at3.symlink_exists(file_b));
|
||||
|
||||
let (at4, mut ucmd4) = at_and_ucmd!();
|
||||
at4.touch(file_a);
|
||||
|
||||
at4.symlink_file(file_a, file_b);
|
||||
at4.symlink_file(file_b, file_c);
|
||||
|
||||
ucmd4
|
||||
.arg(file_c)
|
||||
.arg(file_a)
|
||||
.fails()
|
||||
.stderr_is(format!("mv: '{file_c}' and '{file_a}' are the same file\n",));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
fn test_mv_hardlink_to_symlink() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file = "file";
|
||||
let symlink_file = "symlink";
|
||||
let hardlink_to_symlink_file = "hardlink_to_symlink";
|
||||
|
||||
at.touch(file);
|
||||
at.symlink_file(file, symlink_file);
|
||||
at.hard_link(symlink_file, hardlink_to_symlink_file);
|
||||
|
||||
ucmd.arg(symlink_file).arg(hardlink_to_symlink_file).fails();
|
||||
|
||||
let (at2, mut ucmd2) = at_and_ucmd!();
|
||||
|
||||
at2.touch(file);
|
||||
at2.symlink_file(file, symlink_file);
|
||||
at2.hard_link(symlink_file, hardlink_to_symlink_file);
|
||||
|
||||
ucmd2
|
||||
.arg("--backup")
|
||||
.arg(symlink_file)
|
||||
.arg(hardlink_to_symlink_file)
|
||||
.succeeds();
|
||||
assert!(!at2.symlink_exists(symlink_file));
|
||||
assert!(at2.symlink_exists(&format!("{hardlink_to_symlink_file}~")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
fn test_mv_same_hardlink_backup_simple() {
|
||||
|
|
|
@ -627,6 +627,35 @@ fn test_skip_bytes() {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skip_bytes_hex() {
|
||||
let input = "abcdefghijklmnopq"; // spell-checker:disable-line
|
||||
new_ucmd!()
|
||||
.arg("-c")
|
||||
.arg("--skip-bytes=0xB")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
"
|
||||
0000013 l m n o p q
|
||||
0000021
|
||||
",
|
||||
));
|
||||
new_ucmd!()
|
||||
.arg("-c")
|
||||
.arg("--skip-bytes=0xE")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
"
|
||||
0000016 o p q
|
||||
0000021
|
||||
",
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skip_bytes_error() {
|
||||
let input = "12345";
|
||||
|
|
|
@ -18,7 +18,7 @@ fn test_shred_remove() {
|
|||
at.touch(file_b);
|
||||
|
||||
// Shred file_a.
|
||||
scene.ucmd().arg("-u").arg(file_a).run();
|
||||
scene.ucmd().arg("-u").arg(file_a).succeeds();
|
||||
|
||||
// file_a was deleted, file_b exists.
|
||||
assert!(!at.file_exists(file_a));
|
||||
|
|
|
@ -41,7 +41,7 @@ fn test_sync_no_existing_files() {
|
|||
.arg("--data")
|
||||
.arg("do-no-exist")
|
||||
.fails()
|
||||
.stderr_contains("cannot stat");
|
||||
.stderr_contains("error opening");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -63,9 +63,9 @@ fn test_sync_no_permission_dir() {
|
|||
|
||||
ts.ccmd("chmod").arg("0").arg(dir).succeeds();
|
||||
let result = ts.ucmd().arg("--data").arg(dir).fails();
|
||||
result.stderr_contains("sync: cannot stat 'foo': Permission denied");
|
||||
result.stderr_contains("sync: error opening 'foo': Permission denied");
|
||||
let result = ts.ucmd().arg(dir).fails();
|
||||
result.stderr_contains("sync: cannot stat 'foo': Permission denied");
|
||||
result.stderr_contains("sync: error opening 'foo': Permission denied");
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
|
|
|
@ -35,6 +35,11 @@ fn test_invalid_arg() {
|
|||
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version() {
|
||||
new_ucmd!().arg("--version").succeeds();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple() {
|
||||
run(NO_ARGS, b"y\ny\ny\ny\n");
|
||||
|
|
|
@ -659,6 +659,17 @@ impl CmdResult {
|
|||
self
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn stdout_contains_line<T: AsRef<str>>(&self, cmp: T) -> &Self {
|
||||
assert!(
|
||||
self.stdout_str().lines().any(|line| line == cmp.as_ref()),
|
||||
"'{}' does not contain line '{}'",
|
||||
self.stdout_str(),
|
||||
cmp.as_ref()
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn stderr_contains<T: AsRef<str>>(&self, cmp: T) -> &Self {
|
||||
assert!(
|
||||
|
|
|
@ -232,3 +232,8 @@ sed -i -e "s/Try 'mv --help' for more information/For more information, try '--h
|
|||
sed -i -E "s|^([^#]*2_31.*)$|#\1|g" tests/misc/printf-cov.pl
|
||||
|
||||
sed -i -e "s/du: invalid -t argument/du: invalid --threshold argument/" -e "s/du: option requires an argument/error: a value is required for '--threshold <SIZE>' but none was supplied/" -e "/Try 'du --help' for more information./d" tests/du/threshold.sh
|
||||
|
||||
# disable two kind of tests:
|
||||
# "hostid BEFORE --help" doesn't fail for GNU. we fail. we are probably doing better
|
||||
# "hostid BEFORE --help AFTER " same for this
|
||||
sed -i -e "s/env \$prog \$BEFORE \$opt > out2/env \$prog \$BEFORE \$opt > out2 #/" -e "s/env \$prog \$BEFORE \$opt AFTER > out3/env \$prog \$BEFORE \$opt AFTER > out3 #/" -e "s/compare exp out2/compare exp out2 #/" -e "s/compare exp out3/compare exp out3 #/" tests/misc/help-version-getopt.sh
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue