mirror of
https://github.com/uutils/coreutils.git
synced 2025-08-04 19:08:35 +00:00
Merge branch 'uutils:main' into cp_permissions
This commit is contained in:
commit
aab575327a
259 changed files with 9533 additions and 3172 deletions
|
@ -4,9 +4,9 @@ linker = "x86_64-unknown-redox-gcc"
|
|||
[env]
|
||||
PROJECT_NAME_FOR_VERSION_STRING = "uutils coreutils"
|
||||
# See feat_external_libstdbuf in src/uu/stdbuf/Cargo.toml
|
||||
LIBSTDBUF_DIR = "/usr/lib"
|
||||
LIBSTDBUF_DIR = "/usr/local/libexec/coreutils"
|
||||
|
||||
# libstdbuf must be a shared library, so musl libc can't be linked statically
|
||||
# https://github.com/rust-lang/rust/issues/82193
|
||||
[build]
|
||||
rustflags = [ "-C", "target-feature=-crt-static" ]
|
||||
rustflags = ["-C", "target-feature=-crt-static"]
|
||||
|
|
28
.github/fluent_linter_config.yml
vendored
Normal file
28
.github/fluent_linter_config.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
ID01:
|
||||
enabled: true
|
||||
exclusions:
|
||||
messages: []
|
||||
files: []
|
||||
ID02:
|
||||
enabled: true
|
||||
min_length: 7
|
||||
VC:
|
||||
disabled: true
|
||||
# Disable: # TE01: single quote instead of apostrophe for genitive (foo's)
|
||||
TE01:
|
||||
enabled: false
|
||||
# TE03: single quotes ('foo')
|
||||
TE03:
|
||||
enabled: false
|
||||
# TE04: Double-quoted strings should use Unicode " instead of "foo".
|
||||
TE04:
|
||||
enabled: false
|
||||
# Disable: TE05: 3 dots for ellipsis ("...")
|
||||
TE05:
|
||||
enabled: false
|
||||
# Should be fixed
|
||||
VC01:
|
||||
disabled: true
|
||||
ID03:
|
||||
enabled: true
|
1
.github/workflows/GnuTests.yml
vendored
1
.github/workflows/GnuTests.yml
vendored
|
@ -166,6 +166,7 @@ jobs:
|
|||
sudo locale-gen --keep-existing sv_SE
|
||||
sudo locale-gen --keep-existing sv_SE.UTF-8
|
||||
sudo locale-gen --keep-existing en_US
|
||||
sudo locale-gen --keep-existing en_US.UTF-8
|
||||
sudo locale-gen --keep-existing ru_RU.KOI8-R
|
||||
|
||||
sudo update-locale
|
||||
|
|
|
@ -19,10 +19,12 @@ repos:
|
|||
args: [ --fix=lf ]
|
||||
- id: trailing-whitespace
|
||||
|
||||
- repo: https://github.com/uutils/pre-commit-fluent-hook
|
||||
rev: v0.0.1
|
||||
- repo: https://github.com/mozilla-l10n/moz-fluent-linter
|
||||
rev: v0.4.8
|
||||
hooks:
|
||||
- id: check-fluent
|
||||
- id: fluent_linter
|
||||
files: \.ftl$
|
||||
args: [--config, .github/fluent_linter_config.yml, src/uu/]
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
|
|
|
@ -25,6 +25,7 @@ getrandom
|
|||
globset
|
||||
indicatif
|
||||
itertools
|
||||
iuse
|
||||
langid
|
||||
lscolors
|
||||
mdbook
|
||||
|
|
399
Cargo.lock
generated
399
Cargo.lock
generated
|
@ -4,9 +4,9 @@ version = 4
|
|||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
|
@ -55,9 +55,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
version = "0.6.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
|
@ -70,33 +70,33 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.8"
|
||||
version = "3.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
|
||||
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
|
@ -268,9 +268,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
version = "3.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
|
@ -292,9 +292,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.25"
|
||||
version = "1.2.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
|
||||
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
@ -310,9 +310,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
|
@ -403,9 +403,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||
|
||||
[[package]]
|
||||
name = "clap_mangen"
|
||||
|
@ -419,9 +419,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "compare"
|
||||
|
@ -431,15 +431,15 @@ checksum = "120133d4db2ec47efe2e26502ee984747630c67f51974fca0b6c1340cf2368d3"
|
|||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.11"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
|
||||
checksum = "2e09ced7ebbccb63b4c65413d821f2e00ce54c5ca4514ddc6b3c892fdbcbc69d"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width 0.2.1",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -992,9 +992,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"libz-rs-sys",
|
||||
|
@ -1156,7 +1156,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1195,9 +1195,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.3"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
|
@ -1251,6 +1251,140 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collator"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ad4c6a556938dfd31f75a8c54141079e8821dc697ffb799cfe0f0fa11f2edc"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collator_data",
|
||||
"icu_collections",
|
||||
"icu_locale",
|
||||
"icu_locale_core",
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collator_data"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d880b8e680799eabd90c054e1b95526cd48db16c95269f3c89fb3117e1ac92c5"
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"potential_utf",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locale"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ae5921528335e91da1b6c695dbf1ec37df5ac13faa3f91e5640be93aa2fbefd"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locale_core",
|
||||
"icu_locale_data",
|
||||
"icu_provider",
|
||||
"potential_utf",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locale_core"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locale_data"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fdef0c124749d06a743c69e938350816554eb63ac979166590e2b4ee4252765"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locale_core",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"potential_utf",
|
||||
"zerotrie",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locale_core",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerotrie",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.9.0"
|
||||
|
@ -1258,19 +1392,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.3",
|
||||
"hashbrown 0.15.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.17.11"
|
||||
version = "0.17.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
|
||||
checksum = "4adb2ee6ad319a912210a36e56e3623555817bcc877a7e6e8802d1d69c4d8056"
|
||||
dependencies = [
|
||||
"console",
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"unicode-width 0.2.1",
|
||||
"unit-prefix",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
|
@ -1467,9 +1601,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libz-rs-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
|
||||
checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221"
|
||||
dependencies = [
|
||||
"zlib-rs",
|
||||
]
|
||||
|
@ -1480,6 +1614,18 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13d6a630ed4f43c11056af8768c4773df2c43bc780b6d8a46de345c17236c562"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "0.4.1"
|
||||
|
@ -1508,7 +1654,7 @@ version = "0.12.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.3",
|
||||
"hashbrown 0.15.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1554,9 +1700,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.8"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
@ -1569,7 +1715,7 @@ checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
|
@ -1905,9 +2051,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
|
@ -1918,6 +2064,16 @@ dependencies = [
|
|||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
|
@ -1945,9 +2101,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.33"
|
||||
version = "0.2.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d"
|
||||
checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
|
@ -2073,9 +2229,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.12"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
|
||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
]
|
||||
|
@ -2195,7 +2351,7 @@ dependencies = [
|
|||
"bitflags 2.9.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.9.4",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
|
@ -2426,6 +2582,12 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
|
@ -2434,15 +2596,26 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
version = "2.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
|
@ -2588,15 +2761,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.9"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.26"
|
||||
version = "0.22.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
|
@ -2678,12 +2851,30 @@ version = "0.2.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
|
||||
|
||||
[[package]]
|
||||
name = "unit-prefix"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "323402cff2dd658f39ca17c789b502021b3f18707c91cdf22e3838e1b4023817"
|
||||
|
||||
[[package]]
|
||||
name = "unty"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
|
@ -2797,6 +2988,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
"thiserror 2.0.12",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
|
@ -2844,7 +3036,7 @@ dependencies = [
|
|||
"filetime",
|
||||
"indicatif",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.10.0",
|
||||
"selinux",
|
||||
"thiserror 2.0.12",
|
||||
"uucore",
|
||||
|
@ -3027,6 +3219,7 @@ name = "uu_fmt"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"thiserror 2.0.12",
|
||||
"unicode-width 0.2.1",
|
||||
"uucore",
|
||||
]
|
||||
|
@ -3387,6 +3580,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
"thiserror 2.0.12",
|
||||
"uucore",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
@ -3489,6 +3683,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"thiserror 2.0.12",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
|
@ -3498,6 +3693,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"clap",
|
||||
"tempfile",
|
||||
"thiserror 2.0.12",
|
||||
"uu_stdbuf_libstdbuf",
|
||||
"uucore",
|
||||
]
|
||||
|
@ -3774,6 +3970,8 @@ dependencies = [
|
|||
"fluent-syntax",
|
||||
"glob",
|
||||
"hex",
|
||||
"icu_collator",
|
||||
"icu_locale",
|
||||
"itertools 0.14.0",
|
||||
"libc",
|
||||
"md-5",
|
||||
|
@ -3876,9 +4074,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
|
@ -4044,9 +4242,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
|
@ -4289,9 +4487,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
|||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.10"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -4305,6 +4503,12 @@ dependencies = [
|
|||
"bitflags 2.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
|
@ -4316,9 +4520,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
|
||||
checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix",
|
||||
|
@ -4330,6 +4534,30 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "z85"
|
||||
version = "3.0.6"
|
||||
|
@ -4382,6 +4610,32 @@ name = "zerofrom"
|
|||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
|
||||
dependencies = [
|
||||
"zerofrom-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom-derive"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
|
@ -4389,14 +4643,27 @@ version = "0.11.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "4.1.0"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af7dcdb4229c0e79c2531a24de7726a0e980417a74fb4d030a35f535665439a0"
|
||||
checksum = "95ab361742de920c5535880f89bbd611ee62002bf11341d16a5f057bb8ba6899"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"crc32fast",
|
||||
|
@ -4408,9 +4675,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zlib-rs"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
|
||||
checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a"
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# coreutils (uutils)
|
||||
# * see the repository LICENSE, README, and CONTRIBUTING files for more information
|
||||
|
||||
# spell-checker:ignore (libs) bigdecimal datetime serde bincode gethostid kqueue libselinux mangen memmap uuhelp startswith constness expl
|
||||
# spell-checker:ignore (libs) bigdecimal datetime serde bincode gethostid kqueue libselinux mangen memmap uuhelp startswith constness expl unnested
|
||||
|
||||
[package]
|
||||
name = "coreutils"
|
||||
|
@ -313,6 +313,8 @@ gcd = "2.3"
|
|||
glob = "0.3.1"
|
||||
half = "2.4.1"
|
||||
hostname = "0.4"
|
||||
icu_collator = "2.0.0"
|
||||
icu_locale = "2.0.0"
|
||||
indicatif = "0.17.8"
|
||||
itertools = "0.14.0"
|
||||
jiff = { version = "0.2.10", default-features = false, features = [
|
||||
|
@ -321,7 +323,7 @@ jiff = { version = "0.2.10", default-features = false, features = [
|
|||
"tz-system",
|
||||
] }
|
||||
libc = "0.2.172"
|
||||
linux-raw-sys = "0.9"
|
||||
linux-raw-sys = "0.10"
|
||||
lscolors = { version = "0.20.0", default-features = false, features = [
|
||||
"gnu_legacy",
|
||||
] }
|
||||
|
@ -665,8 +667,7 @@ return_self_not_must_use = "allow" # 8
|
|||
needless_pass_by_value = "allow" # 8
|
||||
# manual_let_else = "allow" # 8
|
||||
# needless_raw_string_hashes = "allow" # 7
|
||||
match_on_vec_items = "allow" # 6
|
||||
inline_always = "allow" # 6
|
||||
inline_always = "allow" # 6
|
||||
# format_push_string = "allow" # 6
|
||||
fn_params_excessive_bools = "allow" # 6
|
||||
# single_char_pattern = "allow" # 4
|
||||
|
|
13
GNUmakefile
13
GNUmakefile
|
@ -33,6 +33,9 @@ PREFIX ?= /usr/local
|
|||
DESTDIR ?=
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
DATAROOTDIR ?= $(PREFIX)/share
|
||||
LIBSTDBUF_DIR ?= $(PREFIX)/libexec/coreutils
|
||||
# Export variable so that it is used during the build
|
||||
export LIBSTDBUF_DIR
|
||||
|
||||
INSTALLDIR_BIN=$(DESTDIR)$(BINDIR)
|
||||
|
||||
|
@ -199,6 +202,8 @@ ifneq ($(OS),Windows_NT)
|
|||
PROGS := $(PROGS) $(UNIX_PROGS)
|
||||
# Build the selinux command even if not on the system
|
||||
PROGS := $(PROGS) $(SELINUX_PROGS)
|
||||
# Always use external libstdbuf when building with make (Unix only)
|
||||
CARGOFLAGS += --features feat_external_libstdbuf
|
||||
endif
|
||||
|
||||
UTILS ?= $(PROGS)
|
||||
|
@ -438,6 +443,10 @@ endif
|
|||
|
||||
install: build install-manpages install-completions install-locales
|
||||
mkdir -p $(INSTALLDIR_BIN)
|
||||
ifneq ($(OS),Windows_NT)
|
||||
mkdir -p $(DESTDIR)$(LIBSTDBUF_DIR)
|
||||
$(INSTALL) -m 755 $(BUILDDIR)/deps/libstdbuf* $(DESTDIR)$(LIBSTDBUF_DIR)/
|
||||
endif
|
||||
ifeq (${MULTICALL}, y)
|
||||
$(INSTALL) $(BUILDDIR)/coreutils $(INSTALLDIR_BIN)/$(PROG_PREFIX)coreutils
|
||||
$(foreach prog, $(filter-out coreutils, $(INSTALLEES)), \
|
||||
|
@ -452,6 +461,10 @@ else
|
|||
endif
|
||||
|
||||
uninstall:
|
||||
ifneq ($(OS),Windows_NT)
|
||||
rm -f $(DESTDIR)$(LIBSTDBUF_DIR)/libstdbuf*
|
||||
-rmdir $(DESTDIR)$(LIBSTDBUF_DIR) 2>/dev/null || true
|
||||
endif
|
||||
ifeq (${MULTICALL}, y)
|
||||
rm -f $(addprefix $(INSTALLDIR_BIN)/,$(PROG_PREFIX)coreutils)
|
||||
endif
|
||||
|
|
|
@ -120,6 +120,8 @@ skip = [
|
|||
{ name = "rand_core", version = "0.6.4" },
|
||||
# utmp-classic
|
||||
{ name = "zerocopy", version = "0.7.35" },
|
||||
# rustix
|
||||
{ name = "linux-raw-sys", version = "0.9.4" },
|
||||
]
|
||||
# spell-checker: enable
|
||||
|
||||
|
|
378
fuzz/Cargo.lock
generated
378
fuzz/Cargo.lock
generated
|
@ -28,9 +28,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
version = "0.6.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
|
@ -43,33 +43,33 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.8"
|
||||
version = "3.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
|
||||
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
|
@ -174,21 +174,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
version = "3.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
|
||||
checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.23"
|
||||
version = "1.2.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
|
||||
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
|
@ -197,9 +197,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
|
@ -221,18 +221,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.38"
|
||||
version = "4.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
||||
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.38"
|
||||
version = "4.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
||||
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -243,15 +243,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "compare"
|
||||
|
@ -261,15 +261,15 @@ checksum = "120133d4db2ec47efe2e26502ee984747630c67f51974fca0b6c1340cf2368d3"
|
|||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.11"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
|
||||
checksum = "2e09ced7ebbccb63b4c65413d821f2e00ce54c5ca4514ddc6b3c892fdbcbc69d"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -483,7 +483,7 @@ dependencies = [
|
|||
"fluent-syntax",
|
||||
"intl-memoizer",
|
||||
"intl_pluralrules",
|
||||
"rustc-hash 2.1.1",
|
||||
"rustc-hash",
|
||||
"self_cell",
|
||||
"smallvec",
|
||||
"unic-langid",
|
||||
|
@ -532,7 +532,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -589,6 +589,140 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collator"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ad4c6a556938dfd31f75a8c54141079e8821dc697ffb799cfe0f0fa11f2edc"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collator_data",
|
||||
"icu_collections",
|
||||
"icu_locale",
|
||||
"icu_locale_core",
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collator_data"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d880b8e680799eabd90c054e1b95526cd48db16c95269f3c89fb3117e1ac92c5"
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"potential_utf",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locale"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ae5921528335e91da1b6c695dbf1ec37df5ac13faa3f91e5640be93aa2fbefd"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locale_core",
|
||||
"icu_locale_data",
|
||||
"icu_provider",
|
||||
"potential_utf",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locale_core"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locale_data"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fdef0c124749d06a743c69e938350816554eb63ac979166590e2b4ee4252765"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locale_core",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"potential_utf",
|
||||
"zerotrie",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locale_core",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerotrie",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intl-memoizer"
|
||||
version = "0.5.3"
|
||||
|
@ -625,9 +759,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.11"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27e77966151130221b079bcec80f1f34a9e414fa489d99152a201c07fd2182bc"
|
||||
checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"jiff-tzdb-platform",
|
||||
|
@ -640,9 +774,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.11"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97265751f8a9a4228476f2fc17874a9e7e70e96b893368e42619880fe143b48a"
|
||||
checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -721,6 +855,12 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
|
@ -739,9 +879,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
version = "2.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
|
@ -870,9 +1010,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
|||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
|
@ -883,6 +1023,16 @@ dependencies = [
|
|||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
|
@ -1005,12 +1155,6 @@ dependencies = [
|
|||
"trim-in-place",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
|
@ -1032,9 +1176,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
|
@ -1117,9 +1261,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.0"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
|
@ -1129,15 +1279,26 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
version = "2.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.20.0"
|
||||
|
@ -1208,11 +1369,11 @@ checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc"
|
|||
|
||||
[[package]]
|
||||
name = "type-map"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f"
|
||||
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
|
||||
dependencies = [
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1247,9 +1408,21 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
|
@ -1287,7 +1460,7 @@ dependencies = [
|
|||
"libc",
|
||||
"parse_datetime",
|
||||
"uucore",
|
||||
"windows-sys 0.60.1",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1423,6 +1596,8 @@ dependencies = [
|
|||
"fluent-syntax",
|
||||
"glob",
|
||||
"hex",
|
||||
"icu_collator",
|
||||
"icu_locale",
|
||||
"itertools",
|
||||
"libc",
|
||||
"md-5",
|
||||
|
@ -1440,7 +1615,7 @@ dependencies = [
|
|||
"uucore_procs",
|
||||
"wild",
|
||||
"winapi-util",
|
||||
"windows-sys 0.60.1",
|
||||
"windows-sys 0.60.2",
|
||||
"z85",
|
||||
]
|
||||
|
||||
|
@ -1500,9 +1675,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
|
@ -1626,9 +1801,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
|
@ -1659,11 +1834,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.1"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b36e9ed89376c545e20cbf5a13c306b49106b21b9d1d4f9cb9a1cb6b1e9ee06a"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.1",
|
||||
"windows-targets 0.53.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1684,9 +1859,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.1"
|
||||
version = "0.53.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30357ec391cde730f8fbfcdc29adc47518b06504528df977ab5af02ef23fdee9"
|
||||
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
|
@ -1803,6 +1978,36 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "z85"
|
||||
version = "3.0.6"
|
||||
|
@ -1834,6 +2039,32 @@ name = "zerofrom"
|
|||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
|
||||
dependencies = [
|
||||
"zerofrom-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom-derive"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
|
@ -1841,5 +2072,18 @@ version = "0.11.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
@ -8,7 +8,7 @@ edition.workspace = true
|
|||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
console = "0.15.0"
|
||||
console = "0.16.0"
|
||||
libc = "0.2.153"
|
||||
rand = { version = "0.9.0", features = ["small_rng"] }
|
||||
similar = "2.5.0"
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# This file contains base32, base64 and basenc strings
|
||||
# This is because we have some common strings for all these tools
|
||||
# and it is easier to have a single file than one file for program
|
||||
# and loading several bundles at the same time.
|
||||
|
||||
base32-about = encode/decode data and print to standard output
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
|
@ -7,3 +12,47 @@ base32-about = encode/decode data and print to standard output
|
|||
to attempt to recover from any other non-alphabet bytes in the
|
||||
encoded stream.
|
||||
base32-usage = base32 [OPTION]... [FILE]
|
||||
|
||||
base64-about = encode/decode data and print to standard output
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
The data are encoded as described for the base64 alphabet in RFC 3548.
|
||||
When decoding, the input may contain newlines in addition
|
||||
to the bytes of the formal base64 alphabet. Use --ignore-garbage
|
||||
to attempt to recover from any other non-alphabet bytes in the
|
||||
encoded stream.
|
||||
base64-usage = base64 [OPTION]... [FILE]
|
||||
|
||||
basenc-about = Encode/decode data and print to standard output
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
When decoding, the input may contain newlines in addition to the bytes of
|
||||
the formal alphabet. Use --ignore-garbage to attempt to recover
|
||||
from any other non-alphabet bytes in the encoded stream.
|
||||
basenc-usage = basenc [OPTION]... [FILE]
|
||||
|
||||
# Help messages for encoding formats
|
||||
basenc-help-base64 = same as 'base64' program
|
||||
basenc-help-base64url = file- and url-safe base64
|
||||
basenc-help-base32 = same as 'base32' program
|
||||
basenc-help-base32hex = extended hex alphabet base32
|
||||
basenc-help-base16 = hex encoding
|
||||
basenc-help-base2lsbf = bit string with least significant bit (lsb) first
|
||||
basenc-help-base2msbf = bit string with most significant bit (msb) first
|
||||
basenc-help-z85 = ascii85-like encoding;
|
||||
when encoding, input length must be a multiple of 4;
|
||||
when decoding, input length must be a multiple of 5
|
||||
|
||||
# Error messages
|
||||
basenc-error-missing-encoding-type = missing encoding type
|
||||
|
||||
# Shared base_common error messages (used by base32, base64, basenc)
|
||||
base-common-extra-operand = extra operand {$operand}
|
||||
base-common-no-such-file = {$file}: No such file or directory
|
||||
base-common-invalid-wrap-size = invalid wrap size: {$size}
|
||||
base-common-read-error = read error: {$error}
|
||||
|
||||
# Shared base_common help messages
|
||||
base-common-help-decode = decode data
|
||||
base-common-help-ignore-garbage = when decoding, ignore non-alphabetic characters
|
||||
base-common-help-wrap = wrap encoded lines after COLS character (default {$default}, 0 to disable wrapping)
|
||||
|
|
53
src/uu/base32/locales/fr-FR.ftl
Normal file
53
src/uu/base32/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,53 @@
|
|||
base32-about = encoder/décoder les données et les imprimer sur la sortie standard
|
||||
Sans FICHIER, ou quand FICHIER est -, lire l'entrée standard.
|
||||
|
||||
Les données sont encodées comme décrit pour l'alphabet base32 dans RFC 4648.
|
||||
Lors du décodage, l'entrée peut contenir des retours à la ligne en plus
|
||||
des octets de l'alphabet base32 formel. Utilisez --ignore-garbage
|
||||
pour tenter de récupérer des autres octets non-alphabétiques dans
|
||||
le flux encodé.
|
||||
base32-usage = base32 [OPTION]... [FICHIER]
|
||||
|
||||
base64-about = encoder/décoder les données et les imprimer sur la sortie standard
|
||||
Sans FICHIER, ou quand FICHIER est -, lire l'entrée standard.
|
||||
|
||||
Les données sont encodées comme décrit pour l'alphabet base64 dans RFC 3548.
|
||||
Lors du décodage, l'entrée peut contenir des retours à la ligne en plus
|
||||
des octets de l'alphabet base64 formel. Utilisez --ignore-garbage
|
||||
pour tenter de récupérer des autres octets non-alphabétiques dans
|
||||
le flux encodé.
|
||||
base64-usage = base64 [OPTION]... [FICHIER]
|
||||
|
||||
basenc-about = Encoder/décoder des données et afficher vers la sortie standard
|
||||
Sans FICHIER, ou lorsque FICHIER est -, lire l'entrée standard.
|
||||
|
||||
Lors du décodage, l'entrée peut contenir des nouvelles lignes en plus des octets de
|
||||
l'alphabet formel. Utilisez --ignore-garbage pour tenter de récupérer
|
||||
depuis tout autre octet non-alphabétique dans le flux encodé.
|
||||
basenc-usage = basenc [OPTION]... [FICHIER]
|
||||
|
||||
# Messages d'aide pour les formats d'encodage
|
||||
basenc-help-base64 = identique au programme 'base64'
|
||||
basenc-help-base64url = base64 sécurisé pour fichiers et URLs
|
||||
basenc-help-base32 = identique au programme 'base32'
|
||||
basenc-help-base32hex = base32 avec alphabet hexadécimal étendu
|
||||
basenc-help-base16 = encodage hexadécimal
|
||||
basenc-help-base2lsbf = chaîne de bits avec le bit de poids faible (lsb) en premier
|
||||
basenc-help-base2msbf = chaîne de bits avec le bit de poids fort (msb) en premier
|
||||
basenc-help-z85 = encodage de type ascii85 ;
|
||||
lors de l'encodage, la longueur d'entrée doit être un multiple de 4 ;
|
||||
lors du décodage, la longueur d'entrée doit être un multiple de 5
|
||||
|
||||
# Messages d'erreur
|
||||
basenc-error-missing-encoding-type = type d'encodage manquant
|
||||
|
||||
# Messages d'erreur partagés de base_common (utilisés par base32, base64, basenc)
|
||||
base-common-extra-operand = opérande supplémentaire {$operand}
|
||||
base-common-no-such-file = {$file} : Aucun fichier ou répertoire de ce type
|
||||
base-common-invalid-wrap-size = taille de retour à la ligne invalide : {$size}
|
||||
base-common-read-error = erreur de lecture : {$error}
|
||||
|
||||
# Messages d'aide partagés de base_common
|
||||
base-common-help-decode = décoder les données
|
||||
base-common-help-ignore-garbage = lors du décodage, ignorer les caractères non-alphabétiques
|
||||
base-common-help-wrap = retour à la ligne des lignes encodées après COLS caractères (par défaut {$default}, 0 pour désactiver le retour à la ligne)
|
|
@ -6,6 +6,7 @@
|
|||
// spell-checker:ignore hexupper lsbf msbf unpadded nopad aGVsbG8sIHdvcmxkIQ
|
||||
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{self, ErrorKind, Read, Seek, SeekFrom};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -17,6 +18,7 @@ use uucore::encoding::{
|
|||
use uucore::encoding::{EncodingWrapper, SupportsFastDecodeAndEncode};
|
||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
||||
use uucore::format_usage;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
pub const BASE_CMD_PARSE_ERROR: i32 = 1;
|
||||
|
||||
|
@ -50,7 +52,10 @@ impl Config {
|
|||
if let Some(extra_op) = values.next() {
|
||||
return Err(UUsageError::new(
|
||||
BASE_CMD_PARSE_ERROR,
|
||||
format!("extra operand {}", extra_op.quote()),
|
||||
get_message_with_args(
|
||||
"base-common-extra-operand",
|
||||
HashMap::from([("operand".to_string(), extra_op.quote().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -62,7 +67,13 @@ impl Config {
|
|||
if !path.exists() {
|
||||
return Err(USimpleError::new(
|
||||
BASE_CMD_PARSE_ERROR,
|
||||
format!("{}: No such file or directory", path.maybe_quote()),
|
||||
get_message_with_args(
|
||||
"base-common-no-such-file",
|
||||
HashMap::from([(
|
||||
"file".to_string(),
|
||||
path.maybe_quote().to_string(),
|
||||
)]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -78,7 +89,10 @@ impl Config {
|
|||
num.parse::<usize>().map_err(|_| {
|
||||
USimpleError::new(
|
||||
BASE_CMD_PARSE_ERROR,
|
||||
format!("invalid wrap size: {}", num.quote()),
|
||||
get_message_with_args(
|
||||
"base-common-invalid-wrap-size",
|
||||
HashMap::from([("size".to_string(), num.quote().to_string())]),
|
||||
),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
@ -114,7 +128,7 @@ pub fn base_app(about: &'static str, usage: &str) -> Command {
|
|||
.short('d')
|
||||
.visible_short_alias('D')
|
||||
.long(options::DECODE)
|
||||
.help("decode data")
|
||||
.help(get_message("base-common-help-decode"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::DECODE),
|
||||
)
|
||||
|
@ -122,7 +136,7 @@ pub fn base_app(about: &'static str, usage: &str) -> Command {
|
|||
Arg::new(options::IGNORE_GARBAGE)
|
||||
.short('i')
|
||||
.long(options::IGNORE_GARBAGE)
|
||||
.help("when decoding, ignore non-alphabetic characters")
|
||||
.help(get_message("base-common-help-ignore-garbage"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::IGNORE_GARBAGE),
|
||||
)
|
||||
|
@ -131,7 +145,10 @@ pub fn base_app(about: &'static str, usage: &str) -> Command {
|
|||
.short('w')
|
||||
.long(options::WRAP)
|
||||
.value_name("COLS")
|
||||
.help(format!("wrap encoded lines after COLS character (default {WRAP_DEFAULT}, 0 to disable wrapping)"))
|
||||
.help(get_message_with_args(
|
||||
"base-common-help-wrap",
|
||||
HashMap::from([("default".to_string(), WRAP_DEFAULT.to_string())]),
|
||||
))
|
||||
.overrides_with(options::WRAP),
|
||||
)
|
||||
// "multiple" arguments are used to check whether there is more than one
|
||||
|
@ -813,7 +830,10 @@ fn format_read_error(kind: ErrorKind) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
format!("read error: {kind_string_capitalized}")
|
||||
get_message_with_args(
|
||||
"base-common-read-error",
|
||||
HashMap::from([("error".to_string(), kind_string_capitalized)]),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
1
src/uu/base64/locales
Symbolic link
1
src/uu/base64/locales
Symbolic link
|
@ -0,0 +1 @@
|
|||
../base32/locales
|
|
@ -1,9 +0,0 @@
|
|||
base64-about = encode/decode data and print to standard output
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
The data are encoded as described for the base64 alphabet in RFC 3548.
|
||||
When decoding, the input may contain newlines in addition
|
||||
to the bytes of the formal base64 alphabet. Use --ignore-garbage
|
||||
to attempt to recover from any other non-alphabet bytes in the
|
||||
encoded stream.
|
||||
base64-usage = base64 [OPTION]... [FILE]
|
1
src/uu/basenc/locales
Symbolic link
1
src/uu/basenc/locales
Symbolic link
|
@ -0,0 +1 @@
|
|||
../base32/locales
|
|
@ -1,22 +0,0 @@
|
|||
basenc-about = Encode/decode data and print to standard output
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
When decoding, the input may contain newlines in addition to the bytes of
|
||||
the formal alphabet. Use --ignore-garbage to attempt to recover
|
||||
from any other non-alphabet bytes in the encoded stream.
|
||||
basenc-usage = basenc [OPTION]... [FILE]
|
||||
|
||||
# Help messages for encoding formats
|
||||
basenc-help-base64 = same as 'base64' program
|
||||
basenc-help-base64url = file- and url-safe base64
|
||||
basenc-help-base32 = same as 'base32' program
|
||||
basenc-help-base32hex = extended hex alphabet base32
|
||||
basenc-help-base16 = hex encoding
|
||||
basenc-help-base2lsbf = bit string with least significant bit (lsb) first
|
||||
basenc-help-base2msbf = bit string with most significant bit (msb) first
|
||||
basenc-help-z85 = ascii85-like encoding;
|
||||
when encoding, input length must be a multiple of 4;
|
||||
when decoding, input length must be a multiple of 5
|
||||
|
||||
# Error messages
|
||||
basenc-error-missing-encoding-type = missing encoding type
|
|
@ -1,22 +0,0 @@
|
|||
basenc-about = Encoder/décoder des données et afficher vers la sortie standard
|
||||
Sans FICHIER, ou lorsque FICHIER est -, lire l'entrée standard.
|
||||
|
||||
Lors du décodage, l'entrée peut contenir des nouvelles lignes en plus des octets de
|
||||
l'alphabet formel. Utilisez --ignore-garbage pour tenter de récupérer
|
||||
depuis tout autre octet non-alphabétique dans le flux encodé.
|
||||
basenc-usage = basenc [OPTION]... [FICHIER]
|
||||
|
||||
# Messages d'aide pour les formats d'encodage
|
||||
basenc-help-base64 = identique au programme 'base64'
|
||||
basenc-help-base64url = base64 sécurisé pour fichiers et URLs
|
||||
basenc-help-base32 = identique au programme 'base32'
|
||||
basenc-help-base32hex = base32 avec alphabet hexadécimal étendu
|
||||
basenc-help-base16 = encodage hexadécimal
|
||||
basenc-help-base2lsbf = chaîne de bits avec le bit de poids faible (lsb) en premier
|
||||
basenc-help-base2msbf = chaîne de bits avec le bit de poids fort (msb) en premier
|
||||
basenc-help-z85 = encodage de type ascii85 ;
|
||||
lors de l'encodage, la longueur d'entrée doit être un multiple de 4 ;
|
||||
lors du décodage, la longueur d'entrée doit être un multiple de 5
|
||||
|
||||
# Messages d'erreur
|
||||
basenc-error-missing-encoding-type = type d'encodage manquant
|
|
@ -1,3 +1,20 @@
|
|||
chgrp-about = Change the group of each FILE to GROUP.
|
||||
chgrp-usage = chgrp [OPTION]... GROUP FILE...
|
||||
chgrp [OPTION]... --reference=RFILE FILE...
|
||||
|
||||
# Help messages
|
||||
chgrp-help-print-help = Print help information.
|
||||
chgrp-help-changes = like verbose but report only when a change is made
|
||||
chgrp-help-quiet = suppress most error messages
|
||||
chgrp-help-verbose = output a diagnostic for every file processed
|
||||
chgrp-help-preserve-root = fail to operate recursively on '/'
|
||||
chgrp-help-no-preserve-root = do not treat '/' specially (the default)
|
||||
chgrp-help-reference = use RFILE's group rather than specifying GROUP values
|
||||
chgrp-help-from = change the group only if its current group matches GROUP
|
||||
chgrp-help-recursive = operate on files and directories recursively
|
||||
|
||||
# Error messages
|
||||
chgrp-error-invalid-group-id = invalid group id: '{ $gid_str }'
|
||||
chgrp-error-invalid-group = invalid group: '{ $group }'
|
||||
chgrp-error-failed-to-get-attributes = failed to get attributes of { $file }
|
||||
chgrp-error-invalid-user = invalid user: '{ $from_group }'
|
||||
|
|
20
src/uu/chgrp/locales/fr-FR.ftl
Normal file
20
src/uu/chgrp/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,20 @@
|
|||
chgrp-about = Changer le groupe de chaque FICHIER vers GROUPE.
|
||||
chgrp-usage = chgrp [OPTION]... GROUPE FICHIER...
|
||||
chgrp [OPTION]... --reference=RFICHIER FICHIER...
|
||||
|
||||
# Messages d'aide
|
||||
chgrp-help-print-help = Afficher les informations d'aide.
|
||||
chgrp-help-changes = comme verbeux mais rapporter seulement lors d'un changement
|
||||
chgrp-help-quiet = supprimer la plupart des messages d'erreur
|
||||
chgrp-help-verbose = afficher un diagnostic pour chaque fichier traité
|
||||
chgrp-help-preserve-root = échouer à opérer récursivement sur '/'
|
||||
chgrp-help-no-preserve-root = ne pas traiter '/' spécialement (par défaut)
|
||||
chgrp-help-reference = utiliser le groupe de RFICHIER plutôt que spécifier les valeurs de GROUPE
|
||||
chgrp-help-from = changer le groupe seulement si son groupe actuel correspond à GROUPE
|
||||
chgrp-help-recursive = opérer sur les fichiers et répertoires récursivement
|
||||
|
||||
# Messages d'erreur
|
||||
chgrp-error-invalid-group-id = identifiant de groupe invalide : '{ $gid_str }'
|
||||
chgrp-error-invalid-group = groupe invalide : '{ $group }'
|
||||
chgrp-error-failed-to-get-attributes = échec de l'obtention des attributs de { $file }
|
||||
chgrp-error-invalid-user = utilisateur invalide : '{ $from_group }'
|
|
@ -12,26 +12,33 @@ use uucore::format_usage;
|
|||
use uucore::perms::{GidUidOwnerFilter, IfFrom, chown_base, options};
|
||||
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use std::fs;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
fn parse_gid_from_str(group: &str) -> Result<u32, String> {
|
||||
if let Some(gid_str) = group.strip_prefix(':') {
|
||||
// Handle :gid format
|
||||
gid_str
|
||||
.parse::<u32>()
|
||||
.map_err(|_| format!("invalid group id: '{gid_str}'"))
|
||||
gid_str.parse::<u32>().map_err(|_| {
|
||||
get_message_with_args(
|
||||
"chgrp-error-invalid-group-id",
|
||||
HashMap::from([("gid_str".to_string(), gid_str.to_string())]),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
// Try as group name first
|
||||
match entries::grp2gid(group) {
|
||||
Ok(g) => Ok(g),
|
||||
// If group name lookup fails, try parsing as raw number
|
||||
Err(_) => group
|
||||
.parse::<u32>()
|
||||
.map_err(|_| format!("invalid group: '{group}'")),
|
||||
Err(_) => group.parse::<u32>().map_err(|_| {
|
||||
get_message_with_args(
|
||||
"chgrp-error-invalid-group",
|
||||
HashMap::from([("group".to_string(), group.to_string())]),
|
||||
)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +52,12 @@ fn get_dest_gid(matches: &ArgMatches) -> UResult<(Option<u32>, String)> {
|
|||
raw_group = entries::gid2grp(gid).unwrap_or_else(|_| gid.to_string());
|
||||
Some(gid)
|
||||
})
|
||||
.map_err_context(|| format!("failed to get attributes of {}", file.quote()))?
|
||||
.map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"chgrp-error-failed-to-get-attributes",
|
||||
HashMap::from([("file".to_string(), file.quote().to_string())]),
|
||||
)
|
||||
})?
|
||||
} else {
|
||||
let group = matches
|
||||
.get_one::<String>(options::ARG_GROUP)
|
||||
|
@ -74,7 +86,10 @@ fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<GidUidOwnerFilter> {
|
|||
Err(_) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid user: '{from_group}'"),
|
||||
get_message_with_args(
|
||||
"chgrp-error-invalid-user",
|
||||
HashMap::from([("from_group".to_string(), from_group.to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -105,14 +120,14 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::HELP)
|
||||
.long(options::HELP)
|
||||
.help("Print help information.")
|
||||
.help(get_message("chgrp-help-print-help"))
|
||||
.action(ArgAction::Help),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::verbosity::CHANGES)
|
||||
.short('c')
|
||||
.long(options::verbosity::CHANGES)
|
||||
.help("like verbose but report only when a change is made")
|
||||
.help(get_message("chgrp-help-changes"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -124,26 +139,26 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::verbosity::QUIET)
|
||||
.long(options::verbosity::QUIET)
|
||||
.help("suppress most error messages")
|
||||
.help(get_message("chgrp-help-quiet"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::verbosity::VERBOSE)
|
||||
.short('v')
|
||||
.long(options::verbosity::VERBOSE)
|
||||
.help("output a diagnostic for every file processed")
|
||||
.help(get_message("chgrp-help-verbose"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::preserve_root::PRESERVE)
|
||||
.long(options::preserve_root::PRESERVE)
|
||||
.help("fail to operate recursively on '/'")
|
||||
.help(get_message("chgrp-help-preserve-root"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::preserve_root::NO_PRESERVE)
|
||||
.long(options::preserve_root::NO_PRESERVE)
|
||||
.help("do not treat '/' specially (the default)")
|
||||
.help(get_message("chgrp-help-no-preserve-root"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -151,19 +166,19 @@ pub fn uu_app() -> Command {
|
|||
.long(options::REFERENCE)
|
||||
.value_name("RFILE")
|
||||
.value_hint(clap::ValueHint::FilePath)
|
||||
.help("use RFILE's group rather than specifying GROUP values"),
|
||||
.help(get_message("chgrp-help-reference")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FROM)
|
||||
.long(options::FROM)
|
||||
.value_name("GROUP")
|
||||
.help("change the group only if its current group matches GROUP"),
|
||||
.help(get_message("chgrp-help-from")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::RECURSIVE)
|
||||
.short('R')
|
||||
.long(options::RECURSIVE)
|
||||
.help("operate on files and directories recursively")
|
||||
.help(get_message("chgrp-help-recursive"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
// Add common arguments with chgrp, chown & chmod
|
||||
|
|
|
@ -20,6 +20,7 @@ path = "src/chmod.rs"
|
|||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "fs", "mode", "perms"] }
|
||||
|
||||
[[bin]]
|
||||
|
|
|
@ -4,3 +4,28 @@ chmod-usage = chmod [OPTION]... MODE[,MODE]... FILE...
|
|||
chmod [OPTION]... OCTAL-MODE FILE...
|
||||
chmod [OPTION]... --reference=RFILE FILE...
|
||||
chmod-after-help = Each MODE is of the form [ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+.
|
||||
chmod-error-cannot-stat = cannot stat attributes of {$file}
|
||||
chmod-error-dangling-symlink = cannot operate on dangling symlink {$file}
|
||||
chmod-error-no-such-file = cannot access {$file}: No such file or directory
|
||||
chmod-error-preserve-root = it is dangerous to operate recursively on {$file}
|
||||
chmod: use --no-preserve-root to override this failsafe
|
||||
chmod-error-permission-denied = {$file}: Permission denied
|
||||
chmod-error-new-permissions = {$file}: new permissions are {$actual}, not {$expected}
|
||||
chmod-error-missing-operand = missing operand
|
||||
|
||||
# Help messages
|
||||
chmod-help-print-help = Print help information.
|
||||
chmod-help-changes = like verbose but report only when a change is made
|
||||
chmod-help-quiet = suppress most error messages
|
||||
chmod-help-verbose = output a diagnostic for every file processed
|
||||
chmod-help-no-preserve-root = do not treat '/' specially (the default)
|
||||
chmod-help-preserve-root = fail to operate recursively on '/'
|
||||
chmod-help-recursive = change files and directories recursively
|
||||
chmod-help-reference = use RFILE's mode instead of MODE values
|
||||
|
||||
# Verbose messages
|
||||
chmod-verbose-failed-dangling = failed to change mode of {$file} from 0000 (---------) to 1500 (r-x-----T)
|
||||
chmod-verbose-neither-changed = neither symbolic link {$file} nor referent has been changed
|
||||
chmod-verbose-mode-retained = mode of {$file} retained as {$mode_octal} ({$mode_display})
|
||||
chmod-verbose-failed-change = failed to change mode of file {$file} from {$old_mode} ({$old_mode_display}) to {$new_mode} ({$new_mode_display})
|
||||
chmod-verbose-mode-changed = mode of {$file} changed from {$old_mode} ({$old_mode_display}) to {$new_mode} ({$new_mode_display})
|
||||
|
|
33
src/uu/chmod/locales/fr-FR.ftl
Normal file
33
src/uu/chmod/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,33 @@
|
|||
chmod-about = Changer le mode de chaque FICHIER vers MODE.
|
||||
Avec --reference, changer le mode de chaque FICHIER vers celui de RFICHIER.
|
||||
chmod-usage = chmod [OPTION]... MODE[,MODE]... FICHIER...
|
||||
chmod [OPTION]... MODE-OCTAL FICHIER...
|
||||
chmod [OPTION]... --reference=RFICHIER FICHIER...
|
||||
chmod-after-help = Chaque MODE est de la forme [ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+.
|
||||
|
||||
# Messages d'aide
|
||||
chmod-help-print-help = Afficher les informations d'aide.
|
||||
chmod-help-changes = comme verbeux mais rapporter seulement lors d'un changement
|
||||
chmod-help-quiet = supprimer la plupart des messages d'erreur
|
||||
chmod-help-verbose = afficher un diagnostic pour chaque fichier traité
|
||||
chmod-help-no-preserve-root = ne pas traiter '/' spécialement (par défaut)
|
||||
chmod-help-preserve-root = échouer à opérer récursivement sur '/'
|
||||
chmod-help-recursive = changer les fichiers et répertoires récursivement
|
||||
chmod-help-reference = utiliser le mode de RFICHIER au lieu des valeurs de MODE
|
||||
|
||||
# Messages d'erreur
|
||||
chmod-error-cannot-stat = impossible d'obtenir les attributs de {$file}
|
||||
chmod-error-dangling-symlink = impossible d'opérer sur le lien symbolique pendouillant {$file}
|
||||
chmod-error-no-such-file = impossible d'accéder à {$file} : Aucun fichier ou dossier de ce type
|
||||
chmod-error-preserve-root = il est dangereux d'opérer récursivement sur {$file}
|
||||
chmod: utiliser --no-preserve-root pour outrepasser cette protection
|
||||
chmod-error-permission-denied = {$file} : Permission refusée
|
||||
chmod-error-new-permissions = {$file} : les nouvelles permissions sont {$actual}, pas {$expected}
|
||||
chmod-error-missing-operand = opérande manquant
|
||||
|
||||
# Messages verbeux/de statut
|
||||
chmod-verbose-failed-dangling = échec du changement de mode de {$file} de 0000 (---------) vers 1500 (r-x-----T)
|
||||
chmod-verbose-neither-changed = ni le lien symbolique {$file} ni la référence n'ont été changés
|
||||
chmod-verbose-mode-retained = mode de {$file} conservé comme {$mode_octal} ({$mode_display})
|
||||
chmod-verbose-failed-change = échec du changement de mode du fichier {$file} de {$old_mode} ({$old_mode_display}) vers {$new_mode} ({$new_mode_display})
|
||||
chmod-verbose-mode-changed = mode de {$file} changé de {$old_mode} ({$old_mode_display}) vers {$new_mode} ({$new_mode_display})
|
|
@ -6,12 +6,14 @@
|
|||
// spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's
|
||||
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::os::unix::fs::{MetadataExt, PermissionsExt};
|
||||
use std::path::Path;
|
||||
use thiserror::Error;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{ExitCode, UResult, USimpleError, UUsageError, set_exit_code};
|
||||
use uucore::error::{ExitCode, UError, UResult, USimpleError, UUsageError, set_exit_code};
|
||||
use uucore::fs::display_permissions_unix;
|
||||
use uucore::libc::mode_t;
|
||||
#[cfg(not(windows))]
|
||||
|
@ -19,7 +21,25 @@ use uucore::mode;
|
|||
use uucore::perms::{TraverseSymlinks, configure_symlink_and_recursion};
|
||||
use uucore::{format_usage, show, show_error};
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum ChmodError {
|
||||
#[error("{}", get_message_with_args("chmod-error-cannot-stat", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
|
||||
CannotStat(String),
|
||||
#[error("{}", get_message_with_args("chmod-error-dangling-symlink", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
|
||||
DanglingSymlink(String),
|
||||
#[error("{}", get_message_with_args("chmod-error-no-such-file", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
|
||||
NoSuchFile(String),
|
||||
#[error("{}", get_message_with_args("chmod-error-preserve-root", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
|
||||
PreserveRoot(String),
|
||||
#[error("{}", get_message_with_args("chmod-error-permission-denied", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
|
||||
PermissionDenied(String),
|
||||
#[error("{}", get_message_with_args("chmod-error-new-permissions", HashMap::from([("file".to_string(), _0.clone()), ("actual".to_string(), _1.clone()), ("expected".to_string(), _2.clone())])))]
|
||||
NewPermissions(String, String, String),
|
||||
}
|
||||
|
||||
impl UError for ChmodError {}
|
||||
|
||||
mod options {
|
||||
pub const HELP: &str = "help";
|
||||
|
@ -103,11 +123,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let fmode = match matches.get_one::<String>(options::REFERENCE) {
|
||||
Some(fref) => match fs::metadata(fref) {
|
||||
Ok(meta) => Some(meta.mode() & 0o7777),
|
||||
Err(err) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("cannot stat attributes of {}: {err}", fref.quote()),
|
||||
));
|
||||
Err(_) => {
|
||||
return Err(ChmodError::CannotStat(fref.to_string()).into());
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
|
@ -135,7 +152,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
};
|
||||
|
||||
if files.is_empty() {
|
||||
return Err(UUsageError::new(1, "missing operand".to_string()));
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
get_message("chmod-error-missing-operand"),
|
||||
));
|
||||
}
|
||||
|
||||
let (recursive, dereference, traverse_symlinks) =
|
||||
|
@ -168,14 +188,14 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::HELP)
|
||||
.long(options::HELP)
|
||||
.help("Print help information.")
|
||||
.help(get_message("chmod-help-print-help"))
|
||||
.action(ArgAction::Help),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::CHANGES)
|
||||
.long(options::CHANGES)
|
||||
.short('c')
|
||||
.help("like verbose but report only when a change is made")
|
||||
.help(get_message("chmod-help-changes"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -183,40 +203,40 @@ pub fn uu_app() -> Command {
|
|||
.long(options::QUIET)
|
||||
.visible_alias("silent")
|
||||
.short('f')
|
||||
.help("suppress most error messages")
|
||||
.help(get_message("chmod-help-quiet"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::VERBOSE)
|
||||
.long(options::VERBOSE)
|
||||
.short('v')
|
||||
.help("output a diagnostic for every file processed")
|
||||
.help(get_message("chmod-help-verbose"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NO_PRESERVE_ROOT)
|
||||
.long(options::NO_PRESERVE_ROOT)
|
||||
.help("do not treat '/' specially (the default)")
|
||||
.help(get_message("chmod-help-no-preserve-root"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PRESERVE_ROOT)
|
||||
.long(options::PRESERVE_ROOT)
|
||||
.help("fail to operate recursively on '/'")
|
||||
.help(get_message("chmod-help-preserve-root"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::RECURSIVE)
|
||||
.long(options::RECURSIVE)
|
||||
.short('R')
|
||||
.help("change files and directories recursively")
|
||||
.help(get_message("chmod-help-recursive"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::REFERENCE)
|
||||
.long("reference")
|
||||
.value_hint(clap::ValueHint::FilePath)
|
||||
.help("use RFILE's mode instead of MODE values"),
|
||||
.help(get_message("chmod-help-reference")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::MODE).required_unless_present(options::REFERENCE),
|
||||
|
@ -265,27 +285,21 @@ impl Chmoder {
|
|||
}
|
||||
|
||||
if !self.quiet {
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
format!("cannot operate on dangling symlink {}", filename.quote()),
|
||||
));
|
||||
show!(ChmodError::DanglingSymlink(filename.to_string()));
|
||||
set_exit_code(1);
|
||||
}
|
||||
|
||||
if self.verbose {
|
||||
println!(
|
||||
"failed to change mode of {} from 0000 (---------) to 1500 (r-x-----T)",
|
||||
filename.quote()
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"chmod-verbose-failed-dangling",
|
||||
HashMap::from([("file".to_string(), filename.quote().to_string())])
|
||||
)
|
||||
);
|
||||
}
|
||||
} else if !self.quiet {
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"cannot access {}: No such file or directory",
|
||||
filename.quote()
|
||||
)
|
||||
));
|
||||
show!(ChmodError::NoSuchFile(filename.to_string()));
|
||||
}
|
||||
// GNU exits with exit code 1 even if -q or --quiet are passed
|
||||
// So we set the exit code, because it hasn't been set yet if `self.quiet` is true.
|
||||
|
@ -298,13 +312,7 @@ impl Chmoder {
|
|||
continue;
|
||||
}
|
||||
if self.recursive && self.preserve_root && filename == "/" {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"it is dangerous to operate recursively on {}\nchmod: use --no-preserve-root to override this failsafe",
|
||||
filename.quote()
|
||||
),
|
||||
));
|
||||
return Err(ChmodError::PreserveRoot(filename.to_string()).into());
|
||||
}
|
||||
if self.recursive {
|
||||
r = self.walk_dir(file);
|
||||
|
@ -368,12 +376,9 @@ impl Chmoder {
|
|||
} else if err.kind() == std::io::ErrorKind::PermissionDenied {
|
||||
// These two filenames would normally be conditionally
|
||||
// quoted, but GNU's tests expect them to always be quoted
|
||||
Err(USimpleError::new(
|
||||
1,
|
||||
format!("{}: Permission denied", file.quote()),
|
||||
))
|
||||
Err(ChmodError::PermissionDenied(file.to_string_lossy().to_string()).into())
|
||||
} else {
|
||||
Err(USimpleError::new(1, format!("{}: {err}", file.quote())))
|
||||
Err(ChmodError::CannotStat(file.to_string_lossy().to_string()).into())
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -420,15 +425,12 @@ impl Chmoder {
|
|||
self.change_file(fperm, new_mode, file)?;
|
||||
// if a permission would have been removed if umask was 0, but it wasn't because umask was not 0, print an error and fail
|
||||
if (new_mode & !naively_expected_new_mode) != 0 {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"{}: new permissions are {}, not {}",
|
||||
file.maybe_quote(),
|
||||
display_permissions_unix(new_mode as mode_t, false),
|
||||
display_permissions_unix(naively_expected_new_mode as mode_t, false)
|
||||
),
|
||||
));
|
||||
return Err(ChmodError::NewPermissions(
|
||||
file.to_string_lossy().to_string(),
|
||||
display_permissions_unix(new_mode as mode_t, false),
|
||||
display_permissions_unix(naively_expected_new_mode as mode_t, false),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
chown-about = Change file owner and group
|
||||
chown-usage = chown [OPTION]... [OWNER][:[GROUP]] FILE...
|
||||
chown [OPTION]... --reference=RFILE FILE...
|
||||
|
||||
# Help messages
|
||||
chown-help-print-help = Print help information.
|
||||
chown-help-changes = like verbose but report only when a change is made
|
||||
chown-help-from = change the owner and/or group of each file only if its
|
||||
current owner and/or group match those specified here.
|
||||
Either may be omitted, in which case a match is not required
|
||||
for the omitted attribute
|
||||
chown-help-preserve-root = fail to operate recursively on '/'
|
||||
chown-help-no-preserve-root = do not treat '/' specially (the default)
|
||||
chown-help-quiet = suppress most error messages
|
||||
chown-help-recursive = operate on files and directories recursively
|
||||
chown-help-reference = use RFILE's owner and group rather than specifying OWNER:GROUP values
|
||||
chown-help-verbose = output a diagnostic for every file processed
|
||||
|
||||
# Error messages
|
||||
chown-error-failed-to-get-attributes = failed to get attributes of { $file }
|
||||
chown-error-invalid-user = invalid user: { $user }
|
||||
chown-error-invalid-group = invalid group: { $group }
|
||||
chown-error-invalid-spec = invalid spec: { $spec }
|
||||
|
|
23
src/uu/chown/locales/fr-FR.ftl
Normal file
23
src/uu/chown/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,23 @@
|
|||
chown-about = Changer le propriétaire et le groupe des fichiers
|
||||
chown-usage = chown [OPTION]... [PROPRIÉTAIRE][:[GROUPE]] FICHIER...
|
||||
chown [OPTION]... --reference=RFICHIER FICHIER...
|
||||
|
||||
# Messages d'aide
|
||||
chown-help-print-help = Afficher les informations d'aide.
|
||||
chown-help-changes = comme verbeux mais rapporter seulement lors d'un changement
|
||||
chown-help-from = changer le propriétaire et/ou le groupe de chaque fichier seulement si son
|
||||
propriétaire et/ou groupe actuel correspondent à ceux spécifiés ici.
|
||||
L'un ou l'autre peut être omis, auquel cas une correspondance n'est pas requise
|
||||
pour l'attribut omis
|
||||
chown-help-preserve-root = échouer à opérer récursivement sur '/'
|
||||
chown-help-no-preserve-root = ne pas traiter '/' spécialement (par défaut)
|
||||
chown-help-quiet = supprimer la plupart des messages d'erreur
|
||||
chown-help-recursive = opérer sur les fichiers et répertoires récursivement
|
||||
chown-help-reference = utiliser le propriétaire et groupe de RFICHIER plutôt que spécifier les valeurs PROPRIÉTAIRE:GROUPE
|
||||
chown-help-verbose = afficher un diagnostic pour chaque fichier traité
|
||||
|
||||
# Messages d'erreur
|
||||
chown-error-failed-to-get-attributes = échec de l'obtention des attributs de { $file }
|
||||
chown-error-invalid-user = utilisateur invalide : { $user }
|
||||
chown-error-invalid-group = groupe invalide : { $group }
|
||||
chown-error-invalid-spec = spécification invalide : { $spec }
|
|
@ -17,7 +17,8 @@ use clap::{Arg, ArgAction, ArgMatches, Command};
|
|||
use std::fs;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use std::collections::HashMap;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<GidUidOwnerFilter> {
|
||||
let filter = if let Some(spec) = matches.get_one::<String>(options::FROM) {
|
||||
|
@ -35,8 +36,12 @@ fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<GidUidOwnerFilter>
|
|||
let dest_gid: Option<u32>;
|
||||
let raw_owner: String;
|
||||
if let Some(file) = matches.get_one::<String>(options::REFERENCE) {
|
||||
let meta = fs::metadata(file)
|
||||
.map_err_context(|| format!("failed to get attributes of {}", file.quote()))?;
|
||||
let meta = fs::metadata(file).map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"chown-error-failed-to-get-attributes",
|
||||
HashMap::from([("file".to_string(), file.quote().to_string())]),
|
||||
)
|
||||
})?;
|
||||
let gid = meta.gid();
|
||||
let uid = meta.uid();
|
||||
dest_gid = Some(gid);
|
||||
|
@ -84,56 +89,51 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::HELP)
|
||||
.long(options::HELP)
|
||||
.help("Print help information.")
|
||||
.help(get_message("chown-help-print-help"))
|
||||
.action(ArgAction::Help),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::verbosity::CHANGES)
|
||||
.short('c')
|
||||
.long(options::verbosity::CHANGES)
|
||||
.help("like verbose but report only when a change is made")
|
||||
.help(get_message("chown-help-changes"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FROM)
|
||||
.long(options::FROM)
|
||||
.help(
|
||||
"change the owner and/or group of each file only if its \
|
||||
current owner and/or group match those specified here. \
|
||||
Either may be omitted, in which case a match is not required \
|
||||
for the omitted attribute",
|
||||
)
|
||||
.help(get_message("chown-help-from"))
|
||||
.value_name("CURRENT_OWNER:CURRENT_GROUP"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::preserve_root::PRESERVE)
|
||||
.long(options::preserve_root::PRESERVE)
|
||||
.help("fail to operate recursively on '/'")
|
||||
.help(get_message("chown-help-preserve-root"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::preserve_root::NO_PRESERVE)
|
||||
.long(options::preserve_root::NO_PRESERVE)
|
||||
.help("do not treat '/' specially (the default)")
|
||||
.help(get_message("chown-help-no-preserve-root"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::verbosity::QUIET)
|
||||
.long(options::verbosity::QUIET)
|
||||
.help("suppress most error messages")
|
||||
.help(get_message("chown-help-quiet"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::RECURSIVE)
|
||||
.short('R')
|
||||
.long(options::RECURSIVE)
|
||||
.help("operate on files and directories recursively")
|
||||
.help(get_message("chown-help-recursive"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::REFERENCE)
|
||||
.long(options::REFERENCE)
|
||||
.help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
|
||||
.help(get_message("chown-help-reference"))
|
||||
.value_name("RFILE")
|
||||
.value_hint(clap::ValueHint::FilePath)
|
||||
.num_args(1..),
|
||||
|
@ -148,7 +148,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::verbosity::VERBOSE)
|
||||
.long(options::verbosity::VERBOSE)
|
||||
.short('v')
|
||||
.help("output a diagnostic for every file processed")
|
||||
.help(get_message("chown-help-verbose"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
// Add common arguments with chgrp, chown & chmod
|
||||
|
@ -177,7 +177,10 @@ fn parse_uid(user: &str, spec: &str, sep: char) -> UResult<Option<u32>> {
|
|||
Ok(uid) => Ok(Some(uid)),
|
||||
Err(_) => Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid user: {}", spec.quote()),
|
||||
get_message_with_args(
|
||||
"chown-error-invalid-user",
|
||||
HashMap::from([("user".to_string(), spec.quote().to_string())]),
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +199,10 @@ fn parse_gid(group: &str, spec: &str) -> UResult<Option<u32>> {
|
|||
Ok(gid) => Ok(Some(gid)),
|
||||
Err(_) => Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid group: {}", spec.quote()),
|
||||
get_message_with_args(
|
||||
"chown-error-invalid-group",
|
||||
HashMap::from([("group".to_string(), spec.quote().to_string())]),
|
||||
),
|
||||
)),
|
||||
},
|
||||
}
|
||||
|
@ -231,7 +237,10 @@ fn parse_spec(spec: &str, sep: char) -> UResult<(Option<u32>, Option<u32>)> {
|
|||
// we should fail with an error
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid spec: {}", spec.quote()),
|
||||
get_message_with_args(
|
||||
"chown-error-invalid-spec",
|
||||
HashMap::from([("spec".to_string(), spec.quote().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -241,9 +250,15 @@ fn parse_spec(spec: &str, sep: char) -> UResult<(Option<u32>, Option<u32>)> {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::env;
|
||||
use uucore::locale;
|
||||
|
||||
#[test]
|
||||
fn test_parse_spec() {
|
||||
unsafe {
|
||||
env::set_var("LANG", "C");
|
||||
}
|
||||
let _ = locale::setup_localization("chown");
|
||||
assert!(matches!(parse_spec(":", ':'), Ok((None, None))));
|
||||
assert!(matches!(parse_spec(".", ':'), Ok((None, None))));
|
||||
assert!(matches!(parse_spec(".", '.'), Ok((None, None))));
|
||||
|
|
|
@ -21,7 +21,7 @@ path = "src/cp.rs"
|
|||
clap = { workspace = true }
|
||||
filetime = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
linux-raw-sys = { workspace = true }
|
||||
linux-raw-sys = { workspace = true, features = ["ioctl"] }
|
||||
selinux = { workspace = true, optional = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"backup-control",
|
||||
|
|
|
@ -14,4 +14,103 @@ cp-after-help = Do not copy a non-directory that has an existing destination wit
|
|||
|
||||
- all This is the default operation when an --update option is not specified, and results in all existing files in the destination being replaced.
|
||||
- none This is similar to the --no-clobber option, in that no files in the destination are replaced, but also skipping a file does not induce a failure.
|
||||
- older This is the default operation when --update is specified, and results in files being replaced if they’re older than the corresponding source file.
|
||||
- older This is the default operation when --update is specified, and results in files being replaced if they're older than the corresponding source file.
|
||||
|
||||
# Help messages
|
||||
cp-help-target-directory = copy all SOURCE arguments into target-directory
|
||||
cp-help-no-target-directory = Treat DEST as a regular file and not a directory
|
||||
cp-help-interactive = ask before overwriting files
|
||||
cp-help-link = hard-link files instead of copying
|
||||
cp-help-no-clobber = don't overwrite a file that already exists
|
||||
cp-help-recursive = copy directories recursively
|
||||
cp-help-strip-trailing-slashes = remove any trailing slashes from each SOURCE argument
|
||||
cp-help-debug = explain how a file is copied. Implies -v
|
||||
cp-help-verbose = explicitly state what is being done
|
||||
cp-help-symbolic-link = make symbolic links instead of copying
|
||||
cp-help-force = if an existing destination file cannot be opened, remove it and try again (this option is ignored when the -n option is also used). Currently not implemented for Windows.
|
||||
cp-help-remove-destination = remove each existing destination file before attempting to open it (contrast with --force). On Windows, currently only works for writeable files.
|
||||
cp-help-reflink = control clone/CoW copies. See below
|
||||
cp-help-attributes-only = Don't copy the file data, just the attributes
|
||||
cp-help-preserve = Preserve the specified attributes (default: mode, ownership (unix only), timestamps), if possible additional attributes: context, links, xattr, all
|
||||
cp-help-preserve-default = same as --preserve=mode,ownership(unix only),timestamps
|
||||
cp-help-no-preserve = don't preserve the specified attributes
|
||||
cp-help-parents = use full source file name under DIRECTORY
|
||||
cp-help-no-dereference = never follow symbolic links in SOURCE
|
||||
cp-help-dereference = always follow symbolic links in SOURCE
|
||||
cp-help-cli-symbolic-links = follow command-line symbolic links in SOURCE
|
||||
cp-help-archive = Same as -dR --preserve=all
|
||||
cp-help-no-dereference-preserve-links = same as --no-dereference --preserve=links
|
||||
cp-help-one-file-system = stay on this file system
|
||||
cp-help-sparse = control creation of sparse files. See below
|
||||
cp-help-selinux = set SELinux security context of destination file to default type
|
||||
cp-help-context = like -Z, or if CTX is specified then set the SELinux or SMACK security context to CTX
|
||||
cp-help-progress = Display a progress bar. Note: this feature is not supported by GNU coreutils.
|
||||
cp-help-copy-contents = NotImplemented: copy contents of special files when recursive
|
||||
|
||||
# Error messages
|
||||
cp-error-missing-file-operand = missing file operand
|
||||
cp-error-missing-destination-operand = missing destination file operand after { $source }
|
||||
cp-error-extra-operand = extra operand { $operand }
|
||||
cp-error-same-file = { $source } and { $dest } are the same file
|
||||
cp-error-backing-up-destroy-source = backing up { $dest } might destroy source; { $source } not copied
|
||||
cp-error-cannot-open-for-reading = cannot open { $source } for reading
|
||||
cp-error-not-writing-dangling-symlink = not writing through dangling symlink { $dest }
|
||||
cp-error-failed-to-clone = failed to clone { $source } from { $dest }: { $error }
|
||||
cp-error-cannot-change-attribute = cannot change attribute { $dest }: Source file is a non regular file
|
||||
cp-error-cannot-stat = cannot stat { $source }: No such file or directory
|
||||
cp-error-cannot-create-symlink = cannot create symlink { $dest } to { $source }
|
||||
cp-error-cannot-create-hard-link = cannot create hard link { $dest } to { $source }
|
||||
cp-error-omitting-directory = -r not specified; omitting directory { $dir }
|
||||
cp-error-cannot-copy-directory-into-itself = cannot copy a directory, { $source }, into itself, { $dest }
|
||||
cp-error-will-not-copy-through-symlink = will not copy { $source } through just-created symlink { $dest }
|
||||
cp-error-will-not-overwrite-just-created = will not overwrite just-created { $dest } with { $source }
|
||||
cp-error-target-not-directory = target: { $target } is not a directory
|
||||
cp-error-cannot-overwrite-directory-with-non-directory = cannot overwrite directory { $dir } with non-directory
|
||||
cp-error-cannot-overwrite-non-directory-with-directory = cannot overwrite non-directory with directory
|
||||
cp-error-with-parents-dest-must-be-dir = with --parents, the destination must be a directory
|
||||
cp-error-not-replacing = not replacing { $file }
|
||||
cp-error-failed-get-current-dir = failed to get current directory { $error }
|
||||
cp-error-failed-set-permissions = cannot set permissions { $path }
|
||||
cp-error-backup-mutually-exclusive = options --backup and --no-clobber are mutually exclusive
|
||||
cp-error-invalid-argument = invalid argument { $arg } for '{ $option }'
|
||||
cp-error-option-not-implemented = Option '{ $option }' not yet implemented.
|
||||
cp-error-not-all-files-copied = Not all files were copied
|
||||
cp-error-reflink-always-sparse-auto = `--reflink=always` can be used only with --sparse=auto
|
||||
cp-error-file-exists = { $path }: File exists
|
||||
cp-error-invalid-backup-argument = --backup is mutually exclusive with -n or --update=none-fail
|
||||
cp-error-reflink-not-supported = --reflink is only supported on linux and macOS
|
||||
cp-error-sparse-not-supported = --sparse is only supported on linux
|
||||
cp-error-not-a-directory = { $path } is not a directory
|
||||
cp-error-selinux-not-enabled = SELinux was not enabled during the compile time!
|
||||
cp-error-selinux-set-context = failed to set the security context of { $path }: { $error }
|
||||
cp-error-selinux-get-context = failed to get security context of { $path }
|
||||
cp-error-selinux-error = SELinux error: { $error }
|
||||
cp-error-cannot-create-fifo = cannot create fifo { $path }: File exists
|
||||
cp-error-invalid-attribute = invalid attribute { $value }
|
||||
cp-error-failed-to-create-whole-tree = failed to create whole tree
|
||||
cp-error-failed-to-create-directory = Failed to create directory: { $error }
|
||||
cp-error-backup-format = cp: { $error }
|
||||
Try '{ $exec } --help' for more information.
|
||||
|
||||
# Debug enum strings
|
||||
cp-debug-enum-no = no
|
||||
cp-debug-enum-yes = yes
|
||||
cp-debug-enum-avoided = avoided
|
||||
cp-debug-enum-unsupported = unsupported
|
||||
cp-debug-enum-unknown = unknown
|
||||
cp-debug-enum-zeros = zeros
|
||||
cp-debug-enum-seek-hole = SEEK_HOLE
|
||||
cp-debug-enum-seek-hole-zeros = SEEK_HOLE + zeros
|
||||
|
||||
# Warning messages
|
||||
cp-warning-source-specified-more-than-once = source { $file_type } { $source } specified more than once
|
||||
|
||||
# Verbose and debug messages
|
||||
cp-verbose-copied = { $source } -> { $dest }
|
||||
cp-debug-skipped = skipped { $path }
|
||||
cp-verbose-created-directory = { $source } -> { $dest }
|
||||
cp-debug-copy-offload = copy offload: { $offload }, reflink: { $reflink }, sparse detection: { $sparse }
|
||||
|
||||
# Prompts
|
||||
cp-prompt-overwrite = overwrite { $path }?
|
||||
cp-prompt-overwrite-with-mode = replace { $path }, overriding mode
|
||||
|
|
116
src/uu/cp/locales/fr-FR.ftl
Normal file
116
src/uu/cp/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,116 @@
|
|||
cp-about = Copier SOURCE vers DEST, ou plusieurs SOURCE(s) vers RÉPERTOIRE.
|
||||
cp-usage = cp [OPTION]... [-T] SOURCE DEST
|
||||
cp [OPTION]... SOURCE... RÉPERTOIRE
|
||||
cp [OPTION]... -t RÉPERTOIRE SOURCE...
|
||||
cp-after-help = Ne pas copier un non-répertoire qui a une destination existante avec le même horodatage de modification ou plus récent ;
|
||||
à la place, ignorer silencieusement le fichier sans échec. Si les horodatages sont préservés, la comparaison est faite avec
|
||||
l'horodatage source tronqué aux résolutions du système de fichiers de destination et des appels système utilisés pour
|
||||
mettre à jour les horodatages ; cela évite le travail en double si plusieurs commandes cp -pu sont exécutées avec la même source
|
||||
et destination. Cette option est ignorée si l'option -n ou --no-clobber est également spécifiée. De plus, si
|
||||
--preserve=links est également spécifié (comme avec cp -au par exemple), cela aura la priorité ; par conséquent,
|
||||
selon l'ordre dans lequel les fichiers sont traités depuis la source, les fichiers plus récents dans la destination peuvent être remplacés,
|
||||
pour refléter les liens durs dans la source. ce qui donne plus de contrôle sur les fichiers existants dans la destination qui sont
|
||||
remplacés, et sa valeur peut être l'une des suivantes :
|
||||
|
||||
- all C'est l'opération par défaut lorsqu'une option --update n'est pas spécifiée, et entraîne le remplacement de tous les fichiers existants dans la destination.
|
||||
- none Cela est similaire à l'option --no-clobber, en ce sens qu'aucun fichier dans la destination n'est remplacé, mais ignorer un fichier n'induit pas d'échec.
|
||||
- older C'est l'opération par défaut lorsque --update est spécifié, et entraîne le remplacement des fichiers s'ils sont plus anciens que le fichier source correspondant.
|
||||
|
||||
# Messages d'aide
|
||||
cp-help-target-directory = copier tous les arguments SOURCE dans le répertoire cible
|
||||
cp-help-no-target-directory = Traiter DEST comme un fichier régulier et non comme un répertoire
|
||||
cp-help-interactive = demander avant d'écraser les fichiers
|
||||
cp-help-link = créer des liens durs au lieu de copier
|
||||
cp-help-no-clobber = ne pas écraser un fichier qui existe déjà
|
||||
cp-help-recursive = copier les répertoires récursivement
|
||||
cp-help-strip-trailing-slashes = supprimer les barres obliques finales de chaque argument SOURCE
|
||||
cp-help-debug = expliquer comment un fichier est copié. Implique -v
|
||||
cp-help-verbose = indiquer explicitement ce qui est fait
|
||||
cp-help-symbolic-link = créer des liens symboliques au lieu de copier
|
||||
cp-help-force = si un fichier de destination existant ne peut pas être ouvert, le supprimer et réessayer (cette option est ignorée lorsque l'option -n est également utilisée). Actuellement non implémenté pour Windows.
|
||||
cp-help-remove-destination = supprimer chaque fichier de destination existant avant de tenter de l'ouvrir (contraste avec --force). Sur Windows, ne fonctionne actuellement que pour les fichiers inscriptibles.
|
||||
cp-help-reflink = contrôler les copies clone/CoW. Voir ci-dessous
|
||||
cp-help-attributes-only = Ne pas copier les données du fichier, juste les attributs
|
||||
cp-help-preserve = Préserver les attributs spécifiés (par défaut : mode, propriété (unix uniquement), horodatages), si possible attributs supplémentaires : contexte, liens, xattr, all
|
||||
cp-help-preserve-default = identique à --preserve=mode,ownership(unix uniquement),timestamps
|
||||
cp-help-no-preserve = ne pas préserver les attributs spécifiés
|
||||
cp-help-parents = utiliser le nom complet du fichier source sous RÉPERTOIRE
|
||||
cp-help-no-dereference = ne jamais suivre les liens symboliques dans SOURCE
|
||||
cp-help-dereference = toujours suivre les liens symboliques dans SOURCE
|
||||
cp-help-cli-symbolic-links = suivre les liens symboliques de la ligne de commande dans SOURCE
|
||||
cp-help-archive = Identique à -dR --preserve=all
|
||||
cp-help-no-dereference-preserve-links = identique à --no-dereference --preserve=links
|
||||
cp-help-one-file-system = rester sur ce système de fichiers
|
||||
cp-help-sparse = contrôler la création de fichiers épars. Voir ci-dessous
|
||||
cp-help-selinux = définir le contexte de sécurité SELinux du fichier de destination au type par défaut
|
||||
cp-help-context = comme -Z, ou si CTX est spécifié, définir le contexte de sécurité SELinux ou SMACK à CTX
|
||||
cp-help-progress = Afficher une barre de progression. Note : cette fonctionnalité n'est pas supportée par GNU coreutils.
|
||||
cp-help-copy-contents = Non implémenté : copier le contenu des fichiers spéciaux lors de la récursion
|
||||
|
||||
# Messages d'erreur
|
||||
cp-error-missing-file-operand = opérande fichier manquant
|
||||
cp-error-missing-destination-operand = opérande fichier de destination manquant après { $source }
|
||||
cp-error-extra-operand = opérande supplémentaire { $operand }
|
||||
cp-error-same-file = { $source } et { $dest } sont le même fichier
|
||||
cp-error-backing-up-destroy-source = sauvegarder { $dest } pourrait détruire la source ; { $source } non copié
|
||||
cp-error-cannot-open-for-reading = impossible d'ouvrir { $source } en lecture
|
||||
cp-error-not-writing-dangling-symlink = ne pas écrire à travers le lien symbolique pendant { $dest }
|
||||
cp-error-failed-to-clone = échec du clonage de { $source } depuis { $dest } : { $error }
|
||||
cp-error-cannot-change-attribute = impossible de changer l'attribut { $dest } : Le fichier source n'est pas un fichier régulier
|
||||
cp-error-cannot-stat = impossible de faire stat sur { $source } : Aucun fichier ou répertoire de ce type
|
||||
cp-error-cannot-create-symlink = impossible de créer le lien symbolique { $dest } vers { $source }
|
||||
cp-error-cannot-create-hard-link = impossible de créer le lien dur { $dest } vers { $source }
|
||||
cp-error-omitting-directory = -r non spécifié ; répertoire { $dir } omis
|
||||
cp-error-cannot-copy-directory-into-itself = impossible de copier un répertoire, { $source }, dans lui-même, { $dest }
|
||||
cp-error-will-not-copy-through-symlink = ne copiera pas { $source } à travers le lien symbolique tout juste créé { $dest }
|
||||
cp-error-will-not-overwrite-just-created = n'écrasera pas le fichier tout juste créé { $dest } avec { $source }
|
||||
cp-error-target-not-directory = cible : { $target } n'est pas un répertoire
|
||||
cp-error-cannot-overwrite-directory-with-non-directory = impossible d'écraser le répertoire { $dir } avec un non-répertoire
|
||||
cp-error-cannot-overwrite-non-directory-with-directory = impossible d'écraser un non-répertoire avec un répertoire
|
||||
cp-error-with-parents-dest-must-be-dir = avec --parents, la destination doit être un répertoire
|
||||
cp-error-not-replacing = ne remplace pas { $file }
|
||||
cp-error-failed-get-current-dir = échec de l'obtention du répertoire actuel { $error }
|
||||
cp-error-failed-set-permissions = impossible de définir les permissions { $path }
|
||||
cp-error-backup-mutually-exclusive = les options --backup et --no-clobber sont mutuellement exclusives
|
||||
cp-error-invalid-argument = argument invalide { $arg } pour '{ $option }'
|
||||
cp-error-option-not-implemented = Option '{ $option }' pas encore implémentée.
|
||||
cp-error-not-all-files-copied = Tous les fichiers n'ont pas été copiés
|
||||
cp-error-reflink-always-sparse-auto = `--reflink=always` ne peut être utilisé qu'avec --sparse=auto
|
||||
cp-error-file-exists = { $path } : Le fichier existe
|
||||
cp-error-invalid-backup-argument = --backup est mutuellement exclusif avec -n ou --update=none-fail
|
||||
cp-error-reflink-not-supported = --reflink n'est supporté que sur linux et macOS
|
||||
cp-error-sparse-not-supported = --sparse n'est supporté que sur linux
|
||||
cp-error-not-a-directory = { $path } n'est pas un répertoire
|
||||
cp-error-selinux-not-enabled = SELinux n'était pas activé lors de la compilation !
|
||||
cp-error-selinux-set-context = échec de la définition du contexte de sécurité de { $path } : { $error }
|
||||
cp-error-selinux-get-context = échec de l'obtention du contexte de sécurité de { $path }
|
||||
cp-error-selinux-error = Erreur SELinux : { $error }
|
||||
cp-error-cannot-create-fifo = impossible de créer le fifo { $path } : Le fichier existe
|
||||
cp-error-invalid-attribute = attribut invalide { $value }
|
||||
cp-error-failed-to-create-whole-tree = échec de la création de l'arborescence complète
|
||||
cp-error-failed-to-create-directory = Échec de la création du répertoire : { $error }
|
||||
cp-error-backup-format = cp : { $error }
|
||||
Tentez '{ $exec } --help' pour plus d'informations.
|
||||
|
||||
# Debug enum strings
|
||||
cp-debug-enum-no = non
|
||||
cp-debug-enum-yes = oui
|
||||
cp-debug-enum-avoided = évité
|
||||
cp-debug-enum-unsupported = non supporté
|
||||
cp-debug-enum-unknown = inconnu
|
||||
cp-debug-enum-zeros = zéros
|
||||
cp-debug-enum-seek-hole = SEEK_HOLE
|
||||
cp-debug-enum-seek-hole-zeros = SEEK_HOLE + zéros
|
||||
|
||||
# Messages d'avertissement
|
||||
cp-warning-source-specified-more-than-once = { $file_type } source { $source } spécifié plus d'une fois
|
||||
|
||||
# Messages verbeux et de débogage
|
||||
cp-verbose-copied = { $source } -> { $dest }
|
||||
cp-debug-skipped = { $path } ignoré
|
||||
cp-verbose-created-directory = { $source } -> { $dest }
|
||||
cp-debug-copy-offload = copy offload : { $offload }, reflink : { $reflink }, sparse detection : { $sparse }
|
||||
|
||||
# Invites
|
||||
cp-prompt-overwrite = écraser { $path } ?
|
||||
cp-prompt-overwrite-with-mode = remplacer { $path }, en écrasant le mode
|
|
@ -20,6 +20,7 @@ use uucore::error::UIoError;
|
|||
use uucore::fs::{
|
||||
FileInformation, MissingHandling, ResolveMode, canonicalize, path_ends_with_terminator,
|
||||
};
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
use uucore::show;
|
||||
use uucore::show_error;
|
||||
use uucore::uio_error;
|
||||
|
@ -177,7 +178,13 @@ impl Entry {
|
|||
let source_is_dir = source.is_dir();
|
||||
if path_ends_with_terminator(context.target) && source_is_dir {
|
||||
if let Err(e) = fs::create_dir_all(context.target) {
|
||||
eprintln!("Failed to create directory: {e}");
|
||||
eprintln!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"cp-error-failed-to-create-directory",
|
||||
HashMap::from([("error".to_string(), e.to_string())])
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
descendant = descendant.strip_prefix(context.root)?.to_path_buf();
|
||||
|
@ -223,7 +230,7 @@ fn copy_direntry(
|
|||
// exist, ...
|
||||
if source_absolute.is_dir() && !local_to_target.exists() {
|
||||
return if target_is_file {
|
||||
Err("cannot overwrite non-directory with directory".into())
|
||||
Err(get_message("cp-error-cannot-overwrite-non-directory-with-directory").into())
|
||||
} else {
|
||||
build_dir(&local_to_target, false, options, Some(&source_absolute))?;
|
||||
if options.verbose {
|
||||
|
@ -263,8 +270,14 @@ fn copy_direntry(
|
|||
CpError::IoErrContext(e, _) if e.kind() == io::ErrorKind::PermissionDenied => {
|
||||
show!(uio_error!(
|
||||
e,
|
||||
"cannot open {} for reading",
|
||||
source_relative.quote(),
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"cp-error-cannot-open-for-reading",
|
||||
HashMap::from([(
|
||||
"source".to_string(),
|
||||
source_relative.quote().to_string()
|
||||
)])
|
||||
),
|
||||
));
|
||||
}
|
||||
e => return Err(e),
|
||||
|
@ -309,15 +322,24 @@ pub(crate) fn copy_directory(
|
|||
}
|
||||
|
||||
if !options.recursive {
|
||||
return Err(format!("-r not specified; omitting directory {}", root.quote()).into());
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-omitting-directory",
|
||||
HashMap::from([("dir".to_string(), root.quote().to_string())]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
// check if root is a prefix of target
|
||||
if path_has_prefix(target, root)? {
|
||||
return Err(format!(
|
||||
"cannot copy a directory, {}, into itself, {}",
|
||||
root.quote(),
|
||||
target.join(root.file_name().unwrap()).quote()
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-cannot-copy-directory-into-itself",
|
||||
HashMap::from([
|
||||
("source".to_string(), root.quote().to_string()),
|
||||
(
|
||||
"dest".to_string(),
|
||||
target.join(root.file_name().unwrap()).quote().to_string(),
|
||||
),
|
||||
]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
@ -362,7 +384,13 @@ pub(crate) fn copy_directory(
|
|||
// the target directory.
|
||||
let context = match Context::new(root, target) {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(format!("failed to get current directory {e}").into()),
|
||||
Err(e) => {
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-failed-get-current-dir",
|
||||
HashMap::from([("error".to_string(), e.to_string())]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
};
|
||||
|
||||
// The directory we were in during the previous iteration
|
||||
|
|
|
@ -41,7 +41,7 @@ use uucore::{
|
|||
};
|
||||
|
||||
use crate::copydir::copy_directory;
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
mod copydir;
|
||||
mod platform;
|
||||
|
@ -62,7 +62,7 @@ pub enum CpError {
|
|||
|
||||
/// Represents the state when a non-fatal error has occurred
|
||||
/// and not all files were copied.
|
||||
#[error("Not all files were copied")]
|
||||
#[error("{}", get_message("cp-error-not-all-files-copied"))]
|
||||
NotAllFilesCopied,
|
||||
|
||||
/// Simple walkdir::Error wrapper
|
||||
|
@ -80,21 +80,21 @@ pub enum CpError {
|
|||
#[error("Skipped copying file (exit with error = {0})")]
|
||||
Skipped(bool),
|
||||
|
||||
/// Result of a skipped file
|
||||
/// Invalid argument error
|
||||
#[error("{0}")]
|
||||
InvalidArgument(String),
|
||||
|
||||
/// All standard options are included as an an implementation
|
||||
/// path, but those that are not implemented yet should return
|
||||
/// a NotImplemented error.
|
||||
#[error("Option '{0}' not yet implemented.")]
|
||||
#[error("{}", get_message_with_args("cp-error-option-not-implemented", HashMap::from([("option".to_string(), 0.to_string())])))]
|
||||
NotImplemented(String),
|
||||
|
||||
/// Invalid arguments to backup
|
||||
#[error(transparent)]
|
||||
Backup(#[from] BackupError),
|
||||
|
||||
#[error("'{}' is not a directory", .0.display())]
|
||||
#[error("{}", get_message_with_args("cp-error-not-a-directory", HashMap::from([("path".to_string(), .0.quote().to_string())])))]
|
||||
NotADirectory(PathBuf),
|
||||
}
|
||||
|
||||
|
@ -118,9 +118,14 @@ impl Display for BackupError {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"cp: {}\nTry '{} --help' for more information.",
|
||||
self.0,
|
||||
uucore::execution_phrase()
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"cp-error-backup-format",
|
||||
HashMap::from([
|
||||
("error".to_string(), self.0.clone()),
|
||||
("exec".to_string(), uucore::execution_phrase().to_string())
|
||||
])
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -415,28 +420,30 @@ struct CopyDebug {
|
|||
sparse_detection: SparseDebug,
|
||||
}
|
||||
|
||||
impl OffloadReflinkDebug {
|
||||
fn to_string(&self) -> &'static str {
|
||||
match self {
|
||||
Self::No => "no",
|
||||
Self::Yes => "yes",
|
||||
Self::Avoided => "avoided",
|
||||
Self::Unsupported => "unsupported",
|
||||
Self::Unknown => "unknown",
|
||||
}
|
||||
impl Display for OffloadReflinkDebug {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let msg = match self {
|
||||
Self::No => get_message("cp-debug-enum-no"),
|
||||
Self::Yes => get_message("cp-debug-enum-yes"),
|
||||
Self::Avoided => get_message("cp-debug-enum-avoided"),
|
||||
Self::Unsupported => get_message("cp-debug-enum-unsupported"),
|
||||
Self::Unknown => get_message("cp-debug-enum-unknown"),
|
||||
};
|
||||
write!(f, "{}", msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl SparseDebug {
|
||||
fn to_string(&self) -> &'static str {
|
||||
match self {
|
||||
Self::No => "no",
|
||||
Self::Zeros => "zeros",
|
||||
Self::SeekHole => "SEEK_HOLE",
|
||||
Self::SeekHoleZeros => "SEEK_HOLE + zeros",
|
||||
Self::Unsupported => "unsupported",
|
||||
Self::Unknown => "unknown",
|
||||
}
|
||||
impl Display for SparseDebug {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let msg = match self {
|
||||
Self::No => get_message("cp-debug-enum-no"),
|
||||
Self::Zeros => get_message("cp-debug-enum-zeros"),
|
||||
Self::SeekHole => get_message("cp-debug-enum-seek-hole"),
|
||||
Self::SeekHoleZeros => get_message("cp-debug-enum-seek-hole-zeros"),
|
||||
Self::Unsupported => get_message("cp-debug-enum-unsupported"),
|
||||
Self::Unknown => get_message("cp-debug-enum-unknown"),
|
||||
};
|
||||
write!(f, "{}", msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,10 +452,18 @@ impl SparseDebug {
|
|||
/// It prints the debug information of the offload, reflink, and sparse detection actions.
|
||||
fn show_debug(copy_debug: &CopyDebug) {
|
||||
println!(
|
||||
"copy offload: {}, reflink: {}, sparse detection: {}",
|
||||
copy_debug.offload.to_string(),
|
||||
copy_debug.reflink.to_string(),
|
||||
copy_debug.sparse_detection.to_string(),
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"cp-debug-copy-offload",
|
||||
HashMap::from([
|
||||
("offload".to_string(), copy_debug.offload.to_string()),
|
||||
("reflink".to_string(), copy_debug.reflink.to_string()),
|
||||
(
|
||||
"sparse".to_string(),
|
||||
copy_debug.sparse_detection.to_string()
|
||||
),
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -537,14 +552,14 @@ pub fn uu_app() -> Command {
|
|||
.value_name(options::TARGET_DIRECTORY)
|
||||
.value_hint(clap::ValueHint::DirPath)
|
||||
.value_parser(ValueParser::path_buf())
|
||||
.help("copy all SOURCE arguments into target-directory"),
|
||||
.help(get_message("cp-help-target-directory")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NO_TARGET_DIRECTORY)
|
||||
.short('T')
|
||||
.long(options::NO_TARGET_DIRECTORY)
|
||||
.conflicts_with(options::TARGET_DIRECTORY)
|
||||
.help("Treat DEST as a regular file and not a directory")
|
||||
.help(get_message("cp-help-no-target-directory"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -552,7 +567,7 @@ pub fn uu_app() -> Command {
|
|||
.short('i')
|
||||
.long(options::INTERACTIVE)
|
||||
.overrides_with(options::NO_CLOBBER)
|
||||
.help("ask before overwriting files")
|
||||
.help(get_message("cp-help-interactive"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -560,7 +575,7 @@ pub fn uu_app() -> Command {
|
|||
.short('l')
|
||||
.long(options::LINK)
|
||||
.overrides_with_all(MODE_ARGS)
|
||||
.help("hard-link files instead of copying")
|
||||
.help(get_message("cp-help-link"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -568,7 +583,7 @@ pub fn uu_app() -> Command {
|
|||
.short('n')
|
||||
.long(options::NO_CLOBBER)
|
||||
.overrides_with(options::INTERACTIVE)
|
||||
.help("don't overwrite a file that already exists")
|
||||
.help(get_message("cp-help-no-clobber"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -577,26 +592,26 @@ pub fn uu_app() -> Command {
|
|||
.visible_short_alias('r')
|
||||
.long(options::RECURSIVE)
|
||||
// --archive sets this option
|
||||
.help("copy directories recursively")
|
||||
.help(get_message("cp-help-recursive"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::STRIP_TRAILING_SLASHES)
|
||||
.long(options::STRIP_TRAILING_SLASHES)
|
||||
.help("remove any trailing slashes from each SOURCE argument")
|
||||
.help(get_message("cp-help-strip-trailing-slashes"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DEBUG)
|
||||
.long(options::DEBUG)
|
||||
.help("explain how a file is copied. Implies -v")
|
||||
.help(get_message("cp-help-debug"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::VERBOSE)
|
||||
.short('v')
|
||||
.long(options::VERBOSE)
|
||||
.help("explicitly state what is being done")
|
||||
.help(get_message("cp-help-verbose"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -604,29 +619,21 @@ pub fn uu_app() -> Command {
|
|||
.short('s')
|
||||
.long(options::SYMBOLIC_LINK)
|
||||
.overrides_with_all(MODE_ARGS)
|
||||
.help("make symbolic links instead of copying")
|
||||
.help(get_message("cp-help-symbolic-link"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FORCE)
|
||||
.short('f')
|
||||
.long(options::FORCE)
|
||||
.help(
|
||||
"if an existing destination file cannot be opened, remove it and \
|
||||
try again (this option is ignored when the -n option is also used). \
|
||||
Currently not implemented for Windows.",
|
||||
)
|
||||
.help(get_message("cp-help-force"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::REMOVE_DESTINATION)
|
||||
.long(options::REMOVE_DESTINATION)
|
||||
.overrides_with(options::FORCE)
|
||||
.help(
|
||||
"remove each existing destination file before attempting to open it \
|
||||
(contrast with --force). On Windows, currently only works for \
|
||||
writeable files.",
|
||||
)
|
||||
.help(get_message("cp-help-remove-destination"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(backup_control::arguments::backup())
|
||||
|
@ -643,13 +650,13 @@ pub fn uu_app() -> Command {
|
|||
.default_missing_value("always")
|
||||
.value_parser(ShortcutValueParser::new(["auto", "always", "never"]))
|
||||
.num_args(0..=1)
|
||||
.help("control clone/CoW copies. See below"),
|
||||
.help(get_message("cp-help-reflink")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ATTRIBUTES_ONLY)
|
||||
.long(options::ATTRIBUTES_ONLY)
|
||||
.overrides_with_all(MODE_ARGS)
|
||||
.help("Don't copy the file data, just the attributes")
|
||||
.help(get_message("cp-help-attributes-only"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -664,16 +671,13 @@ pub fn uu_app() -> Command {
|
|||
.default_missing_value(PRESERVE_DEFAULT_VALUES)
|
||||
// -d sets this option
|
||||
// --archive sets this option
|
||||
.help(
|
||||
"Preserve the specified attributes (default: mode, ownership (unix only), \
|
||||
timestamps), if possible additional attributes: context, links, xattr, all",
|
||||
),
|
||||
.help(get_message("cp-help-preserve")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PRESERVE_DEFAULT_ATTRIBUTES)
|
||||
.short('p')
|
||||
.long(options::PRESERVE_DEFAULT_ATTRIBUTES)
|
||||
.help("same as --preserve=mode,ownership(unix only),timestamps")
|
||||
.help(get_message("cp-help-preserve-default"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -685,13 +689,13 @@ pub fn uu_app() -> Command {
|
|||
.num_args(0..)
|
||||
.require_equals(true)
|
||||
.value_name("ATTR_LIST")
|
||||
.help("don't preserve the specified attributes"),
|
||||
.help(get_message("cp-help-no-preserve")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PARENTS)
|
||||
.long(options::PARENTS)
|
||||
.alias(options::PARENT)
|
||||
.help("use full source file name under DIRECTORY")
|
||||
.help(get_message("cp-help-parents"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -700,7 +704,7 @@ pub fn uu_app() -> Command {
|
|||
.long(options::NO_DEREFERENCE)
|
||||
.overrides_with(options::DEREFERENCE)
|
||||
// -d sets this option
|
||||
.help("never follow symbolic links in SOURCE")
|
||||
.help(get_message("cp-help-no-dereference"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -708,33 +712,33 @@ pub fn uu_app() -> Command {
|
|||
.short('L')
|
||||
.long(options::DEREFERENCE)
|
||||
.overrides_with(options::NO_DEREFERENCE)
|
||||
.help("always follow symbolic links in SOURCE")
|
||||
.help(get_message("cp-help-dereference"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::CLI_SYMBOLIC_LINKS)
|
||||
.short('H')
|
||||
.help("follow command-line symbolic links in SOURCE")
|
||||
.help(get_message("cp-help-cli-symbolic-links"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ARCHIVE)
|
||||
.short('a')
|
||||
.long(options::ARCHIVE)
|
||||
.help("Same as -dR --preserve=all")
|
||||
.help(get_message("cp-help-archive"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NO_DEREFERENCE_PRESERVE_LINKS)
|
||||
.short('d')
|
||||
.help("same as --no-dereference --preserve=links")
|
||||
.help(get_message("cp-help-no-dereference-preserve-links"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ONE_FILE_SYSTEM)
|
||||
.short('x')
|
||||
.long(options::ONE_FILE_SYSTEM)
|
||||
.help("stay on this file system")
|
||||
.help(get_message("cp-help-one-file-system"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -742,12 +746,12 @@ pub fn uu_app() -> Command {
|
|||
.long(options::SPARSE)
|
||||
.value_name("WHEN")
|
||||
.value_parser(ShortcutValueParser::new(["never", "auto", "always"]))
|
||||
.help("control creation of sparse files. See below"),
|
||||
.help(get_message("cp-help-sparse")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SELINUX)
|
||||
.short('Z')
|
||||
.help("set SELinux security context of destination file to default type")
|
||||
.help(get_message("cp-help-selinux"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -755,10 +759,7 @@ pub fn uu_app() -> Command {
|
|||
.long(options::CONTEXT)
|
||||
.value_name("CTX")
|
||||
.value_parser(value_parser!(String))
|
||||
.help(
|
||||
"like -Z, or if CTX is specified then set the SELinux or SMACK security \
|
||||
context to CTX",
|
||||
)
|
||||
.help(get_message("cp-help-context"))
|
||||
.num_args(0..=1)
|
||||
.require_equals(true)
|
||||
.default_missing_value(""),
|
||||
|
@ -770,17 +771,14 @@ pub fn uu_app() -> Command {
|
|||
.long(options::PROGRESS_BAR)
|
||||
.short('g')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(
|
||||
"Display a progress bar. \n\
|
||||
Note: this feature is not supported by GNU coreutils.",
|
||||
),
|
||||
.help(get_message("cp-help-progress")),
|
||||
)
|
||||
// TODO: implement the following args
|
||||
.arg(
|
||||
Arg::new(options::COPY_CONTENTS)
|
||||
.long(options::COPY_CONTENTS)
|
||||
.overrides_with(options::ATTRIBUTES_ONLY)
|
||||
.help("NotImplemented: copy contents of special files when recursive")
|
||||
.help(get_message("cp-help-copy-contents"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
// END TODO
|
||||
|
@ -803,7 +801,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if options.overwrite == OverwriteMode::NoClobber && options.backup != BackupMode::None {
|
||||
return Err(UUsageError::new(
|
||||
EXIT_ERR,
|
||||
"options --backup and --no-clobber are mutually exclusive",
|
||||
get_message("cp-error-backup-mutually-exclusive"),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -984,9 +982,9 @@ impl Attributes {
|
|||
"link" | "links" => &mut new.links,
|
||||
"xattr" => &mut new.xattr,
|
||||
_ => {
|
||||
return Err(CpError::InvalidArgument(format!(
|
||||
"invalid attribute {}",
|
||||
value.quote()
|
||||
return Err(CpError::InvalidArgument(get_message_with_args(
|
||||
"cp-error-invalid-attribute",
|
||||
HashMap::from([("value".to_string(), value.quote().to_string())]),
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
@ -1030,7 +1028,7 @@ impl Options {
|
|||
.is_some_and(|v| v == "none" || v == "none-fail")
|
||||
{
|
||||
return Err(CpError::InvalidArgument(
|
||||
"--backup is mutually exclusive with -n or --update=none-fail".to_string(),
|
||||
get_message("cp-error-invalid-backup-argument").to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -1134,7 +1132,7 @@ impl Options {
|
|||
#[cfg(not(feature = "selinux"))]
|
||||
if let Preserve::Yes { required } = attributes.context {
|
||||
let selinux_disabled_error =
|
||||
CpError::Error("SELinux was not enabled during the compile time!".to_owned());
|
||||
CpError::Error(get_message("cp-error-selinux-not-enabled"));
|
||||
if required {
|
||||
return Err(selinux_disabled_error);
|
||||
}
|
||||
|
@ -1176,9 +1174,12 @@ impl Options {
|
|||
"auto" => ReflinkMode::Auto,
|
||||
"never" => ReflinkMode::Never,
|
||||
value => {
|
||||
return Err(CpError::InvalidArgument(format!(
|
||||
"invalid argument {} for \'reflink\'",
|
||||
value.quote()
|
||||
return Err(CpError::InvalidArgument(get_message_with_args(
|
||||
"cp-error-invalid-argument",
|
||||
HashMap::from([
|
||||
("arg".to_string(), value.quote().to_string()),
|
||||
("option".to_string(), "reflink".to_string()),
|
||||
]),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
@ -1193,8 +1194,12 @@ impl Options {
|
|||
"auto" => SparseMode::Auto,
|
||||
"never" => SparseMode::Never,
|
||||
_ => {
|
||||
return Err(CpError::InvalidArgument(format!(
|
||||
"invalid argument {val} for \'sparse\'"
|
||||
return Err(CpError::InvalidArgument(get_message_with_args(
|
||||
"cp-error-invalid-argument",
|
||||
HashMap::from([
|
||||
("arg".to_string(), val.to_string()),
|
||||
("option".to_string(), "sparse".to_string()),
|
||||
]),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
@ -1269,12 +1274,15 @@ fn parse_path_args(
|
|||
) -> CopyResult<(Vec<PathBuf>, PathBuf)> {
|
||||
if paths.is_empty() {
|
||||
// No files specified
|
||||
return Err("missing file operand".into());
|
||||
return Err(get_message("cp-error-missing-file-operand").into());
|
||||
} else if paths.len() == 1 && options.target_dir.is_none() {
|
||||
// Only one file specified
|
||||
return Err(format!(
|
||||
"missing destination file operand after {}",
|
||||
paths[0].display().to_string().quote()
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-missing-destination-operand",
|
||||
HashMap::from([(
|
||||
"source".to_string(),
|
||||
paths[0].display().to_string().quote().to_string(),
|
||||
)]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
@ -1282,7 +1290,14 @@ fn parse_path_args(
|
|||
// Return an error if the user requested to copy more than one
|
||||
// file source to a file target
|
||||
if options.no_target_dir && options.target_dir.is_none() && paths.len() > 2 {
|
||||
return Err(format!("extra operand {:}", paths[2].display().to_string().quote()).into());
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-extra-operand",
|
||||
HashMap::from([(
|
||||
"operand".to_string(),
|
||||
paths[2].display().to_string().quote().to_string(),
|
||||
)]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let target = match options.target_dir {
|
||||
|
@ -1377,10 +1392,14 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult
|
|||
} else {
|
||||
"file"
|
||||
};
|
||||
show_warning!(
|
||||
"source {file_type} {} specified more than once",
|
||||
source.quote()
|
||||
let msg = get_message_with_args(
|
||||
"cp-warning-source-specified-more-than-once",
|
||||
HashMap::from([
|
||||
("file_type".to_string(), file_type.to_string()),
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
]),
|
||||
);
|
||||
show_warning!("{}", msg);
|
||||
} else {
|
||||
let dest = construct_dest_path(source, target, target_type, options)
|
||||
.unwrap_or_else(|_| target.to_path_buf());
|
||||
|
@ -1395,10 +1414,12 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult
|
|||
// There is already a file and it isn't a symlink (managed in a different place)
|
||||
if copied_destinations.contains(&dest) && options.backup != BackupMode::Numbered {
|
||||
// If the target file was already created in this cp call, do not overwrite
|
||||
return Err(CpError::Error(format!(
|
||||
"will not overwrite just-created '{}' with '{}'",
|
||||
dest.display(),
|
||||
source.display()
|
||||
return Err(CpError::Error(get_message_with_args(
|
||||
"cp-error-will-not-overwrite-just-created",
|
||||
HashMap::from([
|
||||
("dest".to_string(), dest.quote().to_string()),
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
]),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
@ -1442,15 +1463,15 @@ fn construct_dest_path(
|
|||
options: &Options,
|
||||
) -> CopyResult<PathBuf> {
|
||||
if options.no_target_dir && target.is_dir() {
|
||||
return Err(format!(
|
||||
"cannot overwrite directory {} with non-directory",
|
||||
target.quote()
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-cannot-overwrite-directory-with-non-directory",
|
||||
HashMap::from([("dir".to_string(), target.quote().to_string())]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if options.parents && !target.is_dir() {
|
||||
return Err("with --parents, the destination must be a directory".into());
|
||||
return Err(get_message("cp-error-with-parents-dest-must-be-dir").into());
|
||||
}
|
||||
|
||||
Ok(match target_type {
|
||||
|
@ -1575,7 +1596,13 @@ impl OverwriteMode {
|
|||
match *self {
|
||||
Self::NoClobber => {
|
||||
if debug {
|
||||
println!("skipped {}", path.quote());
|
||||
println!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"cp-debug-skipped",
|
||||
HashMap::from([("path".to_string(), path.quote().to_string())])
|
||||
)
|
||||
);
|
||||
}
|
||||
Err(CpError::Skipped(false))
|
||||
}
|
||||
|
@ -1583,12 +1610,17 @@ impl OverwriteMode {
|
|||
let prompt_yes_result = if let Some((octal, human_readable)) =
|
||||
file_mode_for_interactive_overwrite(path)
|
||||
{
|
||||
prompt_yes!(
|
||||
"replace {}, overriding mode {octal} ({human_readable})?",
|
||||
path.quote()
|
||||
)
|
||||
let prompt_msg = get_message_with_args(
|
||||
"cp-prompt-overwrite-with-mode",
|
||||
HashMap::from([("path".to_string(), path.quote().to_string())]),
|
||||
);
|
||||
prompt_yes!("{} {octal} ({human_readable})?", prompt_msg)
|
||||
} else {
|
||||
prompt_yes!("overwrite {}?", path.quote())
|
||||
let prompt_msg = get_message_with_args(
|
||||
"cp-prompt-overwrite",
|
||||
HashMap::from([("path".to_string(), path.quote().to_string())]),
|
||||
);
|
||||
prompt_yes!("{}", prompt_msg)
|
||||
};
|
||||
|
||||
if prompt_yes_result {
|
||||
|
@ -1621,8 +1653,8 @@ fn handle_preserve<F: Fn() -> CopyResult<()>>(p: &Preserve, f: F) -> CopyResult<
|
|||
}
|
||||
|
||||
/// Copies extended attributes (xattrs) from `source` to `dest`, ensuring that `dest` is temporarily
|
||||
/// user-writable if needed and restoring its original permissions afterward. This avoids “Operation
|
||||
/// not permitted” errors on read-only files. Returns an error if permission or metadata operations fail,
|
||||
/// user-writable if needed and restoring its original permissions afterward. This avoids "Operation
|
||||
/// not permitted" errors on read-only files. Returns an error if permission or metadata operations fail,
|
||||
/// or if xattr copying fails.
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
fn copy_extended_attrs(source: &Path, dest: &Path) -> CopyResult<()> {
|
||||
|
@ -1730,16 +1762,19 @@ pub(crate) fn copy_attributes(
|
|||
if let Ok(context) = selinux::SecurityContext::of_path(source, false, false) {
|
||||
if let Some(context) = context {
|
||||
if let Err(e) = context.set_for_path(dest, false, false) {
|
||||
return Err(CpError::Error(format!(
|
||||
"failed to set the security context of {}: {e}",
|
||||
dest.display()
|
||||
return Err(CpError::Error(get_message_with_args(
|
||||
"cp-error-selinux-set-context",
|
||||
HashMap::from([
|
||||
("path".to_string(), dest.display().to_string()),
|
||||
("error".to_string(), e.to_string()),
|
||||
]),
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(CpError::Error(format!(
|
||||
"failed to get security context of {}",
|
||||
source.display()
|
||||
return Err(CpError::Error(get_message_with_args(
|
||||
"cp-error-selinux-get-context",
|
||||
HashMap::from([("path".to_string(), source.display().to_string())]),
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
|
@ -1780,10 +1815,24 @@ fn symlink_file(
|
|||
std::os::unix::fs::symlink(source, dest).map_err(|e| {
|
||||
CpError::IoErrContext(
|
||||
e,
|
||||
format!(
|
||||
"cannot create symlink {} to {}",
|
||||
get_filename(dest).unwrap_or("invalid file name").quote(),
|
||||
get_filename(source).unwrap_or("invalid file name").quote()
|
||||
get_message_with_args(
|
||||
"cp-error-cannot-create-symlink",
|
||||
HashMap::from([
|
||||
(
|
||||
"dest".to_string(),
|
||||
get_filename(dest)
|
||||
.unwrap_or("invalid file name")
|
||||
.quote()
|
||||
.to_string(),
|
||||
),
|
||||
(
|
||||
"source".to_string(),
|
||||
get_filename(source)
|
||||
.unwrap_or("invalid file name")
|
||||
.quote()
|
||||
.to_string(),
|
||||
),
|
||||
]),
|
||||
),
|
||||
)
|
||||
})?;
|
||||
|
@ -1793,10 +1842,24 @@ fn symlink_file(
|
|||
std::os::windows::fs::symlink_file(source, dest).map_err(|e| {
|
||||
CpError::IoErrContext(
|
||||
e,
|
||||
format!(
|
||||
"cannot create symlink {} to {}",
|
||||
get_filename(dest).unwrap_or("invalid file name").quote(),
|
||||
get_filename(source).unwrap_or("invalid file name").quote()
|
||||
get_message_with_args(
|
||||
"cp-error-cannot-create-symlink",
|
||||
HashMap::from([
|
||||
(
|
||||
"dest".to_string(),
|
||||
get_filename(dest)
|
||||
.unwrap_or("invalid file name")
|
||||
.quote()
|
||||
.to_string(),
|
||||
),
|
||||
(
|
||||
"source".to_string(),
|
||||
get_filename(source)
|
||||
.unwrap_or("invalid file name")
|
||||
.quote()
|
||||
.to_string(),
|
||||
),
|
||||
]),
|
||||
),
|
||||
)
|
||||
})?;
|
||||
|
@ -1887,7 +1950,14 @@ fn handle_existing_dest(
|
|||
// Disallow copying a file to itself, unless `--force` and
|
||||
// `--backup` are both specified.
|
||||
if is_forbidden_to_copy_to_same_file(source, dest, options, source_in_command_line) {
|
||||
return Err(format!("{} and {} are the same file", source.quote(), dest.quote()).into());
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-same-file",
|
||||
HashMap::from([
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
("dest".to_string(), dest.quote().to_string()),
|
||||
]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if options.update == UpdateMode::None {
|
||||
|
@ -1905,10 +1975,12 @@ fn handle_existing_dest(
|
|||
let backup_path = backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
|
||||
if let Some(backup_path) = backup_path {
|
||||
if paths_refer_to_same_file(source, &backup_path, true) {
|
||||
return Err(format!(
|
||||
"backing up {} might destroy source; {} not copied",
|
||||
dest.quote(),
|
||||
source.quote()
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-backing-up-destroy-source",
|
||||
HashMap::from([
|
||||
("dest".to_string(), dest.quote().to_string()),
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
@ -2063,7 +2135,16 @@ fn print_paths(parents: bool, source: &Path, dest: &Path) {
|
|||
// a/b -> d/a/b
|
||||
//
|
||||
for (x, y) in aligned_ancestors(source, dest) {
|
||||
println!("{} -> {}", x.display(), y.display());
|
||||
println!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"cp-verbose-created-directory",
|
||||
HashMap::from([
|
||||
("source".to_string(), x.display().to_string()),
|
||||
("dest".to_string(), y.display().to_string())
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2117,10 +2198,24 @@ fn handle_copy_mode(
|
|||
.map_err(|e| {
|
||||
CpError::IoErrContext(
|
||||
e,
|
||||
format!(
|
||||
"cannot create hard link {} to {}",
|
||||
get_filename(dest).unwrap_or("invalid file name").quote(),
|
||||
get_filename(source).unwrap_or("invalid file name").quote()
|
||||
get_message_with_args(
|
||||
"cp-error-cannot-create-hard-link",
|
||||
HashMap::from([
|
||||
(
|
||||
"dest".to_string(),
|
||||
get_filename(dest)
|
||||
.unwrap_or("invalid file name")
|
||||
.quote()
|
||||
.to_string(),
|
||||
),
|
||||
(
|
||||
"source".to_string(),
|
||||
get_filename(source)
|
||||
.unwrap_or("invalid file name")
|
||||
.quote()
|
||||
.to_string(),
|
||||
),
|
||||
]),
|
||||
),
|
||||
)
|
||||
})?;
|
||||
|
@ -2168,9 +2263,9 @@ fn handle_copy_mode(
|
|||
return Ok(PerformedAction::Skipped);
|
||||
}
|
||||
UpdateMode::NoneFail => {
|
||||
return Err(CpError::Error(format!(
|
||||
"not replacing '{}'",
|
||||
dest.display()
|
||||
return Err(CpError::Error(get_message_with_args(
|
||||
"cp-error-not-replacing",
|
||||
HashMap::from([("file".to_string(), dest.quote().to_string())]),
|
||||
)));
|
||||
}
|
||||
UpdateMode::IfOlder => {
|
||||
|
@ -2296,20 +2391,24 @@ fn copy_file(
|
|||
.map(|info| symlinked_files.contains(&info))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return Err(CpError::Error(format!(
|
||||
"will not copy '{}' through just-created symlink '{}'",
|
||||
source.display(),
|
||||
dest.display()
|
||||
return Err(CpError::Error(get_message_with_args(
|
||||
"cp-error-will-not-copy-through-symlink",
|
||||
HashMap::from([
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
("dest".to_string(), dest.quote().to_string()),
|
||||
]),
|
||||
)));
|
||||
}
|
||||
// Fail if cp tries to copy two sources of the same name into a single symlink
|
||||
// Example: "cp file1 dir1/file1 tmp" where "tmp" is a directory containing a symlink "file1" pointing to a file named "foo".
|
||||
// foo will contain the contents of "file1" and "dir1/file1" will not be copied over to "tmp/file1"
|
||||
if copied_destinations.contains(dest) {
|
||||
return Err(CpError::Error(format!(
|
||||
"will not copy '{}' through just-created symlink '{}'",
|
||||
source.display(),
|
||||
dest.display()
|
||||
return Err(CpError::Error(get_message_with_args(
|
||||
"cp-error-will-not-copy-through-symlink",
|
||||
HashMap::from([
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
("dest".to_string(), dest.quote().to_string()),
|
||||
]),
|
||||
)));
|
||||
}
|
||||
|
||||
|
@ -2323,9 +2422,9 @@ fn copy_file(
|
|||
&& !is_symlink_loop(dest)
|
||||
&& std::env::var_os("POSIXLY_CORRECT").is_none()
|
||||
{
|
||||
return Err(CpError::Error(format!(
|
||||
"not writing through dangling symlink '{}'",
|
||||
dest.display()
|
||||
return Err(CpError::Error(get_message_with_args(
|
||||
"cp-error-not-writing-dangling-symlink",
|
||||
HashMap::from([("dest".to_string(), dest.quote().to_string())]),
|
||||
)));
|
||||
}
|
||||
if paths_refer_to_same_file(source, dest, true)
|
||||
|
@ -2392,9 +2491,9 @@ fn copy_file(
|
|||
OverwriteMode::Clobber(ClobberMode::RemoveDestination)
|
||||
)
|
||||
{
|
||||
return Err(format!(
|
||||
"cannot change attribute {}: Source file is a non regular file",
|
||||
dest.quote()
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-cannot-change-attribute",
|
||||
HashMap::from([("dest".to_string(), dest.quote().to_string())]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
@ -2430,7 +2529,10 @@ fn copy_file(
|
|||
// this is just for gnu tests compatibility
|
||||
result.map_err(|err| {
|
||||
if err.to_string().contains("No such file or directory") {
|
||||
return format!("cannot stat {}: No such file or directory", source.quote());
|
||||
return get_message_with_args(
|
||||
"cp-error-cannot-stat",
|
||||
HashMap::from([("source".to_string(), source.quote().to_string())]),
|
||||
);
|
||||
}
|
||||
err.to_string()
|
||||
})?
|
||||
|
@ -2499,7 +2601,10 @@ fn copy_file(
|
|||
if let Err(e) =
|
||||
uucore::selinux::set_selinux_security_context(dest, options.context.as_ref())
|
||||
{
|
||||
return Err(CpError::Error(format!("SELinux error: {}", e)));
|
||||
return Err(CpError::Error(get_message_with_args(
|
||||
"cp-error-selinux-error",
|
||||
HashMap::from([("error".to_string(), e.to_string())]),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2617,7 +2722,13 @@ fn copy_fifo(dest: &Path, overwrite: OverwriteMode, debug: bool) -> CopyResult<(
|
|||
fs::remove_file(dest)?;
|
||||
}
|
||||
|
||||
make_fifo(dest).map_err(|_| format!("cannot create fifo {}: File exists", dest.quote()).into())
|
||||
make_fifo(dest).map_err(|_| {
|
||||
get_message_with_args(
|
||||
"cp-error-cannot-create-fifo",
|
||||
HashMap::from([("path".to_string(), dest.quote().to_string())]),
|
||||
)
|
||||
.into()
|
||||
})
|
||||
}
|
||||
|
||||
fn copy_link(
|
||||
|
@ -2638,12 +2749,14 @@ fn copy_link(
|
|||
/// Generate an error message if `target` is not the correct `target_type`
|
||||
pub fn verify_target_type(target: &Path, target_type: &TargetType) -> CopyResult<()> {
|
||||
match (target_type, target.is_dir()) {
|
||||
(&TargetType::Directory, false) => {
|
||||
Err(format!("target: {} is not a directory", target.quote()).into())
|
||||
}
|
||||
(&TargetType::File, true) => Err(format!(
|
||||
"cannot overwrite directory {} with non-directory",
|
||||
target.quote()
|
||||
(&TargetType::Directory, false) => Err(get_message_with_args(
|
||||
"cp-error-target-not-directory",
|
||||
HashMap::from([("target".to_string(), target.quote().to_string())]),
|
||||
)
|
||||
.into()),
|
||||
(&TargetType::File, true) => Err(get_message_with_args(
|
||||
"cp-error-cannot-overwrite-directory-with-non-directory",
|
||||
HashMap::from([("dir".to_string(), target.quote().to_string())]),
|
||||
)
|
||||
.into()),
|
||||
_ => Ok(()),
|
||||
|
|
|
@ -13,7 +13,7 @@ use std::os::unix::fs::{FileTypeExt, OpenOptionsExt};
|
|||
use std::os::unix::io::AsRawFd;
|
||||
use std::path::Path;
|
||||
use uucore::buf_copy;
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use uucore::mode::get_umask;
|
||||
|
||||
use crate::{
|
||||
|
@ -401,7 +401,7 @@ pub(crate) fn copy_on_write(
|
|||
clone(source, dest, CloneFallback::Error)
|
||||
}
|
||||
(ReflinkMode::Always, _) => {
|
||||
return Err("`--reflink=always` can be used only with --sparse=auto".into());
|
||||
return Err(get_message("cp-error-reflink-always-sparse-auto").into());
|
||||
}
|
||||
};
|
||||
result.map_err(|e| CpError::IoErrContext(e, context.to_owned()))?;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
// spell-checker:ignore reflink
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
@ -10,6 +11,7 @@ use std::os::unix::fs::OpenOptionsExt;
|
|||
use std::path::Path;
|
||||
|
||||
use uucore::buf_copy;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
use uucore::mode::get_umask;
|
||||
|
||||
use crate::{
|
||||
|
@ -30,7 +32,9 @@ pub(crate) fn copy_on_write(
|
|||
source_is_stream: bool,
|
||||
) -> CopyResult<CopyDebug> {
|
||||
if sparse_mode != SparseMode::Auto {
|
||||
return Err("--sparse is only supported on linux".to_string().into());
|
||||
return Err(get_message("cp-error-sparse-not-supported")
|
||||
.to_string()
|
||||
.into());
|
||||
}
|
||||
let mut copy_debug = CopyDebug {
|
||||
offload: OffloadReflinkDebug::Unknown,
|
||||
|
@ -85,10 +89,13 @@ pub(crate) fn copy_on_write(
|
|||
// support COW).
|
||||
match reflink_mode {
|
||||
ReflinkMode::Always => {
|
||||
return Err(format!(
|
||||
"failed to clone {} from {}: {error}",
|
||||
source.display(),
|
||||
dest.display()
|
||||
return Err(get_message_with_args(
|
||||
"cp-error-failed-to-clone",
|
||||
HashMap::from([
|
||||
("source".to_string(), source.display().to_string()),
|
||||
("dest".to_string(), dest.display().to_string()),
|
||||
("error".to_string(), error.to_string()),
|
||||
]),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// spell-checker:ignore reflink
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use uucore::locale::get_message;
|
||||
|
||||
use crate::{
|
||||
CopyDebug, CopyResult, CpError, OffloadReflinkDebug, ReflinkMode, SparseDebug, SparseMode,
|
||||
|
@ -19,12 +20,14 @@ pub(crate) fn copy_on_write(
|
|||
context: &str,
|
||||
) -> CopyResult<CopyDebug> {
|
||||
if reflink_mode != ReflinkMode::Never {
|
||||
return Err("--reflink is only supported on linux and macOS"
|
||||
return Err(get_message("cp-error-reflink-not-supported")
|
||||
.to_string()
|
||||
.into());
|
||||
}
|
||||
if sparse_mode != SparseMode::Auto {
|
||||
return Err("--sparse is only supported on linux".to_string().into());
|
||||
return Err(get_message("cp-error-sparse-not-supported")
|
||||
.to_string()
|
||||
.into());
|
||||
}
|
||||
let copy_debug = CopyDebug {
|
||||
offload: OffloadReflinkDebug::Unsupported,
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::os::unix::fs::OpenOptionsExt;
|
|||
use std::path::Path;
|
||||
|
||||
use uucore::buf_copy;
|
||||
use uucore::locale::get_message;
|
||||
use uucore::mode::get_umask;
|
||||
|
||||
use crate::{
|
||||
|
@ -25,12 +26,14 @@ pub(crate) fn copy_on_write(
|
|||
source_is_stream: bool,
|
||||
) -> CopyResult<CopyDebug> {
|
||||
if reflink_mode != ReflinkMode::Never {
|
||||
return Err("--reflink is only supported on linux and macOS"
|
||||
return Err(get_message("cp-error-reflink-not-supported")
|
||||
.to_string()
|
||||
.into());
|
||||
}
|
||||
if sparse_mode != SparseMode::Auto {
|
||||
return Err("--sparse is only supported on linux".to_string().into());
|
||||
return Err(get_message("cp-error-sparse-not-supported")
|
||||
.to_string()
|
||||
.into());
|
||||
}
|
||||
let copy_debug = CopyDebug {
|
||||
offload: OffloadReflinkDebug::Unsupported,
|
||||
|
|
|
@ -1,3 +1,29 @@
|
|||
csplit-about = Split a file into sections determined by context lines
|
||||
csplit-usage = csplit [OPTION]... FILE PATTERN...
|
||||
csplit-after-help = Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output.
|
||||
|
||||
# Help messages
|
||||
csplit-help-suffix-format = use sprintf FORMAT instead of %02d
|
||||
csplit-help-prefix = use PREFIX instead of 'xx'
|
||||
csplit-help-keep-files = do not remove output files on errors
|
||||
csplit-help-suppress-matched = suppress the lines matching PATTERN
|
||||
csplit-help-digits = use specified number of digits instead of 2
|
||||
csplit-help-quiet = do not print counts of output file sizes
|
||||
csplit-help-elide-empty-files = remove empty output files
|
||||
|
||||
# Error messages
|
||||
csplit-error-line-out-of-range = { $pattern }: line number out of range
|
||||
csplit-error-line-out-of-range-on-repetition = { $pattern }: line number out of range on repetition { $repetition }
|
||||
csplit-error-match-not-found = { $pattern }: match not found
|
||||
csplit-error-match-not-found-on-repetition = { $pattern }: match not found on repetition { $repetition }
|
||||
csplit-error-line-number-is-zero = 0: line number must be greater than zero
|
||||
csplit-error-line-number-smaller-than-previous = line number '{ $current }' is smaller than preceding line number, { $previous }
|
||||
csplit-error-invalid-pattern = { $pattern }: invalid pattern
|
||||
csplit-error-invalid-number = invalid number: { $number }
|
||||
csplit-error-suffix-format-incorrect = incorrect conversion specification in suffix
|
||||
csplit-error-suffix-format-too-many-percents = too many % conversion specifications in suffix
|
||||
csplit-error-not-regular-file = { $file } is not a regular file
|
||||
csplit-warning-line-number-same-as-previous = line number '{ $line_number }' is the same as preceding line number
|
||||
csplit-stream-not-utf8 = stream did not contain valid UTF-8
|
||||
csplit-read-error = read error
|
||||
csplit-write-split-not-created = trying to write to a split that was not created
|
||||
|
|
29
src/uu/csplit/locales/fr-FR.ftl
Normal file
29
src/uu/csplit/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,29 @@
|
|||
csplit-about = Diviser un fichier en sections déterminées par des lignes de contexte
|
||||
csplit-usage = csplit [OPTION]... FICHIER MOTIF...
|
||||
csplit-after-help = Sortir les morceaux de FICHIER séparés par MOTIF(S) dans les fichiers 'xx00', 'xx01', ..., et sortir le nombre d'octets de chaque morceau sur la sortie standard.
|
||||
|
||||
# Messages d'aide
|
||||
csplit-help-suffix-format = utiliser le FORMAT sprintf au lieu de %02d
|
||||
csplit-help-prefix = utiliser PRÉFIXE au lieu de 'xx'
|
||||
csplit-help-keep-files = ne pas supprimer les fichiers de sortie en cas d'erreurs
|
||||
csplit-help-suppress-matched = supprimer les lignes correspondant au MOTIF
|
||||
csplit-help-digits = utiliser le nombre spécifié de chiffres au lieu de 2
|
||||
csplit-help-quiet = ne pas afficher le nombre d'octets des fichiers de sortie
|
||||
csplit-help-elide-empty-files = supprimer les fichiers de sortie vides
|
||||
|
||||
# Messages d'erreur
|
||||
csplit-error-line-out-of-range = { $pattern } : numéro de ligne hors limites
|
||||
csplit-error-line-out-of-range-on-repetition = { $pattern } : numéro de ligne hors limites à la répétition { $repetition }
|
||||
csplit-error-match-not-found = { $pattern } : correspondance non trouvée
|
||||
csplit-error-match-not-found-on-repetition = { $pattern } : correspondance non trouvée à la répétition { $repetition }
|
||||
csplit-error-line-number-is-zero = 0 : le numéro de ligne doit être supérieur à zéro
|
||||
csplit-error-line-number-smaller-than-previous = le numéro de ligne '{ $current }' est plus petit que le numéro de ligne précédent, { $previous }
|
||||
csplit-error-invalid-pattern = { $pattern } : motif invalide
|
||||
csplit-error-invalid-number = nombre invalide : { $number }
|
||||
csplit-error-suffix-format-incorrect = spécification de conversion incorrecte dans le suffixe
|
||||
csplit-error-suffix-format-too-many-percents = trop de spécifications de conversion % dans le suffixe
|
||||
csplit-error-not-regular-file = { $file } n'est pas un fichier régulier
|
||||
csplit-warning-line-number-same-as-previous = le numéro de ligne '{ $line_number }' est identique au numéro de ligne précédent
|
||||
csplit-stream-not-utf8 = le flux ne contenait pas d'UTF-8 valide
|
||||
csplit-read-error = erreur de lecture
|
||||
csplit-write-split-not-created = tentative d'écriture dans une division qui n'a pas été créée
|
|
@ -85,7 +85,10 @@ impl<T: BufRead> Iterator for LinesWithNewlines<T> {
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
fn ret(v: Vec<u8>) -> io::Result<String> {
|
||||
String::from_utf8(v).map_err(|_| {
|
||||
io::Error::new(ErrorKind::InvalidData, "stream did not contain valid UTF-8")
|
||||
io::Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
get_message("csplit-stream-not-utf8"),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -115,7 +118,7 @@ where
|
|||
T: BufRead,
|
||||
{
|
||||
let enumerated_input_lines = LinesWithNewlines::new(input)
|
||||
.map(|line| line.map_err_context(|| "read error".to_string()))
|
||||
.map(|line| line.map_err_context(|| get_message("csplit-read-error")))
|
||||
.enumerate();
|
||||
let mut input_iter = InputSplitter::new(enumerated_input_lines);
|
||||
let mut split_writer = SplitWriter::new(options);
|
||||
|
@ -283,7 +286,7 @@ impl SplitWriter<'_> {
|
|||
current_writer.write_all(bytes)?;
|
||||
self.size += bytes.len();
|
||||
}
|
||||
None => panic!("trying to write to a split that was not created"),
|
||||
None => panic!("{}", get_message("csplit-write-split-not-created")),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -638,26 +641,26 @@ pub fn uu_app() -> Command {
|
|||
.short('b')
|
||||
.long(options::SUFFIX_FORMAT)
|
||||
.value_name("FORMAT")
|
||||
.help("use sprintf FORMAT instead of %02d"),
|
||||
.help(get_message("csplit-help-suffix-format")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PREFIX)
|
||||
.short('f')
|
||||
.long(options::PREFIX)
|
||||
.value_name("PREFIX")
|
||||
.help("use PREFIX instead of 'xx'"),
|
||||
.help(get_message("csplit-help-prefix")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::KEEP_FILES)
|
||||
.short('k')
|
||||
.long(options::KEEP_FILES)
|
||||
.help("do not remove output files on errors")
|
||||
.help(get_message("csplit-help-keep-files"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SUPPRESS_MATCHED)
|
||||
.long(options::SUPPRESS_MATCHED)
|
||||
.help("suppress the lines matching PATTERN")
|
||||
.help(get_message("csplit-help-suppress-matched"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -665,7 +668,7 @@ pub fn uu_app() -> Command {
|
|||
.short('n')
|
||||
.long(options::DIGITS)
|
||||
.value_name("DIGITS")
|
||||
.help("use specified number of digits instead of 2"),
|
||||
.help(get_message("csplit-help-digits")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::QUIET)
|
||||
|
@ -673,14 +676,14 @@ pub fn uu_app() -> Command {
|
|||
.long(options::QUIET)
|
||||
.visible_short_alias('s')
|
||||
.visible_alias("silent")
|
||||
.help("do not print counts of output file sizes")
|
||||
.help(get_message("csplit-help-quiet"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ELIDE_EMPTY_FILES)
|
||||
.short('z')
|
||||
.long(options::ELIDE_EMPTY_FILES)
|
||||
.help("remove empty output files")
|
||||
.help(get_message("csplit-help-elide-empty-files"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
|
|
@ -2,38 +2,40 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::UError;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
/// Errors thrown by the csplit command
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CsplitError {
|
||||
#[error("IO error: {}", _0)]
|
||||
IoError(#[from] io::Error),
|
||||
#[error("{}: line number out of range", ._0.quote())]
|
||||
#[error("{}", get_message_with_args("csplit-error-line-out-of-range", HashMap::from([("pattern".to_string(), _0.quote().to_string())])))]
|
||||
LineOutOfRange(String),
|
||||
#[error("{}: line number out of range on repetition {}", ._0.quote(), _1)]
|
||||
#[error("{}", get_message_with_args("csplit-error-line-out-of-range-on-repetition", HashMap::from([("pattern".to_string(), _0.quote().to_string()), ("repetition".to_string(), _1.to_string())])))]
|
||||
LineOutOfRangeOnRepetition(String, usize),
|
||||
#[error("{}: match not found", ._0.quote())]
|
||||
#[error("{}", get_message_with_args("csplit-error-match-not-found", HashMap::from([("pattern".to_string(), _0.quote().to_string())])))]
|
||||
MatchNotFound(String),
|
||||
#[error("{}: match not found on repetition {}", ._0.quote(), _1)]
|
||||
#[error("{}", get_message_with_args("csplit-error-match-not-found-on-repetition", HashMap::from([("pattern".to_string(), _0.quote().to_string()), ("repetition".to_string(), _1.to_string())])))]
|
||||
MatchNotFoundOnRepetition(String, usize),
|
||||
#[error("0: line number must be greater than zero")]
|
||||
#[error("{}", get_message("csplit-error-line-number-is-zero"))]
|
||||
LineNumberIsZero,
|
||||
#[error("line number '{}' is smaller than preceding line number, {}", _0, _1)]
|
||||
#[error("{}", get_message_with_args("csplit-error-line-number-smaller-than-previous", HashMap::from([("current".to_string(), _0.to_string()), ("previous".to_string(), _1.to_string())])))]
|
||||
LineNumberSmallerThanPrevious(usize, usize),
|
||||
#[error("{}: invalid pattern", ._0.quote())]
|
||||
#[error("{}", get_message_with_args("csplit-error-invalid-pattern", HashMap::from([("pattern".to_string(), _0.quote().to_string())])))]
|
||||
InvalidPattern(String),
|
||||
#[error("invalid number: {}", ._0.quote())]
|
||||
#[error("{}", get_message_with_args("csplit-error-invalid-number", HashMap::from([("number".to_string(), _0.quote().to_string())])))]
|
||||
InvalidNumber(String),
|
||||
#[error("incorrect conversion specification in suffix")]
|
||||
#[error("{}", get_message("csplit-error-suffix-format-incorrect"))]
|
||||
SuffixFormatIncorrect,
|
||||
#[error("too many % conversion specifications in suffix")]
|
||||
#[error("{}", get_message("csplit-error-suffix-format-too-many-percents"))]
|
||||
SuffixFormatTooManyPercents,
|
||||
#[error("{} is not a regular file", ._0.quote())]
|
||||
#[error("{}", get_message_with_args("csplit-error-not-regular-file", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
|
||||
NotRegularFile(String),
|
||||
#[error("{}", _0)]
|
||||
UError(Box<dyn UError>),
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
use crate::csplit_error::CsplitError;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use uucore::locale::get_message_with_args;
|
||||
use uucore::show_warning;
|
||||
|
||||
/// The definition of a pattern to match on a line.
|
||||
|
@ -168,7 +170,13 @@ fn validate_line_numbers(patterns: &[Pattern]) -> Result<(), CsplitError> {
|
|||
(_, 0) => Err(CsplitError::LineNumberIsZero),
|
||||
// two consecutive numbers should not be equal
|
||||
(n, m) if n == m => {
|
||||
show_warning!("line number '{n}' is the same as preceding line number");
|
||||
show_warning!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"csplit-warning-line-number-same-as-previous",
|
||||
HashMap::from([("line_number".to_string(), n.to_string())])
|
||||
)
|
||||
);
|
||||
Ok(n)
|
||||
}
|
||||
// a number cannot be greater than the one that follows
|
||||
|
|
|
@ -74,3 +74,31 @@ date-usage =
|
|||
Show the time on the west coast of the US (use tzselect(1) to find TZ)
|
||||
|
||||
TZ='America/Los_Angeles' date
|
||||
|
||||
date-help-date = display time described by STRING, not 'now'
|
||||
date-help-file = like --date; once for each line of DATEFILE
|
||||
date-help-iso-8601 = output date/time in ISO 8601 format.
|
||||
FMT='date' for date only (the default),
|
||||
'hours', 'minutes', 'seconds', or 'ns'
|
||||
for date and time to the indicated precision.
|
||||
Example: 2006-08-14T02:34:56-06:00
|
||||
date-help-rfc-email = output date and time in RFC 5322 format.
|
||||
Example: Mon, 14 Aug 2006 02:34:56 -0600
|
||||
date-help-rfc-3339 = output date/time in RFC 3339 format.
|
||||
FMT='date', 'seconds', or 'ns'
|
||||
for date and time to the indicated precision.
|
||||
Example: 2006-08-14 02:34:56-06:00
|
||||
date-help-debug = annotate the parsed date, and warn about questionable usage to stderr
|
||||
date-help-reference = display the last modification time of FILE
|
||||
date-help-set = set time described by STRING
|
||||
date-help-set-macos = set time described by STRING (not available on mac yet)
|
||||
date-help-set-redox = set time described by STRING (not available on redox yet)
|
||||
date-help-universal = print or set Coordinated Universal Time (UTC)
|
||||
|
||||
date-error-invalid-date = invalid date '{$date}'
|
||||
date-error-invalid-format = invalid format '{$format}' ({$error})
|
||||
date-error-expected-file-got-directory = expected file, got directory '{$path}'
|
||||
date-error-date-overflow = date overflow '{$date}'
|
||||
date-error-setting-date-not-supported-macos = setting the date is not supported by macOS
|
||||
date-error-setting-date-not-supported-redox = setting the date is not supported by Redox
|
||||
date-error-cannot-set-date = cannot set date
|
||||
|
|
101
src/uu/date/locales/fr-FR.ftl
Normal file
101
src/uu/date/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,101 @@
|
|||
date-about = afficher ou définir la date système
|
||||
date-usage = [OPTION]... [+FORMAT]
|
||||
date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
|
||||
|
||||
FORMAT contrôle la sortie. Les séquences interprétées sont :
|
||||
{ "| Séquence | Description | Exemple |" }
|
||||
{ "| -------- | -------------------------------------------------------------- | ---------------------- |" }
|
||||
{ "| %% | un % littéral | % |" }
|
||||
{ "| %a | nom abrégé du jour de la semaine selon la locale | dim |" }
|
||||
{ "| %A | nom complet du jour de la semaine selon la locale | dimanche |" }
|
||||
{ "| %b | nom abrégé du mois selon la locale | jan |" }
|
||||
{ "| %B | nom complet du mois selon la locale | janvier |" }
|
||||
{ "| %c | date et heure selon la locale | jeu 3 mar 23:05:25 2005|" }
|
||||
{ "| %C | siècle ; comme %Y, sauf qu'on omet les deux derniers chiffres | 20 |" }
|
||||
{ "| %d | jour du mois | 01 |" }
|
||||
{ "| %D | date ; identique à %m/%d/%y | 12/31/99 |" }
|
||||
{ "| %e | jour du mois, rempli avec des espaces ; identique à %_d | 3 |" }
|
||||
{ "| %F | date complète ; identique à %Y-%m-%d | 2005-03-03 |" }
|
||||
{ "| %g | deux derniers chiffres de l'année du numéro de semaine ISO (voir %G) | 05 |" }
|
||||
{ "| %G | année du numéro de semaine ISO (voir %V) ; normalement utile seulement avec %V | 2005 |" }
|
||||
{ "| %h | identique à %b | jan |" }
|
||||
{ "| %H | heure (00..23) | 23 |" }
|
||||
{ "| %I | heure (01..12) | 11 |" }
|
||||
{ "| %j | jour de l'année (001..366) | 062 |" }
|
||||
{ "| %k | heure, remplie avec des espaces ( 0..23) ; identique à %_H | 3 |" }
|
||||
{ "| %l | heure, remplie avec des espaces ( 1..12) ; identique à %_I | 9 |" }
|
||||
{ "| %m | mois (01..12) | 03 |" }
|
||||
{ "| %M | minute (00..59) | 30 |" }
|
||||
{ "| %n | une nouvelle ligne | \\n |" }
|
||||
{ "| %N | nanosecondes (000000000..999999999) | 123456789 |" }
|
||||
{ "| %p | équivalent locale de AM ou PM ; vide si inconnu | PM |" }
|
||||
{ "| %P | comme %p, mais en minuscules | pm |" }
|
||||
{ "| %q | trimestre de l'année (1..4) | 1 |" }
|
||||
{ "| %r | heure sur 12 heures selon la locale | 11:11:04 PM |" }
|
||||
{ "| %R | heure sur 24 heures et minute ; identique à %H:%M | 23:30 |" }
|
||||
{ "| %s | secondes depuis 1970-01-01 00:00:00 UTC | 1615432800 |" }
|
||||
{ "| %S | seconde (00..60) | 30 |" }
|
||||
{ "| %t | une tabulation | \\t |" }
|
||||
{ "| %T | heure ; identique à %H:%M:%S | 23:30:30 |" }
|
||||
{ "| %u | jour de la semaine (1..7) ; 1 est lundi | 4 |" }
|
||||
{ "| %U | numéro de semaine de l'année, avec dimanche comme premier jour de la semaine (00..53) | 10 |" }
|
||||
{ "| %V | numéro de semaine ISO, avec lundi comme premier jour de la semaine (01..53) | 12 |" }
|
||||
{ "| %w | jour de la semaine (0..6) ; 0 est dimanche | 4 |" }
|
||||
{ "| %W | numéro de semaine de l'année, avec lundi comme premier jour de la semaine (00..53) | 11 |" }
|
||||
{ "| %x | représentation de la date selon la locale | 03/03/2005 |" }
|
||||
{ "| %X | représentation de l'heure selon la locale | 23:30:30 |" }
|
||||
{ "| %y | deux derniers chiffres de l'année (00..99) | 05 |" }
|
||||
{ "| %Y | année | 2005 |" }
|
||||
{ "| %z | fuseau horaire numérique +hhmm | -0400 |" }
|
||||
{ "| %:z | fuseau horaire numérique +hh:mm | -04:00 |" }
|
||||
{ "| %::z | fuseau horaire numérique +hh:mm:ss | -04:00:00 |" }
|
||||
{ "| %:::z | fuseau horaire numérique avec : à la précision nécessaire | -04, +05:30 |" }
|
||||
{ "| %Z | abréviation alphabétique du fuseau horaire | EDT |" }
|
||||
|
||||
Par défaut, date remplit les champs numériques avec des zéros.
|
||||
Les indicateurs optionnels suivants peuvent suivre '%' :
|
||||
{ "* `-` (tiret) ne pas remplir le champ" }
|
||||
{ "* `_` (soulignement) remplir avec des espaces" }
|
||||
{ "* `0` (zéro) remplir avec des zéros" }
|
||||
{ "* `^` utiliser des majuscules si possible" }
|
||||
{ "* `#` utiliser l'inverse si possible" }
|
||||
Après tout indicateur vient une largeur de champ optionnelle, comme nombre décimal ;
|
||||
puis un modificateur optionnel, qui est soit
|
||||
{ "* `E` pour utiliser les représentations alternatives de la locale si disponibles, ou" }
|
||||
{ "* `O` pour utiliser les symboles numériques alternatifs de la locale si disponibles." }
|
||||
Exemples :
|
||||
Convertir les secondes depuis l'époque (1970-01-01 UTC) en date
|
||||
|
||||
date --date='@2147483647'
|
||||
|
||||
Montrer l'heure sur la côte ouest des États-Unis (utiliser tzselect(1) pour trouver TZ)
|
||||
|
||||
TZ='America/Los_Angeles' date
|
||||
|
||||
date-help-date = afficher l'heure décrite par CHAÎNE, pas 'maintenant'
|
||||
date-help-file = comme --date ; une fois pour chaque ligne de FICHIER_DATE
|
||||
date-help-iso-8601 = afficher la date/heure au format ISO 8601.
|
||||
FMT='date' pour la date seulement (par défaut),
|
||||
'hours', 'minutes', 'seconds', ou 'ns'
|
||||
pour la date et l'heure à la précision indiquée.
|
||||
Exemple : 2006-08-14T02:34:56-06:00
|
||||
date-help-rfc-email = afficher la date et l'heure au format RFC 5322.
|
||||
Exemple : Mon, 14 Aug 2006 02:34:56 -0600
|
||||
date-help-rfc-3339 = afficher la date/heure au format RFC 3339.
|
||||
FMT='date', 'seconds', ou 'ns'
|
||||
pour la date et l'heure à la précision indiquée.
|
||||
Exemple : 2006-08-14 02:34:56-06:00
|
||||
date-help-debug = annoter la date analysée et avertir des usages douteux sur stderr
|
||||
date-help-reference = afficher l'heure de dernière modification du FICHIER
|
||||
date-help-set = définir l'heure décrite par CHAÎNE
|
||||
date-help-set-macos = définir l'heure décrite par CHAÎNE (pas encore disponible sur mac)
|
||||
date-help-set-redox = définir l'heure décrite par CHAÎNE (pas encore disponible sur redox)
|
||||
date-help-universal = afficher ou définir le Temps Universel Coordonné (UTC)
|
||||
|
||||
date-error-invalid-date = date invalide '{$date}'
|
||||
date-error-invalid-format = format invalide '{$format}' ({$error})
|
||||
date-error-expected-file-got-directory = fichier attendu, répertoire obtenu '{$path}'
|
||||
date-error-date-overflow = débordement de date '{$date}'
|
||||
date-error-setting-date-not-supported-macos = la définition de la date n'est pas prise en charge par macOS
|
||||
date-error-setting-date-not-supported-redox = la définition de la date n'est pas prise en charge par Redox
|
||||
date-error-cannot-set-date = impossible de définir la date
|
|
@ -14,14 +14,14 @@ use libc::{CLOCK_REALTIME, clock_settime, timespec};
|
|||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::path::PathBuf;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::FromIo;
|
||||
use uucore::error::{UResult, USimpleError};
|
||||
use uucore::{format_usage, show};
|
||||
#[cfg(windows)]
|
||||
use windows_sys::Win32::{Foundation::SYSTEMTIME, System::SystemInformation::SetSystemTime};
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use std::collections::HashMap;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
use uucore::parser::shortcut_value_parser::ShortcutValueParser;
|
||||
|
||||
// Options
|
||||
|
@ -43,29 +43,6 @@ const OPT_REFERENCE: &str = "reference";
|
|||
const OPT_UNIVERSAL: &str = "universal";
|
||||
const OPT_UNIVERSAL_2: &str = "utc";
|
||||
|
||||
// Help strings
|
||||
|
||||
static ISO_8601_HELP_STRING: &str = "output date/time in ISO 8601 format.
|
||||
FMT='date' for date only (the default),
|
||||
'hours', 'minutes', 'seconds', or 'ns'
|
||||
for date and time to the indicated precision.
|
||||
Example: 2006-08-14T02:34:56-06:00";
|
||||
|
||||
static RFC_5322_HELP_STRING: &str = "output date and time in RFC 5322 format.
|
||||
Example: Mon, 14 Aug 2006 02:34:56 -0600";
|
||||
|
||||
static RFC_3339_HELP_STRING: &str = "output date/time in RFC 3339 format.
|
||||
FMT='date', 'seconds', or 'ns'
|
||||
for date and time to the indicated precision.
|
||||
Example: 2006-08-14 02:34:56-06:00";
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "redox")))]
|
||||
static OPT_SET_HELP_STRING: &str = "set time described by STRING";
|
||||
#[cfg(target_os = "macos")]
|
||||
static OPT_SET_HELP_STRING: &str = "set time described by STRING (not available on mac yet)";
|
||||
#[cfg(target_os = "redox")]
|
||||
static OPT_SET_HELP_STRING: &str = "set time described by STRING (not available on redox yet)";
|
||||
|
||||
/// Settings for this program, parsed from the command line
|
||||
struct Settings {
|
||||
utc: bool,
|
||||
|
@ -141,7 +118,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if !form.starts_with('+') {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid date {}", form.quote()),
|
||||
get_message_with_args(
|
||||
"date-error-invalid-date",
|
||||
HashMap::from([("date".to_string(), form.to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
let form = form[1..].to_string();
|
||||
|
@ -182,7 +162,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
Some(Err((input, _err))) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid date {}", input.quote()),
|
||||
get_message_with_args(
|
||||
"date-error-invalid-date",
|
||||
HashMap::from([("date".to_string(), input.to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
Some(Ok(date)) => Some(date),
|
||||
|
@ -231,7 +214,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
Err(_) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid date {relative_time}"),
|
||||
get_message_with_args(
|
||||
"date-error-date-overflow",
|
||||
HashMap::from([("date".to_string(), relative_time.to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +231,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if path.is_dir() {
|
||||
return Err(USimpleError::new(
|
||||
2,
|
||||
format!("expected file, got directory {}", path.quote()),
|
||||
get_message_with_args(
|
||||
"date-error-expected-file-got-directory",
|
||||
HashMap::from([("path".to_string(), path.to_string_lossy().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
let file = File::open(path)
|
||||
|
@ -271,13 +260,22 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
Err(e) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid format {format_string} ({e})"),
|
||||
get_message_with_args(
|
||||
"date-error-invalid-format",
|
||||
HashMap::from([
|
||||
("format".to_string(), format_string.to_string()),
|
||||
("error".to_string(), e.to_string()),
|
||||
]),
|
||||
),
|
||||
));
|
||||
}
|
||||
},
|
||||
Err((input, _err)) => show!(USimpleError::new(
|
||||
1,
|
||||
format!("invalid date {}", input.quote())
|
||||
get_message_with_args(
|
||||
"date-error-invalid-date",
|
||||
HashMap::from([("date".to_string(), input.to_string())])
|
||||
)
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -297,7 +295,7 @@ pub fn uu_app() -> Command {
|
|||
.long(OPT_DATE)
|
||||
.value_name("STRING")
|
||||
.allow_hyphen_values(true)
|
||||
.help("display time described by STRING, not 'now'"),
|
||||
.help(get_message("date-help-date")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_FILE)
|
||||
|
@ -305,7 +303,7 @@ pub fn uu_app() -> Command {
|
|||
.long(OPT_FILE)
|
||||
.value_name("DATEFILE")
|
||||
.value_hint(clap::ValueHint::FilePath)
|
||||
.help("like --date; once for each line of DATEFILE"),
|
||||
.help(get_message("date-help-file")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_ISO_8601)
|
||||
|
@ -317,13 +315,13 @@ pub fn uu_app() -> Command {
|
|||
]))
|
||||
.num_args(0..=1)
|
||||
.default_missing_value(OPT_DATE)
|
||||
.help(ISO_8601_HELP_STRING),
|
||||
.help(get_message("date-help-iso-8601")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_RFC_EMAIL)
|
||||
.short('R')
|
||||
.long(OPT_RFC_EMAIL)
|
||||
.help(RFC_5322_HELP_STRING)
|
||||
.help(get_message("date-help-rfc-email"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -331,12 +329,12 @@ pub fn uu_app() -> Command {
|
|||
.long(OPT_RFC_3339)
|
||||
.value_name("FMT")
|
||||
.value_parser(ShortcutValueParser::new([DATE, SECONDS, NS]))
|
||||
.help(RFC_3339_HELP_STRING),
|
||||
.help(get_message("date-help-rfc-3339")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_DEBUG)
|
||||
.long(OPT_DEBUG)
|
||||
.help("annotate the parsed date, and warn about questionable usage to stderr")
|
||||
.help(get_message("date-help-debug"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -345,21 +343,34 @@ pub fn uu_app() -> Command {
|
|||
.long(OPT_REFERENCE)
|
||||
.value_name("FILE")
|
||||
.value_hint(clap::ValueHint::AnyPath)
|
||||
.help("display the last modification time of FILE"),
|
||||
.help(get_message("date-help-reference")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_SET)
|
||||
.short('s')
|
||||
.long(OPT_SET)
|
||||
.value_name("STRING")
|
||||
.help(OPT_SET_HELP_STRING),
|
||||
.help({
|
||||
#[cfg(not(any(target_os = "macos", target_os = "redox")))]
|
||||
{
|
||||
get_message("date-help-set")
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
get_message("date-help-set-macos")
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
{
|
||||
get_message("date-help-set-redox")
|
||||
}
|
||||
}),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_UNIVERSAL)
|
||||
.short('u')
|
||||
.long(OPT_UNIVERSAL)
|
||||
.alias(OPT_UNIVERSAL_2)
|
||||
.help("print or set Coordinated Universal Time (UTC)")
|
||||
.help(get_message("date-help-universal"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(Arg::new(OPT_FORMAT))
|
||||
|
@ -427,7 +438,7 @@ fn set_system_datetime(_date: Zoned) -> UResult<()> {
|
|||
fn set_system_datetime(_date: Zoned) -> UResult<()> {
|
||||
Err(USimpleError::new(
|
||||
1,
|
||||
"setting the date is not supported by macOS".to_string(),
|
||||
get_message("date-error-setting-date-not-supported-macos"),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -435,7 +446,7 @@ fn set_system_datetime(_date: Zoned) -> UResult<()> {
|
|||
fn set_system_datetime(_date: Zoned) -> UResult<()> {
|
||||
Err(USimpleError::new(
|
||||
1,
|
||||
"setting the date is not supported by Redox".to_string(),
|
||||
get_message("date-error-setting-date-not-supported-redox"),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -452,12 +463,13 @@ fn set_system_datetime(date: Zoned) -> UResult<()> {
|
|||
tv_nsec: ts.subsec_nanosecond() as _,
|
||||
};
|
||||
|
||||
let result = unsafe { clock_settime(CLOCK_REALTIME, ×pec) };
|
||||
let result = unsafe { clock_settime(CLOCK_REALTIME, &raw const timespec) };
|
||||
|
||||
if result == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(std::io::Error::last_os_error().map_err_context(|| "cannot set date".to_string()))
|
||||
Err(std::io::Error::last_os_error()
|
||||
.map_err_context(|| get_message("date-error-cannot-set-date")))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,10 +492,11 @@ fn set_system_datetime(date: Zoned) -> UResult<()> {
|
|||
wMilliseconds: ((date.subsec_nanosecond() / 1_000_000) % 1000) as u16,
|
||||
};
|
||||
|
||||
let result = unsafe { SetSystemTime(&system_time) };
|
||||
let result = unsafe { SetSystemTime(&raw const system_time) };
|
||||
|
||||
if result == 0 {
|
||||
Err(std::io::Error::last_os_error().map_err_context(|| "cannot set date".to_string()))
|
||||
Err(std::io::Error::last_os_error()
|
||||
.map_err_context(|| get_message("date-error-cannot-set-date")))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -113,3 +113,48 @@ dd-after-help = ### Operands
|
|||
- nocache : request that OS drop cache.
|
||||
- noctty : do not assign a controlling tty.
|
||||
- nofollow : do not follow system links.
|
||||
|
||||
# Error messages
|
||||
dd-error-failed-to-open = failed to open { $path }
|
||||
dd-error-write-error = write error
|
||||
dd-error-failed-to-seek = failed to seek in output file
|
||||
dd-error-io-error = IO error
|
||||
dd-error-cannot-skip-offset = '{ $file }': cannot skip to specified offset
|
||||
dd-error-cannot-skip-invalid = '{ $file }': cannot skip: Invalid argument
|
||||
dd-error-cannot-seek-invalid = '{ $output }': cannot seek: Invalid argument
|
||||
dd-error-not-directory = setting flags for '{ $file }': Not a directory
|
||||
dd-error-failed-discard-cache-input = failed to discard cache for: 'standard input'
|
||||
dd-error-failed-discard-cache-output = failed to discard cache for: 'standard output'
|
||||
|
||||
# Parse errors
|
||||
dd-error-unrecognized-operand = Unrecognized operand '{ $operand }'
|
||||
dd-error-multiple-format-table = Only one of conv=ascii conv=ebcdic or conv=ibm may be specified
|
||||
dd-error-multiple-case = Only one of conv=lcase or conv=ucase may be specified
|
||||
dd-error-multiple-block = Only one of conv=block or conv=unblock may be specified
|
||||
dd-error-multiple-excl = Only one ov conv=excl or conv=nocreat may be specified
|
||||
dd-error-invalid-flag = invalid input flag: ‘{ $flag }’
|
||||
Try '{ $cmd } --help' for more information.
|
||||
dd-error-conv-flag-no-match = Unrecognized conv=CONV -> { $flag }
|
||||
dd-error-multiplier-parse-failure = invalid number: '{ $input }'
|
||||
dd-error-multiplier-overflow = Multiplier string would overflow on current system -> { $input }
|
||||
dd-error-block-without-cbs = conv=block or conv=unblock specified without cbs=N
|
||||
dd-error-status-not-recognized = status=LEVEL not recognized -> { $level }
|
||||
dd-error-unimplemented = feature not implemented on this system -> { $feature }
|
||||
dd-error-bs-out-of-range = { $param }=N cannot fit into memory
|
||||
dd-error-invalid-number = invalid number: ‘{ $input }’
|
||||
|
||||
# Progress messages
|
||||
dd-progress-records-in = { $complete }+{ $partial } records in
|
||||
dd-progress-records-out = { $complete }+{ $partial } records out
|
||||
dd-progress-truncated-record = { $count ->
|
||||
[one] { $count } truncated record
|
||||
*[other] { $count } truncated records
|
||||
}
|
||||
dd-progress-byte-copied = { $bytes } byte copied, { $duration } s, { $rate }/s
|
||||
dd-progress-bytes-copied = { $bytes } bytes copied, { $duration } s, { $rate }/s
|
||||
dd-progress-bytes-copied-si = { $bytes } bytes ({ $si }) copied, { $duration } s, { $rate }/s
|
||||
dd-progress-bytes-copied-si-iec = { $bytes } bytes ({ $si }, { $iec }) copied, { $duration } s, { $rate }/s
|
||||
|
||||
# Warnings
|
||||
dd-warning-zero-multiplier = { $zero } is a zero multiplier; use { $alternative } if that is intended
|
||||
dd-warning-signal-handler = Internal dd Warning: Unable to register signal handler
|
||||
|
|
160
src/uu/dd/locales/fr-FR.ftl
Normal file
160
src/uu/dd/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,160 @@
|
|||
dd-about = Copier, et optionnellement convertir, une ressource du système de fichiers
|
||||
dd-usage = dd [OPÉRANDE]...
|
||||
dd OPTION
|
||||
dd-after-help = ### Opérandes
|
||||
|
||||
- bs=OCTETS : lire et écrire jusqu'à OCTETS octets à la fois (par défaut : 512) ;
|
||||
remplace ibs et obs.
|
||||
- cbs=OCTETS : la 'taille de bloc de conversion' en octets. S'applique aux
|
||||
opérations conv=block et conv=unblock.
|
||||
- conv=CONVS : une liste séparée par des virgules d'options de conversion ou (pour des
|
||||
raisons historiques) d'indicateurs de fichier.
|
||||
- count=N : arrêter la lecture de l'entrée après N opérations de lecture de taille ibs
|
||||
plutôt que de continuer jusqu'à EOF. Voir iflag=count_bytes si l'arrêt après N octets
|
||||
est préféré
|
||||
- ibs=N : la taille du tampon utilisé pour les lectures (par défaut : 512)
|
||||
- if=FICHIER : le fichier utilisé pour l'entrée. Quand non spécifié, stdin est utilisé à la place
|
||||
- iflag=INDICATEURS : une liste séparée par des virgules d'indicateurs d'entrée qui spécifient comment
|
||||
la source d'entrée est traitée. INDICATEURS peut être n'importe lequel des indicateurs d'entrée ou
|
||||
indicateurs généraux spécifiés ci-dessous.
|
||||
- skip=N (ou iseek=N) : ignorer N enregistrements de taille ibs dans l'entrée avant de commencer
|
||||
les opérations de copie/conversion. Voir iflag=seek_bytes si la recherche de N octets est préférée.
|
||||
- obs=N : la taille du tampon utilisé pour les écritures (par défaut : 512)
|
||||
- of=FICHIER : le fichier utilisé pour la sortie. Quand non spécifié, stdout est utilisé
|
||||
à la place
|
||||
- oflag=INDICATEURS : liste séparée par des virgules d'indicateurs de sortie qui spécifient comment la
|
||||
source de sortie est traitée. INDICATEURS peut être n'importe lequel des indicateurs de sortie ou
|
||||
indicateurs généraux spécifiés ci-dessous
|
||||
- seek=N (ou oseek=N) : recherche N enregistrements de taille obs dans la sortie avant de
|
||||
commencer les opérations de copie/conversion. Voir oflag=seek_bytes si la recherche de N octets est
|
||||
préférée
|
||||
- status=NIVEAU : contrôle si les statistiques de volume et de performance sont écrites sur
|
||||
stderr.
|
||||
|
||||
Quand non spécifié, dd affichera les statistiques à la fin. Un exemple est ci-dessous.
|
||||
|
||||
```plain
|
||||
6+0 enregistrements en entrée
|
||||
16+0 enregistrements en sortie
|
||||
8192 octets (8.2 kB, 8.0 KiB) copiés, 0.00057009 s,
|
||||
14.4 MB/s
|
||||
|
||||
Les deux premières lignes sont les statistiques de 'volume' et la dernière ligne est les
|
||||
statistiques de 'performance'.
|
||||
Les statistiques de volume indiquent le nombre de lectures complètes et partielles de taille ibs,
|
||||
ou d'écritures de taille obs qui ont eu lieu pendant la copie. Le format des statistiques de
|
||||
volume est <complètes>+<partielles>. Si des enregistrements ont été tronqués (voir
|
||||
conv=block), les statistiques de volume contiendront le nombre d'enregistrements tronqués.
|
||||
|
||||
Les valeurs possibles de NIVEAU sont :
|
||||
- progress : Afficher les statistiques de performance périodiques pendant la copie.
|
||||
- noxfer : Afficher les statistiques de volume finales, mais pas les statistiques de performance.
|
||||
- none : N'afficher aucune statistique.
|
||||
|
||||
L'affichage des statistiques de performance est aussi déclenché par le signal INFO (quand supporté),
|
||||
ou le signal USR1. Définir la variable d'environnement POSIXLY_CORRECT à n'importe quelle valeur
|
||||
(y compris une valeur vide) fera ignorer le signal USR1.
|
||||
|
||||
### Options de conversion
|
||||
|
||||
- ascii : convertir d'EBCDIC vers ASCII. C'est l'inverse de l'option ebcdic.
|
||||
Implique conv=unblock.
|
||||
- ebcdic : convertir d'ASCII vers EBCDIC. C'est l'inverse de l'option ascii.
|
||||
Implique conv=block.
|
||||
- ibm : convertir d'ASCII vers EBCDIC, en appliquant les conventions pour [, ]
|
||||
et ~ spécifiées dans POSIX. Implique conv=block.
|
||||
|
||||
- ucase : convertir de minuscules vers majuscules.
|
||||
- lcase : convertir de majuscules vers minuscules.
|
||||
|
||||
- block : pour chaque nouvelle ligne inférieure à la taille indiquée par cbs=OCTETS, supprimer
|
||||
la nouvelle ligne et remplir avec des espaces jusqu'à cbs. Les lignes plus longues que cbs sont tronquées.
|
||||
- unblock : pour chaque bloc d'entrée de la taille indiquée par cbs=OCTETS, supprimer
|
||||
les espaces de fin à droite et remplacer par un caractère de nouvelle ligne.
|
||||
|
||||
- sparse : tente de rechercher la sortie quand un bloc de taille obs ne contient que
|
||||
des zéros.
|
||||
- swab : échange chaque paire d'octets adjacents. Si un nombre impair d'octets est
|
||||
présent, l'octet final est omis.
|
||||
- sync : remplit chaque bloc de taille ibs avec des zéros. Si block ou unblock est
|
||||
spécifié, remplit avec des espaces à la place.
|
||||
- excl : le fichier de sortie doit être créé. Échoue si le fichier de sortie est déjà
|
||||
présent.
|
||||
- nocreat : le fichier de sortie ne sera pas créé. Échoue si le fichier de sortie n'est
|
||||
pas déjà présent.
|
||||
- notrunc : le fichier de sortie ne sera pas tronqué. Si cette option n'est pas
|
||||
présente, la sortie sera tronquée à l'ouverture.
|
||||
- noerror : toutes les erreurs de lecture seront ignorées. Si cette option n'est pas présente,
|
||||
dd n'ignorera que Error::Interrupted.
|
||||
- fdatasync : les données seront écrites avant la fin.
|
||||
- fsync : les données et les métadonnées seront écrites avant la fin.
|
||||
|
||||
### Indicateurs d'entrée
|
||||
|
||||
- count_bytes : une valeur pour count=N sera interprétée comme des octets.
|
||||
- skip_bytes : une valeur pour skip=N sera interprétée comme des octets.
|
||||
- fullblock : attendre ibs octets de chaque lecture. les lectures de longueur zéro sont toujours
|
||||
considérées comme EOF.
|
||||
|
||||
### Indicateurs de sortie
|
||||
|
||||
- append : ouvrir le fichier en mode ajout. Considérez définir conv=notrunc aussi.
|
||||
- seek_bytes : une valeur pour seek=N sera interprétée comme des octets.
|
||||
|
||||
### Indicateurs généraux
|
||||
|
||||
- direct : utiliser les E/S directes pour les données.
|
||||
- directory : échouer sauf si l'entrée donnée (si utilisée comme iflag) ou
|
||||
la sortie (si utilisée comme oflag) est un répertoire.
|
||||
- dsync : utiliser les E/S synchronisées pour les données.
|
||||
- sync : utiliser les E/S synchronisées pour les données et les métadonnées.
|
||||
- nonblock : utiliser les E/S non-bloquantes.
|
||||
- noatime : ne pas mettre à jour l'heure d'accès.
|
||||
- nocache : demander au système d'exploitation de supprimer le cache.
|
||||
- noctty : ne pas assigner un tty de contrôle.
|
||||
- nofollow : ne pas suivre les liens système.
|
||||
|
||||
# Error messages
|
||||
dd-error-failed-to-open = échec de l'ouverture de { $path }
|
||||
dd-error-write-error = erreur d'écriture
|
||||
dd-error-failed-to-seek = échec de la recherche dans le fichier de sortie
|
||||
dd-error-io-error = erreur E/S
|
||||
dd-error-cannot-skip-offset = '{ $file }' : impossible d'ignorer jusqu'au décalage spécifié
|
||||
dd-error-cannot-skip-invalid = '{ $file }' : impossible d'ignorer : Argument invalide
|
||||
dd-error-cannot-seek-invalid = '{ $output }' : impossible de rechercher : Argument invalide
|
||||
dd-error-not-directory = définir les indicateurs pour '{ $file }' : N'est pas un répertoire
|
||||
dd-error-failed-discard-cache-input = échec de la suppression du cache pour : 'entrée standard'
|
||||
dd-error-failed-discard-cache-output = échec de la suppression du cache pour : 'sortie standard'
|
||||
|
||||
# Parse errors
|
||||
dd-error-unrecognized-operand = Opérande non reconnue '{ $operand }'
|
||||
dd-error-multiple-format-table = Seul un seul de conv=ascii conv=ebcdic ou conv=ibm peut être spécifié
|
||||
dd-error-multiple-case = Seul un seul de conv=lcase ou conv=ucase peut être spécifié
|
||||
dd-error-multiple-block = Seul un seul de conv=block ou conv=unblock peut être spécifié
|
||||
dd-error-multiple-excl = Seul un seul de conv=excl ou conv=nocreat peut être spécifié
|
||||
dd-error-invalid-flag = indicateur d'entrée invalide : '{ $flag }'
|
||||
Essayez '{ $cmd } --help' pour plus d'informations.
|
||||
dd-error-conv-flag-no-match = conv=CONV non reconnu -> { $flag }
|
||||
dd-error-multiplier-parse-failure = nombre invalide : ‘{ $input }‘
|
||||
dd-error-multiplier-overflow = La chaîne de multiplicateur déborderait sur le système actuel -> { $input }
|
||||
dd-error-block-without-cbs = conv=block ou conv=unblock spécifié sans cbs=N
|
||||
dd-error-status-not-recognized = status=NIVEAU non reconnu -> { $level }
|
||||
dd-error-unimplemented = fonctionnalité non implémentée sur ce système -> { $feature }
|
||||
dd-error-bs-out-of-range = { $param }=N ne peut pas tenir en mémoire
|
||||
dd-error-invalid-number = nombre invalide : ‘{ $input }‘
|
||||
|
||||
# Progress messages
|
||||
dd-progress-records-in = { $complete }+{ $partial } enregistrements en entrée
|
||||
dd-progress-records-out = { $complete }+{ $partial } enregistrements en sortie
|
||||
dd-progress-truncated-record = { $count ->
|
||||
[one] { $count } enregistrement tronqué
|
||||
*[other] { $count } enregistrements tronqués
|
||||
}
|
||||
dd-progress-byte-copied = { $bytes } octet copié, { $duration } s, { $rate }/s
|
||||
dd-progress-bytes-copied = { $bytes } octets copiés, { $duration } s, { $rate }/s
|
||||
dd-progress-bytes-copied-si = { $bytes } octets ({ $si }) copiés, { $duration } s, { $rate }/s
|
||||
dd-progress-bytes-copied-si-iec = { $bytes } octets ({ $si }, { $iec }) copiés, { $duration } s, { $rate }/s
|
||||
|
||||
# Warnings
|
||||
dd-warning-zero-multiplier = { $zero } est un multiplicateur zéro ; utilisez { $alternative } si c'est voulu
|
||||
dd-warning-signal-handler = Avertissement dd interne : Impossible d'enregistrer le gestionnaire de signal
|
|
@ -26,6 +26,7 @@ use progress::{ProgUpdate, ReadStat, StatusLevel, WriteStat, gen_prog_updater};
|
|||
use uucore::io::OwnedFileDescriptorOrHandle;
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{File, OpenOptions};
|
||||
|
@ -62,7 +63,7 @@ use uucore::error::{USimpleError, set_exit_code};
|
|||
use uucore::show_if_err;
|
||||
use uucore::{format_usage, show_error};
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
const BUF_INIT_BYTE: u8 = 0xDD;
|
||||
|
||||
/// Final settings after parsing
|
||||
|
@ -235,7 +236,13 @@ impl Source {
|
|||
#[cfg(not(unix))]
|
||||
Self::Stdin(stdin) => match io::copy(&mut stdin.take(n), &mut io::sink()) {
|
||||
Ok(m) if m < n => {
|
||||
show_error!("'standard input': cannot skip to specified offset");
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"dd-error-cannot-skip-offset",
|
||||
HashMap::from([("file".to_string(), "standard input".to_string())])
|
||||
)
|
||||
);
|
||||
Ok(m)
|
||||
}
|
||||
Ok(m) => Ok(m),
|
||||
|
@ -247,14 +254,26 @@ impl Source {
|
|||
if len < n {
|
||||
// GNU compatibility:
|
||||
// this case prints the stats but sets the exit code to 1
|
||||
show_error!("'standard input': cannot skip: Invalid argument");
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"dd-error-cannot-skip-invalid",
|
||||
HashMap::from([("file".to_string(), "standard input".to_string())])
|
||||
)
|
||||
);
|
||||
set_exit_code(1);
|
||||
return Ok(len);
|
||||
}
|
||||
}
|
||||
match io::copy(&mut f.take(n), &mut io::sink()) {
|
||||
Ok(m) if m < n => {
|
||||
show_error!("'standard input': cannot skip to specified offset");
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"dd-error-cannot-skip-offset",
|
||||
HashMap::from([("file".to_string(), "standard input".to_string())])
|
||||
)
|
||||
);
|
||||
Ok(m)
|
||||
}
|
||||
Ok(m) => Ok(m),
|
||||
|
@ -343,7 +362,10 @@ impl<'a> Input<'a> {
|
|||
if settings.iflags.directory && !f.metadata()?.is_dir() {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
"setting flags for 'standard input': Not a directory",
|
||||
get_message_with_args(
|
||||
"dd-error-not-directory",
|
||||
HashMap::from([("file".to_string(), "standard input".to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
@ -364,8 +386,12 @@ impl<'a> Input<'a> {
|
|||
opts.custom_flags(libc_flags);
|
||||
}
|
||||
|
||||
opts.open(filename)
|
||||
.map_err_context(|| format!("failed to open {}", filename.quote()))?
|
||||
opts.open(filename).map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"dd-error-failed-to-open",
|
||||
HashMap::from([("path".to_string(), filename.quote().to_string())]),
|
||||
)
|
||||
})?
|
||||
};
|
||||
|
||||
let mut src = Source::File(src);
|
||||
|
@ -457,10 +483,11 @@ impl Input<'_> {
|
|||
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
show_if_err!(self
|
||||
.src
|
||||
.discard_cache(offset, len)
|
||||
.map_err_context(|| "failed to discard cache for: 'standard input'".to_string()));
|
||||
show_if_err!(
|
||||
self.src
|
||||
.discard_cache(offset, len)
|
||||
.map_err_context(|| get_message("dd-error-failed-discard-cache-input"))
|
||||
);
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
|
@ -609,7 +636,16 @@ impl Dest {
|
|||
if len < n {
|
||||
// GNU compatibility:
|
||||
// this case prints the stats but sets the exit code to 1
|
||||
show_error!("'standard output': cannot seek: Invalid argument");
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"dd-error-cannot-seek-invalid",
|
||||
HashMap::from([(
|
||||
"output".to_string(),
|
||||
"standard output".to_string()
|
||||
)])
|
||||
)
|
||||
);
|
||||
set_exit_code(1);
|
||||
return Ok(len);
|
||||
}
|
||||
|
@ -723,7 +759,7 @@ impl<'a> Output<'a> {
|
|||
fn new_stdout(settings: &'a Settings) -> UResult<Self> {
|
||||
let mut dst = Dest::Stdout(io::stdout());
|
||||
dst.seek(settings.seek)
|
||||
.map_err_context(|| "write error".to_string())?;
|
||||
.map_err_context(|| get_message("dd-error-write-error"))?;
|
||||
Ok(Self { dst, settings })
|
||||
}
|
||||
|
||||
|
@ -744,8 +780,12 @@ impl<'a> Output<'a> {
|
|||
opts.open(path)
|
||||
}
|
||||
|
||||
let dst = open_dst(filename, &settings.oconv, &settings.oflags)
|
||||
.map_err_context(|| format!("failed to open {}", filename.quote()))?;
|
||||
let dst = open_dst(filename, &settings.oconv, &settings.oflags).map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"dd-error-failed-to-open",
|
||||
HashMap::from([("path".to_string(), filename.quote().to_string())]),
|
||||
)
|
||||
})?;
|
||||
|
||||
// Seek to the index in the output file, truncating if requested.
|
||||
//
|
||||
|
@ -770,7 +810,7 @@ impl<'a> Output<'a> {
|
|||
};
|
||||
let mut dst = Dest::File(dst, density);
|
||||
dst.seek(settings.seek)
|
||||
.map_err_context(|| "failed to seek in output file".to_string())?;
|
||||
.map_err_context(|| get_message("dd-error-failed-to-seek"))?;
|
||||
Ok(Self { dst, settings })
|
||||
}
|
||||
|
||||
|
@ -832,9 +872,11 @@ impl<'a> Output<'a> {
|
|||
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
show_if_err!(self.dst.discard_cache(offset, len).map_err_context(|| {
|
||||
"failed to discard cache for: 'standard output'".to_string()
|
||||
}));
|
||||
show_if_err!(
|
||||
self.dst
|
||||
.discard_cache(offset, len)
|
||||
.map_err_context(|| { get_message("dd-error-failed-discard-cache-output") })
|
||||
);
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
|
@ -1083,7 +1125,7 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
|
|||
#[cfg(target_os = "linux")]
|
||||
if let Err(e) = &signal_handler {
|
||||
if Some(StatusLevel::None) != i.settings.status {
|
||||
eprintln!("Internal dd Warning: Unable to register signal handler \n\t{e}");
|
||||
eprintln!("{}\n\t{e}", get_message("dd-warning-signal-handler"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1419,7 +1461,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
None if is_stdout_redirected_to_seekable_file() => Output::new_file_from_stdout(&settings)?,
|
||||
None => Output::new_stdout(&settings)?,
|
||||
};
|
||||
dd_copy(i, o).map_err_context(|| "IO error".to_string())
|
||||
dd_copy(i, o).map_err_context(|| get_message("dd-error-io-error"))
|
||||
}
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
|
|
|
@ -9,42 +9,53 @@ mod unit_tests;
|
|||
|
||||
use super::{ConversionMode, IConvFlags, IFlags, Num, OConvFlags, OFlags, Settings, StatusLevel};
|
||||
use crate::conversion_tables::ConversionTable;
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::UError;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
use uucore::parser::parse_size::{ParseSizeError, Parser as SizeParser};
|
||||
use uucore::show_warning;
|
||||
|
||||
/// Parser Errors describe errors with parser input
|
||||
#[derive(Debug, PartialEq, Eq, Error)]
|
||||
pub enum ParseError {
|
||||
#[error("Unrecognized operand '{0}'")]
|
||||
#[error("{}", get_message_with_args("dd-error-unrecognized-operand",
|
||||
HashMap::from([("operand".to_string(), .0.clone())])))]
|
||||
UnrecognizedOperand(String),
|
||||
#[error("Only one of conv=ascii conv=ebcdic or conv=ibm may be specified")]
|
||||
#[error("{}", get_message("dd-error-multiple-format-table"))]
|
||||
MultipleFmtTable,
|
||||
#[error("Only one of conv=lcase or conv=ucase may be specified")]
|
||||
#[error("{}", get_message("dd-error-multiple-case"))]
|
||||
MultipleUCaseLCase,
|
||||
#[error("Only one of conv=block or conv=unblock may be specified")]
|
||||
#[error("{}", get_message("dd-error-multiple-block"))]
|
||||
MultipleBlockUnblock,
|
||||
#[error("Only one ov conv=excl or conv=nocreat may be specified")]
|
||||
#[error("{}", get_message("dd-error-multiple-excl"))]
|
||||
MultipleExclNoCreate,
|
||||
#[error("invalid input flag: ‘{}’\nTry '{} --help' for more information.", .0, uucore::execution_phrase())]
|
||||
#[error("{}", get_message_with_args("dd-error-invalid-flag",
|
||||
HashMap::from([("flag".to_string(), .0.clone()),("cmd".to_string(), uucore::execution_phrase().to_string())])))]
|
||||
FlagNoMatch(String),
|
||||
#[error("Unrecognized conv=CONV -> {0}")]
|
||||
#[error("{}", get_message_with_args("dd-error-conv-flag-no-match",
|
||||
HashMap::from([("flag".to_string(), .0.clone())])))]
|
||||
ConvFlagNoMatch(String),
|
||||
#[error("invalid number: ‘{0}’")]
|
||||
#[error("{}", get_message_with_args("dd-error-multiplier-parse-failure",
|
||||
HashMap::from([("input".to_string(), .0.clone())])))]
|
||||
MultiplierStringParseFailure(String),
|
||||
#[error("Multiplier string would overflow on current system -> {0}")]
|
||||
#[error("{}", get_message_with_args("dd-error-multiplier-overflow",
|
||||
HashMap::from([("input".to_string(), .0.clone())])))]
|
||||
MultiplierStringOverflow(String),
|
||||
#[error("conv=block or conv=unblock specified without cbs=N")]
|
||||
#[error("{}", get_message("dd-error-block-without-cbs"))]
|
||||
BlockUnblockWithoutCBS,
|
||||
#[error("status=LEVEL not recognized -> {0}")]
|
||||
#[error("{}", get_message_with_args("dd-error-status-not-recognized",
|
||||
HashMap::from([("level".to_string(), .0.clone())])))]
|
||||
StatusLevelNotRecognized(String),
|
||||
#[error("feature not implemented on this system -> {0}")]
|
||||
#[error("{}", get_message_with_args("dd-error-unimplemented",
|
||||
HashMap::from([("feature".to_string(), .0.clone())])))]
|
||||
Unimplemented(String),
|
||||
#[error("{0}=N cannot fit into memory")]
|
||||
#[error("{}", get_message_with_args("dd-error-bs-out-of-range",
|
||||
HashMap::from([("param".to_string(), .0.clone())])))]
|
||||
BsOutOfRange(String),
|
||||
#[error("invalid number: ‘{0}’")]
|
||||
#[error("{}", get_message_with_args("dd-error-invalid-number",
|
||||
HashMap::from([("input".to_string(), .0.clone())])))]
|
||||
InvalidNumber(String),
|
||||
}
|
||||
|
||||
|
@ -424,9 +435,14 @@ impl UError for ParseError {
|
|||
|
||||
fn show_zero_multiplier_warning() {
|
||||
show_warning!(
|
||||
"{} is a zero multiplier; use {} if that is intended",
|
||||
"0x".quote(),
|
||||
"00x".quote()
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"dd-warning-zero-multiplier",
|
||||
HashMap::from([
|
||||
("zero".to_string(), "0x".quote().to_string()),
|
||||
("alternative".to_string(), "00x".quote().to_string())
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
//! read and write progress of a running `dd` process. The
|
||||
//! [`gen_prog_updater`] function can be used to implement a progress
|
||||
//! updater that runs in its own thread.
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::sync::mpsc;
|
||||
#[cfg(target_os = "linux")]
|
||||
|
@ -20,6 +21,8 @@ use signal_hook::iterator::Handle;
|
|||
use uucore::{
|
||||
error::UResult,
|
||||
format::num_format::{FloatVariant, Formatter},
|
||||
locale::get_message_with_args,
|
||||
locale::setup_localization,
|
||||
};
|
||||
|
||||
use crate::numbers::{SuffixType, to_magnitude_and_suffix};
|
||||
|
@ -102,8 +105,13 @@ impl ProgUpdate {
|
|||
self.write_stat.report(w)?;
|
||||
match self.read_stat.records_truncated {
|
||||
0 => {}
|
||||
1 => writeln!(w, "1 truncated record")?,
|
||||
n => writeln!(w, "{n} truncated records")?,
|
||||
count => {
|
||||
let message = get_message_with_args(
|
||||
"dd-progress-truncated-record",
|
||||
HashMap::from([("count".to_string(), count.to_string())]),
|
||||
);
|
||||
writeln!(w, "{}", message)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -164,24 +172,45 @@ impl ProgUpdate {
|
|||
// If the number of bytes written is sufficiently large, then
|
||||
// print a more concise representation of the number, like
|
||||
// "1.2 kB" and "1.0 KiB".
|
||||
match btotal {
|
||||
1 => write!(
|
||||
w,
|
||||
"{carriage_return}{btotal} byte copied, {duration_str} s, {transfer_rate}/s{newline}",
|
||||
)?,
|
||||
0..=999 => write!(
|
||||
w,
|
||||
"{carriage_return}{btotal} bytes copied, {duration_str} s, {transfer_rate}/s{newline}",
|
||||
)?,
|
||||
1000..=1023 => write!(
|
||||
w,
|
||||
"{carriage_return}{btotal} bytes ({btotal_metric}) copied, {duration_str} s, {transfer_rate}/s{newline}",
|
||||
)?,
|
||||
_ => write!(
|
||||
w,
|
||||
"{carriage_return}{btotal} bytes ({btotal_metric}, {btotal_bin}) copied, {duration_str} s, {transfer_rate}/s{newline}",
|
||||
)?,
|
||||
let message = match btotal {
|
||||
1 => get_message_with_args(
|
||||
"dd-progress-byte-copied",
|
||||
HashMap::from([
|
||||
("bytes".to_string(), btotal.to_string()),
|
||||
("duration".to_string(), duration_str.to_string()),
|
||||
("rate".to_string(), transfer_rate.to_string()),
|
||||
]),
|
||||
),
|
||||
0..=999 => get_message_with_args(
|
||||
"dd-progress-bytes-copied",
|
||||
HashMap::from([
|
||||
("bytes".to_string(), btotal.to_string()),
|
||||
("duration".to_string(), duration_str.to_string()),
|
||||
("rate".to_string(), transfer_rate.to_string()),
|
||||
]),
|
||||
),
|
||||
1000..=1023 => get_message_with_args(
|
||||
"dd-progress-bytes-copied-si",
|
||||
HashMap::from([
|
||||
("bytes".to_string(), btotal.to_string()),
|
||||
("si".to_string(), btotal_metric.to_string()),
|
||||
("duration".to_string(), duration_str.to_string()),
|
||||
("rate".to_string(), transfer_rate.to_string()),
|
||||
]),
|
||||
),
|
||||
_ => get_message_with_args(
|
||||
"dd-progress-bytes-copied-si-iec",
|
||||
HashMap::from([
|
||||
("bytes".to_string(), btotal.to_string()),
|
||||
("si".to_string(), btotal_metric.to_string()),
|
||||
("iec".to_string(), btotal_bin.to_string()),
|
||||
("duration".to_string(), duration_str.to_string()),
|
||||
("rate".to_string(), transfer_rate.to_string()),
|
||||
]),
|
||||
),
|
||||
};
|
||||
|
||||
write!(w, "{carriage_return}{message}{newline}")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -311,11 +340,14 @@ impl ReadStat {
|
|||
///
|
||||
/// If there is a problem writing to `w`.
|
||||
fn report(&self, w: &mut impl Write) -> std::io::Result<()> {
|
||||
writeln!(
|
||||
w,
|
||||
"{}+{} records in",
|
||||
self.reads_complete, self.reads_partial
|
||||
)?;
|
||||
let message = get_message_with_args(
|
||||
"dd-progress-records-in",
|
||||
HashMap::from([
|
||||
("complete".to_string(), self.reads_complete.to_string()),
|
||||
("partial".to_string(), self.reads_partial.to_string()),
|
||||
]),
|
||||
);
|
||||
writeln!(w, "{}", message)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -368,11 +400,14 @@ impl WriteStat {
|
|||
///
|
||||
/// If there is a problem writing to `w`.
|
||||
fn report(&self, w: &mut impl Write) -> std::io::Result<()> {
|
||||
writeln!(
|
||||
w,
|
||||
"{}+{} records out",
|
||||
self.writes_complete, self.writes_partial
|
||||
)
|
||||
let message = get_message_with_args(
|
||||
"dd-progress-records-out",
|
||||
HashMap::from([
|
||||
("complete".to_string(), self.writes_complete.to_string()),
|
||||
("partial".to_string(), self.writes_partial.to_string()),
|
||||
]),
|
||||
);
|
||||
writeln!(w, "{}", message)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,6 +463,9 @@ pub(crate) fn gen_prog_updater(
|
|||
print_level: Option<StatusLevel>,
|
||||
) -> impl Fn() {
|
||||
move || {
|
||||
// As we are in a thread, we need to set up localization independently.
|
||||
let _ = setup_localization("dd");
|
||||
|
||||
let mut progress_printed = false;
|
||||
while let Ok(update) = rx.recv() {
|
||||
// Print the final read/write statistics.
|
||||
|
@ -502,6 +540,9 @@ pub(crate) fn gen_prog_updater(
|
|||
) -> impl Fn() {
|
||||
// --------------------------------------------------------------
|
||||
move || {
|
||||
// As we are in a thread, we need to set up localization independently.
|
||||
let _ = setup_localization("dd");
|
||||
|
||||
// Holds the state of whether we have printed the current progress.
|
||||
// This is needed so that we know whether or not to print a newline
|
||||
// character before outputting non-progress data.
|
||||
|
@ -532,11 +573,18 @@ pub(crate) fn gen_prog_updater(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::env;
|
||||
use std::io::Cursor;
|
||||
use std::time::Duration;
|
||||
use uucore::locale::setup_localization;
|
||||
|
||||
use super::{ProgUpdate, ReadStat, WriteStat};
|
||||
fn init() {
|
||||
unsafe {
|
||||
env::set_var("LANG", "C");
|
||||
}
|
||||
let _ = setup_localization("dd");
|
||||
}
|
||||
|
||||
fn prog_update_write(n: u128) -> ProgUpdate {
|
||||
ProgUpdate {
|
||||
|
@ -561,22 +609,31 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_read_stat_report() {
|
||||
init();
|
||||
let read_stat = ReadStat::new(1, 2, 3, 4);
|
||||
let mut cursor = Cursor::new(vec![]);
|
||||
read_stat.report(&mut cursor).unwrap();
|
||||
assert_eq!(cursor.get_ref(), b"1+2 records in\n");
|
||||
assert_eq!(
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"1+2 records in\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_stat_report() {
|
||||
init();
|
||||
let write_stat = WriteStat::new(1, 2, 3);
|
||||
let mut cursor = Cursor::new(vec![]);
|
||||
write_stat.report(&mut cursor).unwrap();
|
||||
assert_eq!(cursor.get_ref(), b"1+2 records out\n");
|
||||
assert_eq!(
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"1+2 records out\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prog_update_write_io_lines() {
|
||||
init();
|
||||
let read_stat = ReadStat::new(1, 2, 3, 4);
|
||||
let write_stat = WriteStat::new(4, 5, 6);
|
||||
let duration = Duration::new(789, 0);
|
||||
|
@ -591,13 +648,14 @@ mod tests {
|
|||
let mut cursor = Cursor::new(vec![]);
|
||||
prog_update.write_io_lines(&mut cursor).unwrap();
|
||||
assert_eq!(
|
||||
cursor.get_ref(),
|
||||
b"1+2 records in\n4+5 records out\n3 truncated records\n"
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"1+2 records in\n4+5 records out\n3 truncated records\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prog_update_write_prog_line() {
|
||||
init();
|
||||
let prog_update = ProgUpdate {
|
||||
read_stat: ReadStat::default(),
|
||||
write_stat: WriteStat::default(),
|
||||
|
@ -615,45 +673,55 @@ mod tests {
|
|||
// 0 bytes copied, 7.9151e-05 s, 0.0 kB/s
|
||||
//
|
||||
// The throughput still does not match GNU dd.
|
||||
assert_eq!(cursor.get_ref(), b"0 bytes copied, 1 s, 0.0 B/s\n");
|
||||
assert_eq!(
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"0 bytes copied, 1 s, 0.0 B/s\n"
|
||||
);
|
||||
|
||||
let prog_update = prog_update_write(1);
|
||||
let mut cursor = Cursor::new(vec![]);
|
||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||
assert_eq!(cursor.get_ref(), b"1 byte copied, 1 s, 0.0 B/s\n");
|
||||
assert_eq!(
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"1 byte copied, 1 s, 0.0 B/s\n"
|
||||
);
|
||||
|
||||
let prog_update = prog_update_write(999);
|
||||
let mut cursor = Cursor::new(vec![]);
|
||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||
assert_eq!(cursor.get_ref(), b"999 bytes copied, 1 s, 0.0 B/s\n");
|
||||
assert_eq!(
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"999 bytes copied, 1 s, 0.0 B/s\n"
|
||||
);
|
||||
|
||||
let prog_update = prog_update_write(1000);
|
||||
let mut cursor = Cursor::new(vec![]);
|
||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||
assert_eq!(
|
||||
cursor.get_ref(),
|
||||
b"1000 bytes (1.0 kB) copied, 1 s, 1.0 kB/s\n"
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"1000 bytes (1.0 kB) copied, 1 s, 1.0 kB/s\n"
|
||||
);
|
||||
|
||||
let prog_update = prog_update_write(1023);
|
||||
let mut cursor = Cursor::new(vec![]);
|
||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||
assert_eq!(
|
||||
cursor.get_ref(),
|
||||
b"1023 bytes (1.0 kB) copied, 1 s, 1.0 kB/s\n"
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"1023 bytes (1.0 kB) copied, 1 s, 1.0 kB/s\n"
|
||||
);
|
||||
|
||||
let prog_update = prog_update_write(1024);
|
||||
let mut cursor = Cursor::new(vec![]);
|
||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||
assert_eq!(
|
||||
cursor.get_ref(),
|
||||
b"1024 bytes (1.0 kB, 1.0 KiB) copied, 1 s, 1.0 kB/s\n"
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"1024 bytes (1.0 kB, 1.0 KiB) copied, 1 s, 1.0 kB/s\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_transfer_stats() {
|
||||
init();
|
||||
let prog_update = ProgUpdate {
|
||||
read_stat: ReadStat::default(),
|
||||
write_stat: WriteStat::default(),
|
||||
|
@ -664,16 +732,18 @@ mod tests {
|
|||
prog_update
|
||||
.write_transfer_stats(&mut cursor, false)
|
||||
.unwrap();
|
||||
let mut iter = cursor.get_ref().split(|v| *v == b'\n');
|
||||
assert_eq!(iter.next().unwrap(), b"0+0 records in");
|
||||
assert_eq!(iter.next().unwrap(), b"0+0 records out");
|
||||
assert_eq!(iter.next().unwrap(), b"0 bytes copied, 1 s, 0.0 B/s");
|
||||
assert_eq!(iter.next().unwrap(), b"");
|
||||
let output_str = std::str::from_utf8(cursor.get_ref()).unwrap();
|
||||
let mut iter = output_str.split('\n');
|
||||
assert_eq!(iter.next().unwrap(), "0+0 records in");
|
||||
assert_eq!(iter.next().unwrap(), "0+0 records out");
|
||||
assert_eq!(iter.next().unwrap(), "0 bytes copied, 1 s, 0.0 B/s");
|
||||
assert_eq!(iter.next().unwrap(), "");
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_final_transfer_stats() {
|
||||
init();
|
||||
// Tests the formatting of the final statistics written after a progress line.
|
||||
let prog_update = ProgUpdate {
|
||||
read_stat: ReadStat::default(),
|
||||
|
@ -685,21 +755,26 @@ mod tests {
|
|||
let rewrite = true;
|
||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||
prog_update.write_transfer_stats(&mut cursor, true).unwrap();
|
||||
let mut iter = cursor.get_ref().split(|v| *v == b'\n');
|
||||
assert_eq!(iter.next().unwrap(), b"\r0 bytes copied, 1 s, 0.0 B/s");
|
||||
assert_eq!(iter.next().unwrap(), b"0+0 records in");
|
||||
assert_eq!(iter.next().unwrap(), b"0+0 records out");
|
||||
assert_eq!(iter.next().unwrap(), b"0 bytes copied, 1 s, 0.0 B/s");
|
||||
assert_eq!(iter.next().unwrap(), b"");
|
||||
let output_str = std::str::from_utf8(cursor.get_ref()).unwrap();
|
||||
let mut iter = output_str.split('\n');
|
||||
assert_eq!(iter.next().unwrap(), "\r0 bytes copied, 1 s, 0.0 B/s");
|
||||
assert_eq!(iter.next().unwrap(), "0+0 records in");
|
||||
assert_eq!(iter.next().unwrap(), "0+0 records out");
|
||||
assert_eq!(iter.next().unwrap(), "0 bytes copied, 1 s, 0.0 B/s");
|
||||
assert_eq!(iter.next().unwrap(), "");
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_precision() {
|
||||
init();
|
||||
let prog_update = prog_update_duration(Duration::from_nanos(123));
|
||||
let mut cursor = Cursor::new(vec![]);
|
||||
let rewrite = false;
|
||||
prog_update.write_prog_line(&mut cursor, rewrite).unwrap();
|
||||
assert_eq!(cursor.get_ref(), b"0 bytes copied, 1.23e-07 s, 0.0 B/s\n");
|
||||
assert_eq!(
|
||||
std::str::from_utf8(cursor.get_ref()).unwrap(),
|
||||
"0 bytes copied, 0.000000123 s, 0.0 B/s\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,3 +8,53 @@ df-after-help = Display values are in units of the first available SIZE from --b
|
|||
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).
|
||||
|
||||
# Help messages
|
||||
df-help-print-help = Print help information.
|
||||
df-help-all = include dummy file systems
|
||||
df-help-block-size = scale sizes by SIZE before printing them; e.g. '-BM' prints sizes in units of 1,048,576 bytes
|
||||
df-help-total = produce a grand total
|
||||
df-help-human-readable = print sizes in human readable format (e.g., 1K 234M 2G)
|
||||
df-help-si = likewise, but use powers of 1000 not 1024
|
||||
df-help-inodes = list inode information instead of block usage
|
||||
df-help-kilo = like --block-size=1K
|
||||
df-help-local = limit listing to local file systems
|
||||
df-help-no-sync = do not invoke sync before getting usage info (default)
|
||||
df-help-output = use output format defined by FIELD_LIST, or print all fields if FIELD_LIST is omitted.
|
||||
df-help-portability = use the POSIX output format
|
||||
df-help-sync = invoke sync before getting usage info (non-windows only)
|
||||
df-help-type = limit listing to file systems of type TYPE
|
||||
df-help-print-type = print file system type
|
||||
df-help-exclude-type = limit listing to file systems not of type TYPE
|
||||
|
||||
# Error messages
|
||||
df-error-block-size-too-large = --block-size argument '{ $size }' too large
|
||||
df-error-invalid-block-size = invalid --block-size argument { $size }
|
||||
df-error-invalid-suffix = invalid suffix in --block-size argument { $size }
|
||||
df-error-field-used-more-than-once = option --output: field { $field } used more than once
|
||||
df-error-filesystem-type-both-selected-and-excluded = file system type { $type } both selected and excluded
|
||||
df-error-no-such-file-or-directory = { $path }: No such file or directory
|
||||
df-error-no-file-systems-processed = no file systems processed
|
||||
df-error-cannot-access-over-mounted = cannot access { $path }: over-mounted by another device
|
||||
df-error-cannot-read-table-of-mounted-filesystems = cannot read table of mounted file systems
|
||||
df-error-inodes-not-supported-windows = { $program }: doesn't support -i option
|
||||
|
||||
# Headers
|
||||
df-header-filesystem = Filesystem
|
||||
df-header-size = Size
|
||||
df-header-used = Used
|
||||
df-header-avail = Avail
|
||||
df-header-available = Available
|
||||
df-header-use-percent = Use%
|
||||
df-header-capacity = Capacity
|
||||
df-header-mounted-on = Mounted on
|
||||
df-header-inodes = Inodes
|
||||
df-header-iused = IUsed
|
||||
df-header-iavail = IFree
|
||||
df-header-iuse-percent = IUse%
|
||||
df-header-file = File
|
||||
df-header-type = Type
|
||||
|
||||
# Other
|
||||
df-total = total
|
||||
df-blocks-suffix = -blocks
|
||||
|
|
60
src/uu/df/locales/fr-FR.ftl
Normal file
60
src/uu/df/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,60 @@
|
|||
df-about = afficher des informations sur le système de fichiers sur lequel chaque FICHIER réside,
|
||||
ou tous les systèmes de fichiers par défaut.
|
||||
df-usage = df [OPTION]... [FICHIER]...
|
||||
df-after-help = Les valeurs affichées sont en unités de la première TAILLE disponible de --block-size,
|
||||
et des variables d'environnement DF_BLOCK_SIZE, BLOCK_SIZE et BLOCKSIZE.
|
||||
Sinon, les unités par défaut sont 1024 octets (ou 512 si POSIXLY_CORRECT est défini).
|
||||
|
||||
TAILLE est un entier et une unité optionnelle (exemple : 10M est 10*1024*1024).
|
||||
Les unités sont K, M, G, T, P, E, Z, Y (puissances de 1024) ou KB, MB,... (puissances
|
||||
de 1000).
|
||||
|
||||
# Messages d'aide
|
||||
df-help-print-help = afficher les informations d'aide.
|
||||
df-help-all = inclure les systèmes de fichiers factices
|
||||
df-help-block-size = mettre les tailles à l'échelle par TAILLE avant de les afficher ; par ex. '-BM' affiche les tailles en unités de 1 048 576 octets
|
||||
df-help-total = produire un total général
|
||||
df-help-human-readable = afficher les tailles dans un format lisible par l'homme (par ex., 1K 234M 2G)
|
||||
df-help-si = pareillement, mais utiliser les puissances de 1000 pas 1024
|
||||
df-help-inodes = lister les informations d'inode au lieu de l'utilisation des blocs
|
||||
df-help-kilo = comme --block-size=1K
|
||||
df-help-local = limiter l'affichage aux systèmes de fichiers locaux
|
||||
df-help-no-sync = ne pas invoquer sync avant d'obtenir les informations d'utilisation (par défaut)
|
||||
df-help-output = utiliser le format de sortie défini par LISTE_CHAMPS, ou afficher tous les champs si LISTE_CHAMPS est omise.
|
||||
df-help-portability = utiliser le format de sortie POSIX
|
||||
df-help-sync = invoquer sync avant d'obtenir les informations d'utilisation (non-windows seulement)
|
||||
df-help-type = limiter l'affichage aux systèmes de fichiers de type TYPE
|
||||
df-help-print-type = afficher le type de système de fichiers
|
||||
df-help-exclude-type = limiter l'affichage aux systèmes de fichiers pas de type TYPE
|
||||
|
||||
# Messages d'erreur
|
||||
df-error-block-size-too-large = argument --block-size '{ $size }' trop grand
|
||||
df-error-invalid-block-size = argument --block-size invalide { $size }
|
||||
df-error-invalid-suffix = suffixe invalide dans l'argument --block-size { $size }
|
||||
df-error-field-used-more-than-once = option --output : champ { $field } utilisé plus d'une fois
|
||||
df-error-filesystem-type-both-selected-and-excluded = type de système de fichiers { $type } à la fois sélectionné et exclu
|
||||
df-error-no-such-file-or-directory = { $path } : aucun fichier ou répertoire de ce type
|
||||
df-error-no-file-systems-processed = aucun système de fichiers traité
|
||||
df-error-cannot-access-over-mounted = impossible d'accéder à { $path } : sur-monté par un autre périphérique
|
||||
df-error-cannot-read-table-of-mounted-filesystems = impossible de lire la table des systèmes de fichiers montés
|
||||
df-error-inodes-not-supported-windows = { $program } : ne supporte pas l'option -i
|
||||
|
||||
# En-têtes du tableau
|
||||
df-header-filesystem = Sys. de fichiers
|
||||
df-header-size = Taille
|
||||
df-header-used = Utilisé
|
||||
df-header-avail = Disp.
|
||||
df-header-available = Disponible
|
||||
df-header-use-percent = Util%
|
||||
df-header-capacity = Capacité
|
||||
df-header-mounted-on = Monté sur
|
||||
df-header-inodes = Inodes
|
||||
df-header-iused = IUtil
|
||||
df-header-iavail = ILibre
|
||||
df-header-iuse-percent = IUtil%
|
||||
df-header-file = Fichier
|
||||
df-header-type = Type
|
||||
|
||||
# Autres messages
|
||||
df-total = total
|
||||
df-blocks-suffix = -blocs
|
|
@ -29,7 +29,8 @@ use crate::filesystem::Filesystem;
|
|||
use crate::filesystem::FsError;
|
||||
use crate::table::Table;
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use std::collections::HashMap;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
static OPT_HELP: &str = "help";
|
||||
static OPT_ALL: &str = "all";
|
||||
|
@ -115,25 +116,28 @@ impl Default for Options {
|
|||
enum OptionsError {
|
||||
// TODO This needs to vary based on whether `--block-size`
|
||||
// or `-B` were provided.
|
||||
#[error("--block-size argument '{0}' too large")]
|
||||
#[error("{}", get_message_with_args("df-error-block-size-too-large", HashMap::from([("size".to_string(), .0.clone())])))]
|
||||
BlockSizeTooLarge(String),
|
||||
// TODO This needs to vary based on whether `--block-size`
|
||||
// or `-B` were provided.,
|
||||
#[error("invalid --block-size argument {0}")]
|
||||
#[error("{}", get_message_with_args("df-error-invalid-block-size", HashMap::from([("size".to_string(), .0.clone())])))]
|
||||
InvalidBlockSize(String),
|
||||
// TODO This needs to vary based on whether `--block-size`
|
||||
// or `-B` were provided.
|
||||
#[error("invalid suffix in --block-size argument {0}")]
|
||||
#[error("{}", get_message_with_args("df-error-invalid-suffix", HashMap::from([("size".to_string(), .0.clone())])))]
|
||||
InvalidSuffix(String),
|
||||
|
||||
/// An error getting the columns to display in the output table.
|
||||
#[error("option --output: field {0} used more than once")]
|
||||
#[error("{}", get_message_with_args("df-error-field-used-more-than-once", HashMap::from([("field".to_string(), format!("{}", .0))])))]
|
||||
ColumnError(ColumnError),
|
||||
|
||||
#[error("{}", .0.iter()
|
||||
.map(|t| format!("file system type {} both selected and excluded", t.quote()))
|
||||
#[error(
|
||||
"{}",
|
||||
.0.iter()
|
||||
.map(|t| get_message_with_args("df-error-filesystem-type-both-selected-and-excluded", HashMap::from([("type".to_string(), t.quote().to_string())])))
|
||||
.collect::<Vec<_>>()
|
||||
.join(format!("\n{}: ", uucore::util_name()).as_str()))]
|
||||
.join(format!("\n{}: ", uucore::util_name()).as_str())
|
||||
)]
|
||||
FilesystemTypeBothSelectedAndExcluded(Vec<String>),
|
||||
}
|
||||
|
||||
|
@ -359,26 +363,35 @@ where
|
|||
Err(FsError::InvalidPath) => {
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
format!("{}: No such file or directory", path.as_ref().display())
|
||||
get_message_with_args(
|
||||
"df-error-no-such-file-or-directory",
|
||||
HashMap::from([("path".to_string(), path.as_ref().display().to_string())])
|
||||
)
|
||||
));
|
||||
}
|
||||
Err(FsError::MountMissing) => {
|
||||
show!(USimpleError::new(1, "no file systems processed"));
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
get_message("df-error-no-file-systems-processed")
|
||||
));
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
Err(FsError::OverMounted) => {
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"cannot access {}: over-mounted by another device",
|
||||
path.as_ref().quote()
|
||||
get_message_with_args(
|
||||
"df-error-cannot-access-over-mounted",
|
||||
HashMap::from([("path".to_string(), path.as_ref().quote().to_string())])
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
if get_exit_code() == 0 && result.is_empty() {
|
||||
show!(USimpleError::new(1, "no file systems processed"));
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
get_message("df-error-no-file-systems-processed")
|
||||
));
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -405,7 +418,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
#[cfg(windows)]
|
||||
{
|
||||
if matches.get_flag(OPT_INODES) {
|
||||
println!("{}: doesn't support -i option", uucore::util_name());
|
||||
println!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"df-error-inodes-not-supported-windows",
|
||||
HashMap::from([("program".to_string(), uucore::util_name().to_string())])
|
||||
)
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -415,12 +434,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let filesystems: Vec<Filesystem> = match matches.get_many::<String>(OPT_PATHS) {
|
||||
None => {
|
||||
let filesystems = get_all_filesystems(&opt).map_err(|e| {
|
||||
let context = "cannot read table of mounted file systems";
|
||||
let context = get_message("df-error-cannot-read-table-of-mounted-filesystems");
|
||||
USimpleError::new(e.code(), format!("{context}: {e}"))
|
||||
})?;
|
||||
|
||||
if filesystems.is_empty() {
|
||||
return Err(USimpleError::new(1, "no file systems processed"));
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
get_message("df-error-no-file-systems-processed"),
|
||||
));
|
||||
}
|
||||
|
||||
filesystems
|
||||
|
@ -428,7 +450,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
Some(paths) => {
|
||||
let paths: Vec<_> = paths.collect();
|
||||
let filesystems = get_named_filesystems(&paths, &opt).map_err(|e| {
|
||||
let context = "cannot read table of mounted file systems";
|
||||
let context = get_message("df-error-cannot-read-table-of-mounted-filesystems");
|
||||
USimpleError::new(e.code(), format!("{context}: {e}"))
|
||||
})?;
|
||||
|
||||
|
@ -458,7 +480,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(OPT_HELP)
|
||||
.long(OPT_HELP)
|
||||
.help("Print help information.")
|
||||
.help(get_message("df-help-print-help"))
|
||||
.action(ArgAction::Help),
|
||||
)
|
||||
.arg(
|
||||
|
@ -466,7 +488,7 @@ pub fn uu_app() -> Command {
|
|||
.short('a')
|
||||
.long("all")
|
||||
.overrides_with(OPT_ALL)
|
||||
.help("include dummy file systems")
|
||||
.help(get_message("df-help-all"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -475,16 +497,13 @@ pub fn uu_app() -> Command {
|
|||
.long("block-size")
|
||||
.value_name("SIZE")
|
||||
.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",
|
||||
),
|
||||
.help(get_message("df-help-block-size")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_TOTAL)
|
||||
.long("total")
|
||||
.overrides_with(OPT_TOTAL)
|
||||
.help("produce a grand total")
|
||||
.help(get_message("df-help-total"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -492,7 +511,7 @@ pub fn uu_app() -> Command {
|
|||
.short('h')
|
||||
.long("human-readable")
|
||||
.overrides_with_all([OPT_HUMAN_READABLE_DECIMAL, OPT_HUMAN_READABLE_BINARY])
|
||||
.help("print sizes in human readable format (e.g., 1K 234M 2G)")
|
||||
.help(get_message("df-help-human-readable"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -500,7 +519,7 @@ pub fn uu_app() -> Command {
|
|||
.short('H')
|
||||
.long("si")
|
||||
.overrides_with_all([OPT_HUMAN_READABLE_BINARY, OPT_HUMAN_READABLE_DECIMAL])
|
||||
.help("likewise, but use powers of 1000 not 1024")
|
||||
.help(get_message("df-help-si"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -508,13 +527,13 @@ pub fn uu_app() -> Command {
|
|||
.short('i')
|
||||
.long("inodes")
|
||||
.overrides_with(OPT_INODES)
|
||||
.help("list inode information instead of block usage")
|
||||
.help(get_message("df-help-inodes"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_KILO)
|
||||
.short('k')
|
||||
.help("like --block-size=1K")
|
||||
.help(get_message("df-help-kilo"))
|
||||
.overrides_with_all([OPT_BLOCKSIZE, OPT_KILO])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -523,14 +542,14 @@ pub fn uu_app() -> Command {
|
|||
.short('l')
|
||||
.long("local")
|
||||
.overrides_with(OPT_LOCAL)
|
||||
.help("limit listing to local file systems")
|
||||
.help(get_message("df-help-local"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_NO_SYNC)
|
||||
.long("no-sync")
|
||||
.overrides_with_all([OPT_SYNC, OPT_NO_SYNC])
|
||||
.help("do not invoke sync before getting usage info (default)")
|
||||
.help(get_message("df-help-no-sync"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -545,24 +564,21 @@ pub fn uu_app() -> Command {
|
|||
.default_missing_values(OUTPUT_FIELD_LIST)
|
||||
.default_values(["source", "size", "used", "avail", "pcent", "target"])
|
||||
.conflicts_with_all([OPT_INODES, OPT_PORTABILITY, OPT_PRINT_TYPE])
|
||||
.help(
|
||||
"use the output format defined by FIELD_LIST, \
|
||||
or print all fields if FIELD_LIST is omitted.",
|
||||
),
|
||||
.help(get_message("df-help-output")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_PORTABILITY)
|
||||
.short('P')
|
||||
.long("portability")
|
||||
.overrides_with(OPT_PORTABILITY)
|
||||
.help("use the POSIX output format")
|
||||
.help(get_message("df-help-portability"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_SYNC)
|
||||
.long("sync")
|
||||
.overrides_with_all([OPT_NO_SYNC, OPT_SYNC])
|
||||
.help("invoke sync before getting usage info (non-windows only)")
|
||||
.help(get_message("df-help-sync"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -572,14 +588,14 @@ pub fn uu_app() -> Command {
|
|||
.value_parser(ValueParser::os_string())
|
||||
.value_name("TYPE")
|
||||
.action(ArgAction::Append)
|
||||
.help("limit listing to file systems of type TYPE"),
|
||||
.help(get_message("df-help-type")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_PRINT_TYPE)
|
||||
.short('T')
|
||||
.long("print-type")
|
||||
.overrides_with(OPT_PRINT_TYPE)
|
||||
.help("print file system type")
|
||||
.help(get_message("df-help-print-type"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -590,7 +606,7 @@ pub fn uu_app() -> Command {
|
|||
.value_parser(ValueParser::os_string())
|
||||
.value_name("TYPE")
|
||||
.use_value_delimiter(true)
|
||||
.help("limit listing to file systems not of type TYPE"),
|
||||
.help(get_message("df-help-exclude-type")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_PATHS)
|
||||
|
|
|
@ -14,6 +14,7 @@ use crate::columns::{Alignment, Column};
|
|||
use crate::filesystem::Filesystem;
|
||||
use crate::{BlockSize, Options};
|
||||
use uucore::fsext::{FsUsage, MountInfo};
|
||||
use uucore::locale::get_message;
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::AddAssign;
|
||||
|
@ -106,7 +107,7 @@ impl AddAssign for Row {
|
|||
let inodes_used = self.inodes_used + rhs.inodes_used;
|
||||
*self = Self {
|
||||
file: None,
|
||||
fs_device: "total".into(),
|
||||
fs_device: get_message("df-total"),
|
||||
fs_type: "-".into(),
|
||||
fs_mount: "-".into(),
|
||||
bytes,
|
||||
|
@ -261,7 +262,7 @@ impl<'a> RowFormatter<'a> {
|
|||
let string = match column {
|
||||
Column::Source => {
|
||||
if self.is_total_row {
|
||||
"total".to_string()
|
||||
get_message("df-total")
|
||||
} else {
|
||||
self.row.fs_device.to_string()
|
||||
}
|
||||
|
@ -273,7 +274,7 @@ impl<'a> RowFormatter<'a> {
|
|||
|
||||
Column::Target => {
|
||||
if self.is_total_row && !self.options.columns.contains(&Column::Source) {
|
||||
"total".to_string()
|
||||
get_message("df-total")
|
||||
} else {
|
||||
self.row.fs_mount.to_string()
|
||||
}
|
||||
|
@ -325,32 +326,38 @@ impl Header {
|
|||
|
||||
for column in &options.columns {
|
||||
let header = match column {
|
||||
Column::Source => String::from("Filesystem"),
|
||||
Column::Source => get_message("df-header-filesystem"),
|
||||
Column::Size => match options.header_mode {
|
||||
HeaderMode::HumanReadable => String::from("Size"),
|
||||
HeaderMode::HumanReadable => get_message("df-header-size"),
|
||||
HeaderMode::PosixPortability => {
|
||||
format!("{}-blocks", options.block_size.as_u64())
|
||||
format!(
|
||||
"{}{}",
|
||||
options.block_size.as_u64(),
|
||||
get_message("df-blocks-suffix")
|
||||
)
|
||||
}
|
||||
_ => format!("{}-blocks", options.block_size),
|
||||
_ => format!("{}{}", options.block_size, get_message("df-blocks-suffix")),
|
||||
},
|
||||
Column::Used => String::from("Used"),
|
||||
Column::Used => get_message("df-header-used"),
|
||||
Column::Avail => match options.header_mode {
|
||||
HeaderMode::HumanReadable | HeaderMode::Output => String::from("Avail"),
|
||||
_ => String::from("Available"),
|
||||
HeaderMode::HumanReadable | HeaderMode::Output => {
|
||||
get_message("df-header-avail")
|
||||
}
|
||||
_ => get_message("df-header-available"),
|
||||
},
|
||||
Column::Pcent => match options.header_mode {
|
||||
HeaderMode::PosixPortability => String::from("Capacity"),
|
||||
_ => String::from("Use%"),
|
||||
HeaderMode::PosixPortability => get_message("df-header-capacity"),
|
||||
_ => get_message("df-header-use-percent"),
|
||||
},
|
||||
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"),
|
||||
Column::Target => get_message("df-header-mounted-on"),
|
||||
Column::Itotal => get_message("df-header-inodes"),
|
||||
Column::Iused => get_message("df-header-iused"),
|
||||
Column::Iavail => get_message("df-header-iavail"),
|
||||
Column::Ipcent => get_message("df-header-iuse-percent"),
|
||||
Column::File => get_message("df-header-file"),
|
||||
Column::Fstype => get_message("df-header-type"),
|
||||
#[cfg(target_os = "macos")]
|
||||
Column::Capacity => String::from("Capacity"),
|
||||
Column::Capacity => get_message("df-header-capacity"),
|
||||
};
|
||||
|
||||
headers.push(header);
|
||||
|
@ -383,7 +390,7 @@ impl Table {
|
|||
//
|
||||
// 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");
|
||||
let mut total = Row::new(&get_message("df-total"));
|
||||
|
||||
for filesystem in filesystems {
|
||||
// If the filesystem is not empty, or if the options require
|
||||
|
@ -440,8 +447,8 @@ impl fmt::Display for Table {
|
|||
while let Some((i, elem)) = col_iter.next() {
|
||||
let is_last_col = col_iter.peek().is_none();
|
||||
|
||||
match self.alignments[i] {
|
||||
Alignment::Left => {
|
||||
match self.alignments.get(i) {
|
||||
Some(Alignment::Left) => {
|
||||
if is_last_col {
|
||||
// no trailing spaces in last column
|
||||
write!(f, "{elem}")?;
|
||||
|
@ -449,7 +456,10 @@ impl fmt::Display for Table {
|
|||
write!(f, "{:<width$}", elem, width = self.widths[i])?;
|
||||
}
|
||||
}
|
||||
Alignment::Right => write!(f, "{:>width$}", elem, width = self.widths[i])?,
|
||||
Some(Alignment::Right) => {
|
||||
write!(f, "{:>width$}", elem, width = self.widths[i])?;
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
|
||||
if !is_last_col {
|
||||
|
@ -471,12 +481,20 @@ impl fmt::Display for Table {
|
|||
mod tests {
|
||||
|
||||
use std::vec;
|
||||
use uucore::locale::setup_localization;
|
||||
|
||||
use crate::blocks::HumanReadable;
|
||||
use crate::columns::Column;
|
||||
use crate::table::{Header, HeaderMode, Row, RowFormatter, Table};
|
||||
use crate::{BlockSize, Options};
|
||||
|
||||
fn init() {
|
||||
unsafe {
|
||||
std::env::set_var("LANG", "C");
|
||||
}
|
||||
let _ = setup_localization("df");
|
||||
}
|
||||
|
||||
const COLUMNS_WITH_FS_TYPE: [Column; 7] = [
|
||||
Column::Source,
|
||||
Column::Fstype,
|
||||
|
@ -521,7 +539,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_default_header() {
|
||||
init();
|
||||
let options = Options::default();
|
||||
|
||||
assert_eq!(
|
||||
Header::get_headers(&options),
|
||||
vec!(
|
||||
|
@ -537,6 +557,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_header_with_fs_type() {
|
||||
init();
|
||||
let options = Options {
|
||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||
..Default::default()
|
||||
|
@ -557,6 +578,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_header_with_inodes() {
|
||||
init();
|
||||
let options = Options {
|
||||
columns: COLUMNS_WITH_INODES.to_vec(),
|
||||
..Default::default()
|
||||
|
@ -576,6 +598,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_header_with_block_size_1024() {
|
||||
init();
|
||||
let options = Options {
|
||||
block_size: BlockSize::Bytes(3 * 1024),
|
||||
..Default::default()
|
||||
|
@ -595,6 +618,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_human_readable_header() {
|
||||
init();
|
||||
let options = Options {
|
||||
header_mode: HeaderMode::HumanReadable,
|
||||
..Default::default()
|
||||
|
@ -607,6 +631,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_posix_portability_header() {
|
||||
init();
|
||||
let options = Options {
|
||||
header_mode: HeaderMode::PosixPortability,
|
||||
..Default::default()
|
||||
|
@ -626,6 +651,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_output_header() {
|
||||
init();
|
||||
let options = Options {
|
||||
header_mode: HeaderMode::Output,
|
||||
..Default::default()
|
||||
|
@ -645,6 +671,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_formatter() {
|
||||
init();
|
||||
let options = Options {
|
||||
block_size: BlockSize::Bytes(1),
|
||||
..Default::default()
|
||||
|
@ -669,6 +696,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_formatter_with_fs_type() {
|
||||
init();
|
||||
let options = Options {
|
||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||
block_size: BlockSize::Bytes(1),
|
||||
|
@ -695,6 +723,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_formatter_with_inodes() {
|
||||
init();
|
||||
let options = Options {
|
||||
columns: COLUMNS_WITH_INODES.to_vec(),
|
||||
block_size: BlockSize::Bytes(1),
|
||||
|
@ -720,6 +749,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_formatter_with_bytes_and_inodes() {
|
||||
init();
|
||||
let options = Options {
|
||||
columns: vec![Column::Size, Column::Itotal],
|
||||
block_size: BlockSize::Bytes(100),
|
||||
|
@ -736,6 +766,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_formatter_with_human_readable_si() {
|
||||
init();
|
||||
let options = Options {
|
||||
human_readable: Some(HumanReadable::Decimal),
|
||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||
|
@ -762,6 +793,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_formatter_with_human_readable_binary() {
|
||||
init();
|
||||
let options = Options {
|
||||
human_readable: Some(HumanReadable::Binary),
|
||||
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||
|
@ -788,6 +820,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_formatter_with_round_up_usage() {
|
||||
init();
|
||||
let options = Options {
|
||||
columns: vec![Column::Pcent],
|
||||
..Default::default()
|
||||
|
@ -802,6 +835,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_formatter_with_round_up_byte_values() {
|
||||
init();
|
||||
fn get_formatted_values(bytes: u64, bytes_used: u64, bytes_avail: u64) -> Vec<String> {
|
||||
let options = Options {
|
||||
block_size: BlockSize::Bytes(1000),
|
||||
|
@ -826,6 +860,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_converter_with_invalid_numbers() {
|
||||
init();
|
||||
// copy from wsl linux
|
||||
let d = crate::Filesystem {
|
||||
file: None,
|
||||
|
@ -857,6 +892,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_table_column_width_computation_include_total_row() {
|
||||
init();
|
||||
let d1 = crate::Filesystem {
|
||||
file: None,
|
||||
mount_info: crate::MountInfo {
|
||||
|
@ -915,6 +951,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_row_accumulation_u64_overflow() {
|
||||
init();
|
||||
let total = u64::MAX as u128;
|
||||
let used1 = 3000u128;
|
||||
let used2 = 50000u128;
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::ffi::OsString;
|
|||
use std::path::Path;
|
||||
use uu_ls::{Config, Format, options};
|
||||
use uucore::error::UResult;
|
||||
use uucore::quoting_style::{Quotes, QuotingStyle};
|
||||
use uucore::quoting_style::QuotingStyle;
|
||||
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
|
@ -45,9 +45,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let mut config = Config::from(&matches)?;
|
||||
|
||||
if default_quoting_style {
|
||||
config.quoting_style = QuotingStyle::C {
|
||||
quotes: Quotes::None,
|
||||
};
|
||||
config.quoting_style = QuotingStyle::C_NO_QUOTES;
|
||||
}
|
||||
if default_format_style {
|
||||
config.format = Format::Columns;
|
||||
|
|
|
@ -230,7 +230,7 @@ fn get_size_on_disk(path: &Path) -> u64 {
|
|||
|
||||
unsafe {
|
||||
let mut file_info: FILE_STANDARD_INFO = core::mem::zeroed();
|
||||
let file_info_ptr: *mut FILE_STANDARD_INFO = &mut file_info;
|
||||
let file_info_ptr: *mut FILE_STANDARD_INFO = &raw mut file_info;
|
||||
|
||||
let success = GetFileInformationByHandleEx(
|
||||
file.as_raw_handle() as HANDLE,
|
||||
|
@ -257,7 +257,7 @@ fn get_file_info(path: &Path) -> Option<FileInfo> {
|
|||
|
||||
unsafe {
|
||||
let mut file_info: FILE_ID_INFO = core::mem::zeroed();
|
||||
let file_info_ptr: *mut FILE_ID_INFO = &mut file_info;
|
||||
let file_info_ptr: *mut FILE_ID_INFO = &raw mut file_info;
|
||||
|
||||
let success = GetFileInformationByHandleEx(
|
||||
file.as_raw_handle() as HANDLE,
|
||||
|
|
|
@ -16,3 +16,9 @@ echo-after-help = Echo the STRING(s) to standard output.
|
|||
- \v vertical tab
|
||||
- \0NNN byte with octal value NNN (1 to 3 digits)
|
||||
- \xHH byte with hexadecimal value HH (1 to 2 digits)
|
||||
|
||||
echo-help-no-newline = do not output the trailing newline
|
||||
echo-help-enable-escapes = enable interpretation of backslash escapes
|
||||
echo-help-disable-escapes = disable interpretation of backslash escapes (default)
|
||||
|
||||
echo-error-non-utf8 = Non-UTF-8 arguments provided, but this platform does not support them
|
||||
|
|
24
src/uu/echo/locales/fr-FR.ftl
Normal file
24
src/uu/echo/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,24 @@
|
|||
echo-about = Affiche une ligne de texte
|
||||
echo-usage = echo [OPTIONS]... [CHAÎNE]...
|
||||
echo-after-help = Affiche la ou les CHAÎNE(s) sur la sortie standard.
|
||||
|
||||
Si -e est activé, les séquences suivantes sont reconnues :
|
||||
|
||||
- \ barre oblique inverse
|
||||
- \a alerte (BEL)
|
||||
- \b retour arrière
|
||||
- \c ne produit aucune sortie supplémentaire
|
||||
- \e échappement
|
||||
- \f saut de page
|
||||
- \n nouvelle ligne
|
||||
- \r retour chariot
|
||||
- \t tabulation horizontale
|
||||
- \v tabulation verticale
|
||||
- \0NNN octet avec valeur octale NNN (1 à 3 chiffres)
|
||||
- \xHH octet avec valeur hexadécimale HH (1 à 2 chiffres)
|
||||
|
||||
echo-help-no-newline = ne pas afficher la nouvelle ligne finale
|
||||
echo-help-enable-escapes = activer l'interprétation des séquences d'échappement
|
||||
echo-help-disable-escapes = désactiver l'interprétation des séquences d'échappement (par défaut)
|
||||
|
||||
echo-error-non-utf8 = Arguments non-UTF-8 fournis, mais cette plateforme ne les prend pas en charge
|
|
@ -145,20 +145,20 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::NO_NEWLINE)
|
||||
.short('n')
|
||||
.help("do not output the trailing newline")
|
||||
.help(get_message("echo-help-no-newline"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ENABLE_BACKSLASH_ESCAPE)
|
||||
.short('e')
|
||||
.help("enable interpretation of backslash escapes")
|
||||
.help(get_message("echo-help-enable-escapes"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::DISABLE_BACKSLASH_ESCAPE),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DISABLE_BACKSLASH_ESCAPE)
|
||||
.short('E')
|
||||
.help("disable interpretation of backslash escapes (default)")
|
||||
.help(get_message("echo-help-disable-escapes"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::ENABLE_BACKSLASH_ESCAPE),
|
||||
)
|
||||
|
@ -177,10 +177,7 @@ fn execute(
|
|||
) -> UResult<()> {
|
||||
for (i, input) in arguments_after_options.into_iter().enumerate() {
|
||||
let Some(bytes) = bytes_from_os_string(input.as_os_str()) else {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
"Non-UTF-8 arguments provided, but this platform does not support them",
|
||||
));
|
||||
return Err(USimpleError::new(1, get_message("echo-error-non-utf8")));
|
||||
};
|
||||
|
||||
if i > 0 {
|
||||
|
|
40
src/uu/env/locales/en-US.ftl
vendored
40
src/uu/env/locales/en-US.ftl
vendored
|
@ -1,3 +1,43 @@
|
|||
env-about = Set each NAME to VALUE in the environment and run COMMAND
|
||||
env-usage = env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
|
||||
env-after-help = A mere - implies -i. If no COMMAND, print the resulting environment.
|
||||
|
||||
# Help messages
|
||||
env-help-ignore-environment = start with an empty environment
|
||||
env-help-chdir = change working directory to DIR
|
||||
env-help-null = end each output line with a 0 byte rather than a newline (only valid when printing the environment)
|
||||
env-help-file = read and set variables from a ".env"-style configuration file (prior to any unset and/or set)
|
||||
env-help-unset = remove variable from the environment
|
||||
env-help-debug = print verbose information for each processing step
|
||||
env-help-split-string = process and split S into separate arguments; used to pass multiple arguments on shebang lines
|
||||
env-help-argv0 = Override the zeroth argument passed to the command being executed. Without this option a default value of `command` is used.
|
||||
env-help-ignore-signal = set handling of SIG signal(s) to do nothing
|
||||
|
||||
# Error messages
|
||||
env-error-missing-closing-quote = no terminating quote in -S string at position { $position } for quote '{ $quote }'
|
||||
env-error-invalid-backslash-at-end = invalid backslash at end of string in -S at position { $position } in context { $context }
|
||||
env-error-backslash-c-not-allowed = '\c' must not appear in double-quoted -S string at position { $position }
|
||||
env-error-invalid-sequence = invalid sequence '\{ $char }' in -S at position { $position }
|
||||
env-error-missing-closing-brace = Missing closing brace at position { $position }
|
||||
env-error-missing-variable = Missing variable name at position { $position }
|
||||
env-error-missing-closing-brace-after-value = Missing closing brace after default value at position { $position }
|
||||
env-error-unexpected-number = Unexpected character: '{ $char }', expected variable name must not start with 0..9 at position { $position }
|
||||
env-error-expected-brace-or-colon = Unexpected character: '{ $char }', expected a closing brace ('{"}"}') or colon (':') at position { $position }
|
||||
env-error-cannot-specify-null-with-command = cannot specify --null (-0) with command
|
||||
env-error-invalid-signal = { $signal }: invalid signal
|
||||
env-error-config-file = { $file }: { $error }
|
||||
env-error-variable-name-issue = variable name issue (at { $position }): { $error }
|
||||
env-error-generic = Error: { $error }
|
||||
env-error-no-such-file = { $program }: No such file or directory
|
||||
env-error-use-s-shebang = use -[v]S to pass options in shebang lines
|
||||
env-error-cannot-unset = cannot unset '{ $name }': Invalid argument
|
||||
env-error-cannot-unset-invalid = cannot unset { $name }: Invalid argument
|
||||
env-error-must-specify-command-with-chdir = must specify command with --chdir (-C)
|
||||
env-error-cannot-change-directory = cannot change directory to { $directory }: { $error }
|
||||
env-error-argv0-not-supported = --argv0 is currently not supported on this platform
|
||||
env-error-permission-denied = { $program }: Permission denied
|
||||
env-error-unknown = unknown error: { $error }
|
||||
env-error-failed-set-signal-action = failed to set signal action for signal { $signal }: { $error }
|
||||
|
||||
# Warning messages
|
||||
env-warning-no-name-specified = no name specified for value { $value }
|
||||
|
|
43
src/uu/env/locales/fr-FR.ftl
vendored
Normal file
43
src/uu/env/locales/fr-FR.ftl
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
env-about = Définir chaque NOM à VALEUR dans l'environnement et exécuter COMMANDE
|
||||
env-usage = env [OPTION]... [-] [NOM=VALEUR]... [COMMANDE [ARG]...]
|
||||
env-after-help = Un simple - implique -i. Si aucune COMMANDE, afficher l'environnement résultant.
|
||||
|
||||
# Messages d'aide
|
||||
env-help-ignore-environment = commencer avec un environnement vide
|
||||
env-help-chdir = changer le répertoire de travail vers RÉP
|
||||
env-help-null = terminer chaque ligne de sortie avec un octet 0 plutôt qu'un retour à la ligne (valide uniquement lors de l'affichage de l'environnement)
|
||||
env-help-file = lire et définir les variables à partir d'un fichier de configuration de style ".env" (avant toute suppression et/ou définition)
|
||||
env-help-unset = supprimer la variable de l'environnement
|
||||
env-help-debug = afficher des informations détaillées pour chaque étape de traitement
|
||||
env-help-split-string = traiter et diviser S en arguments séparés ; utilisé pour passer plusieurs arguments sur les lignes shebang
|
||||
env-help-argv0 = Remplacer le zéroième argument passé à la commande en cours d'exécution. Sans cette option, une valeur par défaut de `command` est utilisée.
|
||||
env-help-ignore-signal = définir la gestion du/des signal/signaux SIG pour ne rien faire
|
||||
|
||||
# Messages d'erreur
|
||||
env-error-missing-closing-quote = aucune guillemet de fermeture dans la chaîne -S à la position { $position } pour la guillemet '{ $quote }'
|
||||
env-error-invalid-backslash-at-end = barre oblique inverse invalide à la fin de la chaîne dans -S à la position { $position } dans le contexte { $context }
|
||||
env-error-backslash-c-not-allowed = '\\c' ne doit pas apparaître dans une chaîne -S entre guillemets doubles à la position { $position }
|
||||
env-error-invalid-sequence = séquence invalide '\\{ $char }' dans -S à la position { $position }
|
||||
env-error-missing-closing-brace = Accolade fermante manquante à la position { $position }
|
||||
env-error-missing-variable = Nom de variable manquant à la position { $position }
|
||||
env-error-missing-closing-brace-after-value = Accolade fermante manquante après la valeur par défaut à la position { $position }
|
||||
env-error-unexpected-number = Caractère inattendu : '{ $char }', le nom de variable attendu ne doit pas commencer par 0..9 à la position { $position }
|
||||
env-error-expected-brace-or-colon = Caractère inattendu : '{ $char }', accolade fermante ('}') ou deux-points (':') attendu à la position { $position }
|
||||
env-error-cannot-specify-null-with-command = impossible de spécifier --null (-0) avec une commande
|
||||
env-error-invalid-signal = { $signal } : signal invalide
|
||||
env-error-config-file = { $file } : { $error }
|
||||
env-error-variable-name-issue = problème de nom de variable (à { $position }) : { $error }
|
||||
env-error-generic = Erreur : { $error }
|
||||
env-error-no-such-file = { $program } : Aucun fichier ou répertoire de ce type
|
||||
env-error-use-s-shebang = utilisez -[v]S pour passer des options dans les lignes shebang
|
||||
env-error-cannot-unset = impossible de supprimer '{ $name }' : Argument invalide
|
||||
env-error-cannot-unset-invalid = impossible de supprimer { $name } : Argument invalide
|
||||
env-error-must-specify-command-with-chdir = doit spécifier une commande avec --chdir (-C)
|
||||
env-error-cannot-change-directory = impossible de changer de répertoire vers { $directory } : { $error }
|
||||
env-error-argv0-not-supported = --argv0 n'est actuellement pas supporté sur cette plateforme
|
||||
env-error-permission-denied = { $program } : Permission refusée
|
||||
env-error-unknown = erreur inconnue : { $error }
|
||||
env-error-failed-set-signal-action = échec de la définition de l'action du signal pour le signal { $signal } : { $error }
|
||||
|
||||
# Messages d'avertissement
|
||||
env-warning-no-name-specified = aucun nom spécifié pour la valeur { $value }
|
233
src/uu/env/src/env.rs
vendored
233
src/uu/env/src/env.rs
vendored
|
@ -22,6 +22,7 @@ use nix::sys::signal::{
|
|||
SaFlags, SigAction, SigHandler, SigHandler::SigIgn, SigSet, Signal, raise, sigaction, signal,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::io::{self, Write};
|
||||
|
@ -34,6 +35,7 @@ use std::process::{self};
|
|||
use uucore::display::Quotable;
|
||||
use uucore::error::{ExitCode, UError, UResult, USimpleError, UUsageError};
|
||||
use uucore::line_ending::LineEnding;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
#[cfg(unix)]
|
||||
use uucore::signals::signal_by_name_or_value;
|
||||
use uucore::{format_usage, show_warning};
|
||||
|
@ -42,23 +44,23 @@ use thiserror::Error;
|
|||
|
||||
#[derive(Debug, Error, PartialEq)]
|
||||
pub enum EnvError {
|
||||
#[error("no terminating quote in -S string")]
|
||||
#[error("{}", get_message_with_args("env-error-missing-closing-quote", HashMap::from([("position".to_string(), .0.to_string()), ("quote".to_string(), .1.to_string())])))]
|
||||
EnvMissingClosingQuote(usize, char),
|
||||
#[error("invalid backslash at end of string in -S")]
|
||||
#[error("{}", get_message_with_args("env-error-invalid-backslash-at-end", HashMap::from([("position".to_string(), .0.to_string()), ("context".to_string(), .1.clone())])))]
|
||||
EnvInvalidBackslashAtEndOfStringInMinusS(usize, String),
|
||||
#[error("'\\c' must not appear in double-quoted -S string")]
|
||||
#[error("{}", get_message_with_args("env-error-backslash-c-not-allowed", HashMap::from([("position".to_string(), .0.to_string())])))]
|
||||
EnvBackslashCNotAllowedInDoubleQuotes(usize),
|
||||
#[error("invalid sequence '\\{}' in -S",.1)]
|
||||
#[error("{}", get_message_with_args("env-error-invalid-sequence", HashMap::from([("position".to_string(), .0.to_string()), ("char".to_string(), .1.to_string())])))]
|
||||
EnvInvalidSequenceBackslashXInMinusS(usize, char),
|
||||
#[error("Missing closing brace")]
|
||||
#[error("{}", get_message_with_args("env-error-missing-closing-brace", HashMap::from([("position".to_string(), .0.to_string())])))]
|
||||
EnvParsingOfVariableMissingClosingBrace(usize),
|
||||
#[error("Missing variable name")]
|
||||
#[error("{}", get_message_with_args("env-error-missing-variable", HashMap::from([("position".to_string(), .0.to_string())])))]
|
||||
EnvParsingOfMissingVariable(usize),
|
||||
#[error("Missing closing brace after default value at {}",.0)]
|
||||
#[error("{}", get_message_with_args("env-error-missing-closing-brace-after-value", HashMap::from([("position".to_string(), .0.to_string())])))]
|
||||
EnvParsingOfVariableMissingClosingBraceAfterValue(usize),
|
||||
#[error("Unexpected character: '{}', expected variable name must not start with 0..9",.1)]
|
||||
#[error("{}", get_message_with_args("env-error-unexpected-number", HashMap::from([("position".to_string(), .0.to_string()), ("char".to_string(), .1.clone())])))]
|
||||
EnvParsingOfVariableUnexpectedNumber(usize, String),
|
||||
#[error("Unexpected character: '{}', expected a closing brace ('}}') or colon (':')",.1)]
|
||||
#[error("{}", get_message_with_args("env-error-expected-brace-or-colon", HashMap::from([("position".to_string(), .0.to_string()), ("char".to_string(), .1.clone())])))]
|
||||
EnvParsingOfVariableExceptedBraceOrColon(usize, String),
|
||||
#[error("")]
|
||||
EnvReachedEnd,
|
||||
|
@ -74,8 +76,6 @@ impl From<string_parser::Error> for EnvError {
|
|||
}
|
||||
}
|
||||
|
||||
use uucore::locale::get_message;
|
||||
|
||||
mod options {
|
||||
pub const IGNORE_ENVIRONMENT: &str = "ignore-environment";
|
||||
pub const CHDIR: &str = "chdir";
|
||||
|
@ -88,8 +88,6 @@ mod options {
|
|||
pub const IGNORE_SIGNAL: &str = "ignore-signal";
|
||||
}
|
||||
|
||||
const ERROR_MSG_S_SHEBANG: &str = "use -[v]S to pass options in shebang lines";
|
||||
|
||||
struct Options<'a> {
|
||||
ignore_env: bool,
|
||||
line_ending: LineEnding,
|
||||
|
@ -131,7 +129,7 @@ fn parse_program_opt<'a>(opts: &mut Options<'a>, opt: &'a OsStr) -> UResult<()>
|
|||
if opts.line_ending == LineEnding::Nul {
|
||||
Err(UUsageError::new(
|
||||
125,
|
||||
"cannot specify --null (-0) with command".to_string(),
|
||||
get_message("env-error-cannot-specify-null-with-command"),
|
||||
))
|
||||
} else {
|
||||
opts.program.push(opt);
|
||||
|
@ -143,7 +141,13 @@ fn parse_program_opt<'a>(opts: &mut Options<'a>, opt: &'a OsStr) -> UResult<()>
|
|||
fn parse_signal_value(signal_name: &str) -> UResult<usize> {
|
||||
let signal_name_upcase = signal_name.to_uppercase();
|
||||
let optional_signal_value = signal_by_name_or_value(&signal_name_upcase);
|
||||
let error = USimpleError::new(125, format!("{}: invalid signal", signal_name.quote()));
|
||||
let error = USimpleError::new(
|
||||
125,
|
||||
get_message_with_args(
|
||||
"env-error-invalid-signal",
|
||||
HashMap::from([("signal".to_string(), signal_name.quote().to_string())]),
|
||||
),
|
||||
);
|
||||
match optional_signal_value {
|
||||
Some(sig_val) => {
|
||||
if sig_val == 0 {
|
||||
|
@ -177,7 +181,10 @@ fn parse_signal_opt<'a>(opts: &mut Options<'a>, opt: &'a OsStr) -> UResult<()> {
|
|||
let Some(sig_str) = sig.to_str() else {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("{}: invalid signal", sig.quote()),
|
||||
get_message_with_args(
|
||||
"env-error-invalid-signal",
|
||||
HashMap::from([("signal".to_string(), sig.quote().to_string())]),
|
||||
),
|
||||
));
|
||||
};
|
||||
let sig_val = parse_signal_value(sig_str)?;
|
||||
|
@ -201,8 +208,18 @@ fn load_config_file(opts: &mut Options) -> UResult<()> {
|
|||
Ini::load_from_file(file)
|
||||
};
|
||||
|
||||
let conf =
|
||||
conf.map_err(|e| USimpleError::new(1, format!("{}: {e}", file.maybe_quote())))?;
|
||||
let conf = conf.map_err(|e| {
|
||||
USimpleError::new(
|
||||
1,
|
||||
get_message_with_args(
|
||||
"env-error-config-file",
|
||||
HashMap::from([
|
||||
("file".to_string(), file.maybe_quote().to_string()),
|
||||
("error".to_string(), e.to_string()),
|
||||
]),
|
||||
),
|
||||
)
|
||||
})?;
|
||||
|
||||
for (_, prop) in &conf {
|
||||
// ignore all INI section lines (treat them as comments)
|
||||
|
@ -229,7 +246,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::IGNORE_ENVIRONMENT)
|
||||
.short('i')
|
||||
.long(options::IGNORE_ENVIRONMENT)
|
||||
.help("start with an empty environment")
|
||||
.help(get_message("env-help-ignore-environment"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -240,16 +257,13 @@ pub fn uu_app() -> Command {
|
|||
.value_name("DIR")
|
||||
.value_parser(ValueParser::os_string())
|
||||
.value_hint(clap::ValueHint::DirPath)
|
||||
.help("change working directory to DIR"),
|
||||
.help(get_message("env-help-chdir")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NULL)
|
||||
.short('0')
|
||||
.long(options::NULL)
|
||||
.help(
|
||||
"end each output line with a 0 byte rather than a newline (only \
|
||||
valid when printing the environment)",
|
||||
)
|
||||
.help(get_message("env-help-null"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -260,10 +274,7 @@ pub fn uu_app() -> Command {
|
|||
.value_hint(clap::ValueHint::FilePath)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.action(ArgAction::Append)
|
||||
.help(
|
||||
"read and set variables from a \".env\"-style configuration file \
|
||||
(prior to any unset and/or set)",
|
||||
),
|
||||
.help(get_message("env-help-file")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::UNSET)
|
||||
|
@ -272,14 +283,14 @@ pub fn uu_app() -> Command {
|
|||
.value_name("NAME")
|
||||
.action(ArgAction::Append)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.help("remove variable from the environment"),
|
||||
.help(get_message("env-help-unset")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DEBUG)
|
||||
.short('v')
|
||||
.long(options::DEBUG)
|
||||
.action(ArgAction::Count)
|
||||
.help("print verbose information for each processing step"),
|
||||
.help(get_message("env-help-debug")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SPLIT_STRING) // split string handling is implemented directly, not using CLAP. But this entry here is needed for the help information output.
|
||||
|
@ -288,8 +299,9 @@ pub fn uu_app() -> Command {
|
|||
.value_name("S")
|
||||
.action(ArgAction::Set)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.help("process and split S into separate arguments; used to pass multiple arguments on shebang lines")
|
||||
).arg(
|
||||
.help(get_message("env-help-split-string")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ARGV0)
|
||||
.overrides_with(options::ARGV0)
|
||||
.short('a')
|
||||
|
@ -297,13 +309,12 @@ pub fn uu_app() -> Command {
|
|||
.value_name("a")
|
||||
.action(ArgAction::Set)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.help("Override the zeroth argument passed to the command being executed. \
|
||||
Without this option a default value of `command` is used.")
|
||||
.help(get_message("env-help-argv0")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("vars")
|
||||
.action(ArgAction::Append)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.value_parser(ValueParser::os_string()),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::IGNORE_SIGNAL)
|
||||
|
@ -311,7 +322,7 @@ pub fn uu_app() -> Command {
|
|||
.value_name("SIG")
|
||||
.action(ArgAction::Append)
|
||||
.value_parser(ValueParser::os_string())
|
||||
.help("set handling of SIG signal(s) to do nothing")
|
||||
.help(get_message("env-help-ignore-signal")),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -325,22 +336,63 @@ pub fn parse_args_from_str(text: &NativeIntStr) -> UResult<Vec<NativeIntString>>
|
|||
USimpleError::new(125, e.to_string())
|
||||
}
|
||||
EnvError::EnvMissingClosingQuote(_, _) => USimpleError::new(125, e.to_string()),
|
||||
EnvError::EnvParsingOfVariableMissingClosingBrace(pos) => {
|
||||
USimpleError::new(125, format!("variable name issue (at {pos}): {e}"))
|
||||
}
|
||||
EnvError::EnvParsingOfMissingVariable(pos) => {
|
||||
USimpleError::new(125, format!("variable name issue (at {pos}): {e}"))
|
||||
}
|
||||
EnvError::EnvParsingOfVariableMissingClosingBraceAfterValue(pos) => {
|
||||
USimpleError::new(125, format!("variable name issue (at {pos}): {e}"))
|
||||
}
|
||||
EnvError::EnvParsingOfVariableUnexpectedNumber(pos, _) => {
|
||||
USimpleError::new(125, format!("variable name issue (at {pos}): {e}"))
|
||||
}
|
||||
EnvError::EnvParsingOfVariableExceptedBraceOrColon(pos, _) => {
|
||||
USimpleError::new(125, format!("variable name issue (at {pos}): {e}"))
|
||||
}
|
||||
_ => USimpleError::new(125, format!("Error: {e:?}")),
|
||||
EnvError::EnvParsingOfVariableMissingClosingBrace(pos) => USimpleError::new(
|
||||
125,
|
||||
get_message_with_args(
|
||||
"env-error-variable-name-issue",
|
||||
HashMap::from([
|
||||
("position".to_string(), pos.to_string()),
|
||||
("error".to_string(), e.to_string()),
|
||||
]),
|
||||
),
|
||||
),
|
||||
EnvError::EnvParsingOfMissingVariable(pos) => USimpleError::new(
|
||||
125,
|
||||
get_message_with_args(
|
||||
"env-error-variable-name-issue",
|
||||
HashMap::from([
|
||||
("position".to_string(), pos.to_string()),
|
||||
("error".to_string(), e.to_string()),
|
||||
]),
|
||||
),
|
||||
),
|
||||
EnvError::EnvParsingOfVariableMissingClosingBraceAfterValue(pos) => USimpleError::new(
|
||||
125,
|
||||
get_message_with_args(
|
||||
"env-error-variable-name-issue",
|
||||
HashMap::from([
|
||||
("position".to_string(), pos.to_string()),
|
||||
("error".to_string(), e.to_string()),
|
||||
]),
|
||||
),
|
||||
),
|
||||
EnvError::EnvParsingOfVariableUnexpectedNumber(pos, _) => USimpleError::new(
|
||||
125,
|
||||
get_message_with_args(
|
||||
"env-error-variable-name-issue",
|
||||
HashMap::from([
|
||||
("position".to_string(), pos.to_string()),
|
||||
("error".to_string(), e.to_string()),
|
||||
]),
|
||||
),
|
||||
),
|
||||
EnvError::EnvParsingOfVariableExceptedBraceOrColon(pos, _) => USimpleError::new(
|
||||
125,
|
||||
get_message_with_args(
|
||||
"env-error-variable-name-issue",
|
||||
HashMap::from([
|
||||
("position".to_string(), pos.to_string()),
|
||||
("error".to_string(), e.to_string()),
|
||||
]),
|
||||
),
|
||||
),
|
||||
_ => USimpleError::new(
|
||||
125,
|
||||
get_message_with_args(
|
||||
"env-error-generic",
|
||||
HashMap::from([("error".to_string(), format!("{e:?}"))]),
|
||||
),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -385,9 +437,15 @@ struct EnvAppData {
|
|||
|
||||
impl EnvAppData {
|
||||
fn make_error_no_such_file_or_dir(&self, prog: &OsStr) -> Box<dyn UError> {
|
||||
uucore::show_error!("{}: No such file or directory", prog.quote());
|
||||
uucore::show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"env-error-no-such-file",
|
||||
HashMap::from([("program".to_string(), prog.quote().to_string())])
|
||||
)
|
||||
);
|
||||
if !self.had_string_argument {
|
||||
uucore::show_error!("{ERROR_MSG_S_SHEBANG}");
|
||||
uucore::show_error!("{}", get_message("env-error-use-s-shebang"));
|
||||
}
|
||||
ExitCode::new(127)
|
||||
}
|
||||
|
@ -461,7 +519,10 @@ impl EnvAppData {
|
|||
{
|
||||
return Err(USimpleError::new(
|
||||
125,
|
||||
format!("cannot unset '{}': Invalid argument", &arg_str[2..]),
|
||||
get_message_with_args(
|
||||
"env-error-cannot-unset",
|
||||
HashMap::from([("name".to_string(), arg_str[2..].to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -493,7 +554,7 @@ impl EnvAppData {
|
|||
let s = s.trim_end();
|
||||
uucore::show_error!("{s}");
|
||||
}
|
||||
uucore::show_error!("{ERROR_MSG_S_SHEBANG}");
|
||||
uucore::show_error!("{}", get_message("env-error-use-s-shebang"));
|
||||
ExitCode::new(125)
|
||||
}
|
||||
}
|
||||
|
@ -578,7 +639,7 @@ impl EnvAppData {
|
|||
#[cfg(not(unix))]
|
||||
return Err(USimpleError::new(
|
||||
2,
|
||||
"--argv0 is currently not supported on this platform",
|
||||
get_message("env-error-argv0-not-supported"),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -629,11 +690,23 @@ impl EnvAppData {
|
|||
Err(self.make_error_no_such_file_or_dir(&prog))
|
||||
}
|
||||
io::ErrorKind::PermissionDenied => {
|
||||
uucore::show_error!("{}: Permission denied", prog.quote());
|
||||
uucore::show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"env-error-permission-denied",
|
||||
HashMap::from([("program".to_string(), prog.quote().to_string())])
|
||||
)
|
||||
);
|
||||
Err(126.into())
|
||||
}
|
||||
_ => {
|
||||
uucore::show_error!("unknown error: {err:?}");
|
||||
uucore::show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"env-error-unknown",
|
||||
HashMap::from([("error".to_string(), format!("{err:?}"))])
|
||||
)
|
||||
);
|
||||
Err(126.into())
|
||||
}
|
||||
};
|
||||
|
@ -722,7 +795,10 @@ fn apply_unset_env_vars(opts: &Options<'_>) -> Result<(), Box<dyn UError>> {
|
|||
{
|
||||
return Err(USimpleError::new(
|
||||
125,
|
||||
format!("cannot unset {}: Invalid argument", name.quote()),
|
||||
get_message_with_args(
|
||||
"env-error-cannot-unset-invalid",
|
||||
HashMap::from([("name".to_string(), name.quote().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
unsafe {
|
||||
|
@ -737,7 +813,7 @@ fn apply_change_directory(opts: &Options<'_>) -> Result<(), Box<dyn UError>> {
|
|||
if opts.program.is_empty() && opts.running_directory.is_some() {
|
||||
return Err(UUsageError::new(
|
||||
125,
|
||||
"must specify command with --chdir (-C)".to_string(),
|
||||
get_message("env-error-must-specify-command-with-chdir"),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -747,7 +823,13 @@ fn apply_change_directory(opts: &Options<'_>) -> Result<(), Box<dyn UError>> {
|
|||
Err(error) => {
|
||||
return Err(USimpleError::new(
|
||||
125,
|
||||
format!("cannot change directory to {}: {error}", d.quote()),
|
||||
get_message_with_args(
|
||||
"env-error-cannot-change-directory",
|
||||
HashMap::from([
|
||||
("directory".to_string(), d.quote().to_string()),
|
||||
("error".to_string(), error.to_string()),
|
||||
]),
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
@ -781,7 +863,13 @@ fn apply_specified_env_vars(opts: &Options<'_>) {
|
|||
*/
|
||||
|
||||
if name.is_empty() {
|
||||
show_warning!("no name specified for value {}", val.quote());
|
||||
show_warning!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"env-warning-no-name-specified",
|
||||
HashMap::from([("value".to_string(), val.quote().to_string())])
|
||||
)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
unsafe {
|
||||
|
@ -809,10 +897,12 @@ fn ignore_signal(sig: Signal) -> UResult<()> {
|
|||
if let Err(err) = result {
|
||||
return Err(USimpleError::new(
|
||||
125,
|
||||
format!(
|
||||
"failed to set signal action for signal {}: {}",
|
||||
sig as i32,
|
||||
err.desc()
|
||||
get_message_with_args(
|
||||
"env-error-failed-set-signal-action",
|
||||
HashMap::from([
|
||||
("signal".to_string(), (sig as i32).to_string()),
|
||||
("error".to_string(), err.desc().to_string()),
|
||||
]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
@ -827,6 +917,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use uucore::locale;
|
||||
|
||||
#[test]
|
||||
fn test_split_string_environment_vars_test() {
|
||||
|
@ -861,12 +952,14 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_error_cases() {
|
||||
let _ = locale::setup_localization("env");
|
||||
|
||||
// Test EnvBackslashCNotAllowedInDoubleQuotes
|
||||
let result = parse_args_from_str(&NCvt::convert(r#"sh -c "echo \c""#));
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.unwrap_err().to_string(),
|
||||
"'\\c' must not appear in double-quoted -S string"
|
||||
"'\\c' must not appear in double-quoted -S string at position 13"
|
||||
);
|
||||
|
||||
// Test EnvInvalidBackslashAtEndOfStringInMinusS
|
||||
|
@ -874,7 +967,7 @@ mod tests {
|
|||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.unwrap_err().to_string(),
|
||||
"no terminating quote in -S string"
|
||||
"no terminating quote in -S string at position 13 for quote '\"'"
|
||||
);
|
||||
|
||||
// Test EnvInvalidSequenceBackslashXInMinusS
|
||||
|
@ -892,7 +985,7 @@ mod tests {
|
|||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.unwrap_err().to_string(),
|
||||
"no terminating quote in -S string"
|
||||
"no terminating quote in -S string at position 12 for quote '\"'"
|
||||
);
|
||||
|
||||
// Test variable-related errors
|
||||
|
|
|
@ -381,10 +381,10 @@ fn expand_line(
|
|||
}
|
||||
} else {
|
||||
(
|
||||
match buf[byte] {
|
||||
match buf.get(byte) {
|
||||
// always take exactly 1 byte in strict ASCII mode
|
||||
0x09 => Tab,
|
||||
0x08 => Backspace,
|
||||
Some(0x09) => Tab,
|
||||
Some(0x08) => Backspace,
|
||||
_ => Other,
|
||||
},
|
||||
1,
|
||||
|
|
|
@ -21,6 +21,7 @@ path = "src/fmt.rs"
|
|||
clap = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "fmt"
|
||||
|
|
|
@ -1,2 +1,32 @@
|
|||
fmt-about = Reformat paragraphs from input files (or stdin) to stdout.
|
||||
fmt-usage = fmt [-WIDTH] [OPTION]... [FILE]...
|
||||
fmt-about = Reformat paragraphs from input (or standard input) to stdout.
|
||||
fmt-usage = [OPTION]... [FILE]...
|
||||
|
||||
# Help messages
|
||||
fmt-crown-margin-help = First and second line of paragraph may have different indentations, in which case the first line's indentation is preserved, and each subsequent line's indentation matches the second line.
|
||||
fmt-tagged-paragraph-help = Like -c, except that the first and second line of a paragraph *must* have different indentation or they are treated as separate paragraphs.
|
||||
fmt-preserve-headers-help = Attempt to detect and preserve mail headers in the input. Be careful when combining this flag with -p.
|
||||
fmt-split-only-help = Split lines only, do not reflow.
|
||||
fmt-uniform-spacing-help = Insert exactly one space between words, and two between sentences. Sentence breaks in the input are detected as [?!.] followed by two spaces or a newline; other punctuation is not interpreted as a sentence break.
|
||||
fmt-prefix-help = Reformat only lines beginning with PREFIX, reattaching PREFIX to reformatted lines. Unless -x is specified, leading whitespace will be ignored when matching PREFIX.
|
||||
fmt-skip-prefix-help = Do not reformat lines beginning with PSKIP. Unless -X is specified, leading whitespace will be ignored when matching PSKIP
|
||||
fmt-exact-prefix-help = PREFIX must match at the beginning of the line with no preceding whitespace.
|
||||
fmt-exact-skip-prefix-help = PSKIP must match at the beginning of the line with no preceding whitespace.
|
||||
fmt-width-help = Fill output lines up to a maximum of WIDTH columns, default 75. This can be specified as a negative number in the first argument.
|
||||
fmt-goal-help = Goal width, default of 93% of WIDTH. Must be less than or equal to WIDTH.
|
||||
fmt-quick-help = Break lines more quickly at the expense of a potentially more ragged appearance.
|
||||
fmt-tab-width-help = Treat tabs as TABWIDTH spaces for determining line length, default 8. Note that this is used only for calculating line lengths; tabs are preserved in the output.
|
||||
|
||||
# Error messages
|
||||
fmt-error-invalid-goal = invalid goal: {$goal}
|
||||
fmt-error-goal-greater-than-width = GOAL cannot be greater than WIDTH.
|
||||
fmt-error-invalid-width = invalid width: {$width}
|
||||
fmt-error-width-out-of-range = invalid width: '{$width}': Numerical result out of range
|
||||
fmt-error-invalid-tabwidth = Invalid TABWIDTH specification: {$tabwidth}
|
||||
fmt-error-first-option-width = invalid option -- {$option}; -WIDTH is recognized only when it is the first
|
||||
option; use -w N instead
|
||||
Try 'fmt --help' for more information.
|
||||
fmt-error-read = read error
|
||||
fmt-error-invalid-width-malformed = invalid width: {$width}
|
||||
fmt-error-cannot-open-for-reading = cannot open {$file} for reading
|
||||
fmt-error-cannot-get-metadata = cannot get metadata for {$file}
|
||||
fmt-error-failed-to-write-output = failed to write output
|
||||
|
|
32
src/uu/fmt/locales/fr-FR.ftl
Normal file
32
src/uu/fmt/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,32 @@
|
|||
fmt-about = Reformate les paragraphes depuis l'entrée (ou l'entrée standard) vers la sortie standard.
|
||||
fmt-usage = [OPTION]... [FICHIER]...
|
||||
|
||||
# Messages d'aide
|
||||
fmt-crown-margin-help = La première et la deuxième ligne d'un paragraphe peuvent avoir des indentations différentes, auquel cas l'indentation de la première ligne est préservée, et chaque ligne suivante correspond à l'indentation de la deuxième ligne.
|
||||
fmt-tagged-paragraph-help = Comme -c, sauf que la première et la deuxième ligne d'un paragraphe *doivent* avoir des indentations différentes ou elles sont traitées comme des paragraphes séparés.
|
||||
fmt-preserve-headers-help = Tente de détecter et préserver les en-têtes de courrier dans l'entrée. Attention en combinant ce drapeau avec -p.
|
||||
fmt-split-only-help = Divise les lignes seulement, ne les reformate pas.
|
||||
fmt-uniform-spacing-help = Insère exactement un espace entre les mots, et deux entre les phrases. Les fins de phrase dans l'entrée sont détectées comme [?!.] suivies de deux espaces ou d'une nouvelle ligne ; les autres ponctuations ne sont pas interprétées comme des fins de phrase.
|
||||
fmt-prefix-help = Reformate seulement les lignes commençant par PRÉFIXE, en rattachant PRÉFIXE aux lignes reformatées. À moins que -x soit spécifié, les espaces de début seront ignorés lors de la correspondance avec PRÉFIXE.
|
||||
fmt-skip-prefix-help = Ne reformate pas les lignes commençant par PSKIP. À moins que -X soit spécifié, les espaces de début seront ignorés lors de la correspondance avec PSKIP
|
||||
fmt-exact-prefix-help = PRÉFIXE doit correspondre au début de la ligne sans espace précédent.
|
||||
fmt-exact-skip-prefix-help = PSKIP doit correspondre au début de la ligne sans espace précédent.
|
||||
fmt-width-help = Remplit les lignes de sortie jusqu'à un maximum de WIDTH colonnes, par défaut 75. Cela peut être spécifié comme un nombre négatif dans le premier argument.
|
||||
fmt-goal-help = Largeur objectif, par défaut 93% de WIDTH. Doit être inférieur ou égal à WIDTH.
|
||||
fmt-quick-help = Divise les lignes plus rapidement au détriment d'un aspect potentiellement plus irrégulier.
|
||||
fmt-tab-width-help = Traite les tabulations comme TABWIDTH espaces pour déterminer la longueur de ligne, par défaut 8. Notez que ceci n'est utilisé que pour calculer les longueurs de ligne ; les tabulations sont préservées dans la sortie.
|
||||
|
||||
# Messages d'erreur
|
||||
fmt-error-invalid-goal = objectif invalide : {$goal}
|
||||
fmt-error-goal-greater-than-width = GOAL ne peut pas être supérieur à WIDTH.
|
||||
fmt-error-invalid-width = largeur invalide : {$width}
|
||||
fmt-error-width-out-of-range = largeur invalide : '{$width}' : Résultat numérique hors limites
|
||||
fmt-error-invalid-tabwidth = Spécification TABWIDTH invalide : {$tabwidth}
|
||||
fmt-error-first-option-width = option invalide -- {$option} ; -WIDTH n'est reconnu que lorsqu'il est la première
|
||||
option ; utilisez -w N à la place
|
||||
Essayez 'fmt --help' pour plus d'informations.
|
||||
fmt-error-read = erreur de lecture
|
||||
fmt-error-invalid-width-malformed = largeur invalide : {$width}
|
||||
fmt-error-cannot-open-for-reading = impossible d'ouvrir {$file} en lecture
|
||||
fmt-error-cannot-get-metadata = impossible d'obtenir les métadonnées pour {$file}
|
||||
fmt-error-failed-to-write-output = échec de l'écriture de sortie
|
|
@ -9,16 +9,45 @@ use clap::{Arg, ArgAction, ArgMatches, Command};
|
|||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter, Read, Stdout, Write, stdin, stdout};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
||||
use uucore::error::{FromIo, UResult, USimpleError};
|
||||
|
||||
use uucore::format_usage;
|
||||
|
||||
use linebreak::break_lines;
|
||||
use parasplit::ParagraphStream;
|
||||
use uucore::locale::get_message;
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
mod linebreak;
|
||||
mod parasplit;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum FmtError {
|
||||
#[error("{}", get_message_with_args("fmt-error-invalid-goal", HashMap::from([("goal".to_string(), .0.quote().to_string())])))]
|
||||
InvalidGoal(String),
|
||||
#[error("{}", get_message("fmt-error-goal-greater-than-width"))]
|
||||
GoalGreaterThanWidth,
|
||||
#[error("{}", get_message_with_args("fmt-error-invalid-width", HashMap::from([("width".to_string(), .0.quote().to_string())])))]
|
||||
InvalidWidth(String),
|
||||
#[error("{}", get_message_with_args("fmt-error-width-out-of-range", HashMap::from([("width".to_string(), .0.to_string())])))]
|
||||
WidthOutOfRange(usize),
|
||||
#[error("{}", get_message_with_args("fmt-error-invalid-tabwidth", HashMap::from([("tabwidth".to_string(), .0.quote().to_string())])))]
|
||||
InvalidTabWidth(String),
|
||||
#[error("{}", get_message_with_args("fmt-error-first-option-width", HashMap::from([("option".to_string(), .0.to_string())])))]
|
||||
FirstOptionWidth(char),
|
||||
#[error("{}", get_message("fmt-error-read"))]
|
||||
ReadError,
|
||||
#[error("{}", get_message_with_args("fmt-error-invalid-width-malformed", HashMap::from([("width".to_string(), .0.quote().to_string())])))]
|
||||
InvalidWidthMalformed(String),
|
||||
}
|
||||
|
||||
impl From<FmtError> for Box<dyn uucore::error::UError> {
|
||||
fn from(err: FmtError) -> Self {
|
||||
USimpleError::new(1, err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_WIDTH: usize = 2500;
|
||||
const DEFAULT_GOAL: usize = 70;
|
||||
const DEFAULT_WIDTH: usize = 75;
|
||||
|
@ -92,10 +121,7 @@ impl FmtOptions {
|
|||
match goal_str.parse::<usize>() {
|
||||
Ok(goal) => Some(goal),
|
||||
Err(_) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid goal: {}", goal_str.quote()),
|
||||
));
|
||||
return Err(FmtError::InvalidGoal(goal_str.clone()).into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -105,7 +131,7 @@ impl FmtOptions {
|
|||
let (width, goal) = match (width_opt, goal_opt) {
|
||||
(Some(w), Some(g)) => {
|
||||
if g > w {
|
||||
return Err(USimpleError::new(1, "GOAL cannot be greater than WIDTH."));
|
||||
return Err(FmtError::GoalGreaterThanWidth.into());
|
||||
}
|
||||
(w, g)
|
||||
}
|
||||
|
@ -119,7 +145,7 @@ impl FmtOptions {
|
|||
}
|
||||
(None, Some(g)) => {
|
||||
if g > DEFAULT_WIDTH {
|
||||
return Err(USimpleError::new(1, "GOAL cannot be greater than WIDTH."));
|
||||
return Err(FmtError::GoalGreaterThanWidth.into());
|
||||
}
|
||||
let w = (g * 100 / DEFAULT_GOAL_TO_WIDTH_RATIO).max(g + 3);
|
||||
(w, g)
|
||||
|
@ -132,21 +158,15 @@ impl FmtOptions {
|
|||
);
|
||||
|
||||
if width > MAX_WIDTH {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid width: '{width}': Numerical result out of range"),
|
||||
));
|
||||
return Err(FmtError::WidthOutOfRange(width).into());
|
||||
}
|
||||
|
||||
let mut tabwidth = 8;
|
||||
if let Some(s) = matches.get_one::<String>(options::TAB_WIDTH) {
|
||||
tabwidth = match s.parse::<usize>() {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("Invalid TABWIDTH specification: {}: {e}", s.quote()),
|
||||
));
|
||||
Err(_) => {
|
||||
return Err(FmtError::InvalidTabWidth(s.clone()).into());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -192,13 +212,22 @@ fn process_file(
|
|||
let mut fp = BufReader::new(match file_name {
|
||||
"-" => Box::new(stdin()) as Box<dyn Read + 'static>,
|
||||
_ => {
|
||||
let f = File::open(file_name)
|
||||
.map_err_context(|| format!("cannot open {} for reading", file_name.quote()))?;
|
||||
let f = File::open(file_name).map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"fmt-error-cannot-open-for-reading",
|
||||
HashMap::from([("file".to_string(), file_name.quote().to_string())]),
|
||||
)
|
||||
})?;
|
||||
if f.metadata()
|
||||
.map_err_context(|| format!("cannot get metadata for {}", file_name.quote()))?
|
||||
.map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"fmt-error-cannot-get-metadata",
|
||||
HashMap::from([("file".to_string(), file_name.quote().to_string())]),
|
||||
)
|
||||
})?
|
||||
.is_dir()
|
||||
{
|
||||
return Err(USimpleError::new(1, "read error".to_string()));
|
||||
return Err(FmtError::ReadError.into());
|
||||
}
|
||||
|
||||
Box::new(f) as Box<dyn Read + 'static>
|
||||
|
@ -211,20 +240,20 @@ fn process_file(
|
|||
Err(s) => {
|
||||
ostream
|
||||
.write_all(s.as_bytes())
|
||||
.map_err_context(|| "failed to write output".to_string())?;
|
||||
.map_err_context(|| get_message("fmt-error-failed-to-write-output"))?;
|
||||
ostream
|
||||
.write_all(b"\n")
|
||||
.map_err_context(|| "failed to write output".to_string())?;
|
||||
.map_err_context(|| get_message("fmt-error-failed-to-write-output"))?;
|
||||
}
|
||||
Ok(para) => break_lines(¶, fmt_opts, ostream)
|
||||
.map_err_context(|| "failed to write output".to_string())?,
|
||||
.map_err_context(|| get_message("fmt-error-failed-to-write-output"))?,
|
||||
}
|
||||
}
|
||||
|
||||
// flush the output after each file
|
||||
ostream
|
||||
.flush()
|
||||
.map_err_context(|| "failed to write output".to_string())?;
|
||||
.map_err_context(|| get_message("fmt-error-failed-to-write-output"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -251,10 +280,11 @@ fn extract_files(matches: &ArgMatches) -> UResult<Vec<String>> {
|
|||
if in_first_pos && i == 0 {
|
||||
None
|
||||
} else {
|
||||
let first_num = x.chars().nth(1).expect("a negative number should be at least two characters long");
|
||||
Some(Err(
|
||||
UUsageError::new(1, format!("invalid option -- {first_num}; -WIDTH is recognized only when it is the first\noption; use -w N instead"))
|
||||
))
|
||||
let first_num = x
|
||||
.chars()
|
||||
.nth(1)
|
||||
.expect("a negative number should be at least two characters long");
|
||||
Some(Err(FmtError::FirstOptionWidth(first_num).into()))
|
||||
}
|
||||
} else {
|
||||
Some(Ok(x.clone()))
|
||||
|
@ -275,10 +305,7 @@ fn extract_width(matches: &ArgMatches) -> UResult<Option<usize>> {
|
|||
return if let Ok(width) = width_str.parse::<usize>() {
|
||||
Ok(Some(width))
|
||||
} else {
|
||||
Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid width: {}", width_str.quote()),
|
||||
))
|
||||
Err(FmtError::InvalidWidth(width_str.clone()).into())
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -307,13 +334,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
&& first_arg.chars().nth(1).is_some_and(|c| c.is_ascii_digit())
|
||||
&& first_arg.chars().skip(2).any(|c| !c.is_ascii_digit());
|
||||
if malformed_number {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"invalid width: {}",
|
||||
first_arg.strip_prefix('-').unwrap().quote()
|
||||
),
|
||||
));
|
||||
return Err(FmtError::InvalidWidthMalformed(
|
||||
first_arg.strip_prefix('-').unwrap().to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,102 +367,70 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::CROWN_MARGIN)
|
||||
.short('c')
|
||||
.long(options::CROWN_MARGIN)
|
||||
.help(
|
||||
"First and second line of paragraph \
|
||||
may have different indentations, in which \
|
||||
case the first line's indentation is preserved, \
|
||||
and each subsequent line's indentation matches the second line.",
|
||||
)
|
||||
.help(get_message("fmt-crown-margin-help"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::TAGGED_PARAGRAPH)
|
||||
.short('t')
|
||||
.long("tagged-paragraph")
|
||||
.help(
|
||||
"Like -c, except that the first and second line of a paragraph *must* \
|
||||
have different indentation or they are treated as separate paragraphs.",
|
||||
)
|
||||
.help(get_message("fmt-tagged-paragraph-help"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PRESERVE_HEADERS)
|
||||
.short('m')
|
||||
.long("preserve-headers")
|
||||
.help(
|
||||
"Attempt to detect and preserve mail headers in the input. \
|
||||
Be careful when combining this flag with -p.",
|
||||
)
|
||||
.help(get_message("fmt-preserve-headers-help"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SPLIT_ONLY)
|
||||
.short('s')
|
||||
.long("split-only")
|
||||
.help("Split lines only, do not reflow.")
|
||||
.help(get_message("fmt-split-only-help"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::UNIFORM_SPACING)
|
||||
.short('u')
|
||||
.long("uniform-spacing")
|
||||
.help(
|
||||
"Insert exactly one \
|
||||
space between words, and two between sentences. \
|
||||
Sentence breaks in the input are detected as [?!.] \
|
||||
followed by two spaces or a newline; other punctuation \
|
||||
is not interpreted as a sentence break.",
|
||||
)
|
||||
.help(get_message("fmt-uniform-spacing-help"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PREFIX)
|
||||
.short('p')
|
||||
.long("prefix")
|
||||
.help(
|
||||
"Reformat only lines \
|
||||
beginning with PREFIX, reattaching PREFIX to reformatted lines. \
|
||||
Unless -x is specified, leading whitespace will be ignored \
|
||||
when matching PREFIX.",
|
||||
)
|
||||
.help(get_message("fmt-prefix-help"))
|
||||
.value_name("PREFIX"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SKIP_PREFIX)
|
||||
.short('P')
|
||||
.long("skip-prefix")
|
||||
.help(
|
||||
"Do not reformat lines \
|
||||
beginning with PSKIP. Unless -X is specified, leading whitespace \
|
||||
will be ignored when matching PSKIP",
|
||||
)
|
||||
.help(get_message("fmt-skip-prefix-help"))
|
||||
.value_name("PSKIP"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::EXACT_PREFIX)
|
||||
.short('x')
|
||||
.long("exact-prefix")
|
||||
.help(
|
||||
"PREFIX must match at the \
|
||||
beginning of the line with no preceding whitespace.",
|
||||
)
|
||||
.help(get_message("fmt-exact-prefix-help"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::EXACT_SKIP_PREFIX)
|
||||
.short('X')
|
||||
.long("exact-skip-prefix")
|
||||
.help(
|
||||
"PSKIP must match at the \
|
||||
beginning of the line with no preceding whitespace.",
|
||||
)
|
||||
.help(get_message("fmt-exact-skip-prefix-help"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::WIDTH)
|
||||
.short('w')
|
||||
.long("width")
|
||||
.help("Fill output lines up to a maximum of WIDTH columns, default 75. This can be specified as a negative number in the first argument.")
|
||||
.help(get_message("fmt-width-help"))
|
||||
// We must accept invalid values if they are overridden later. This is not supported by clap, so accept all strings instead.
|
||||
.value_name("WIDTH"),
|
||||
)
|
||||
|
@ -446,7 +438,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::GOAL)
|
||||
.short('g')
|
||||
.long("goal")
|
||||
.help("Goal width, default of 93% of WIDTH. Must be less than or equal to WIDTH.")
|
||||
.help(get_message("fmt-goal-help"))
|
||||
// We must accept invalid values if they are overridden later. This is not supported by clap, so accept all strings instead.
|
||||
.value_name("GOAL"),
|
||||
)
|
||||
|
@ -454,21 +446,14 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::QUICK)
|
||||
.short('q')
|
||||
.long("quick")
|
||||
.help(
|
||||
"Break lines more quickly at the \
|
||||
expense of a potentially more ragged appearance.",
|
||||
)
|
||||
.help(get_message("fmt-quick-help"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::TAB_WIDTH)
|
||||
.short('T')
|
||||
.long("tab-width")
|
||||
.help(
|
||||
"Treat tabs as TABWIDTH spaces for \
|
||||
determining line length, default 8. Note that this is used only for \
|
||||
calculating line lengths; tabs are preserved in the output.",
|
||||
)
|
||||
.help(get_message("fmt-tab-width-help"))
|
||||
.value_name("TABWIDTH"),
|
||||
)
|
||||
.arg(
|
||||
|
|
|
@ -236,7 +236,11 @@ fn find_kp_breakpoints<'a, T: Iterator<Item = &'a WordInfo<'a>>>(
|
|||
let mut next_active_breaks = vec![];
|
||||
|
||||
let stretch = args.opts.width - args.opts.goal;
|
||||
let minlength = args.opts.goal.max(stretch + 1) - stretch;
|
||||
let minlength = if args.opts.goal <= 10 {
|
||||
1
|
||||
} else {
|
||||
args.opts.goal.max(stretch + 1) - stretch
|
||||
};
|
||||
let mut new_linebreaks = vec![];
|
||||
let mut is_sentence_start = false;
|
||||
let mut least_demerits = 0;
|
||||
|
@ -384,11 +388,11 @@ fn build_best_path<'a>(paths: &[LineBreak<'a>], active: &[usize]) -> Vec<(&'a Wo
|
|||
const BAD_INFTY: i64 = 10_000_000;
|
||||
const BAD_INFTY_SQ: i64 = BAD_INFTY * BAD_INFTY;
|
||||
// badness = BAD_MULT * abs(r) ^ 3
|
||||
const BAD_MULT: f32 = 100.0;
|
||||
const BAD_MULT: f32 = 200.0;
|
||||
// DR_MULT is multiplier for delta-R between lines
|
||||
const DR_MULT: f32 = 600.0;
|
||||
// DL_MULT is penalty multiplier for short words at end of line
|
||||
const DL_MULT: f32 = 300.0;
|
||||
const DL_MULT: f32 = 10.0;
|
||||
|
||||
fn compute_demerits(delta_len: isize, stretch: usize, wlen: usize, prev_rat: f32) -> (i64, f32) {
|
||||
// how much stretch are we using?
|
||||
|
|
|
@ -26,6 +26,14 @@ fn char_width(c: char) -> usize {
|
|||
}
|
||||
}
|
||||
|
||||
// GNU fmt has a more restrictive definition of whitespace than Unicode.
|
||||
// It only considers ASCII whitespace characters (space, tab, newline, etc.)
|
||||
// and excludes many Unicode whitespace characters like non-breaking spaces.
|
||||
fn is_fmt_whitespace(c: char) -> bool {
|
||||
// Only ASCII whitespace characters are considered whitespace in GNU fmt
|
||||
matches!(c, ' ' | '\t' | '\n' | '\r' | '\x0B' | '\x0C')
|
||||
}
|
||||
|
||||
// lines with PSKIP, lacking PREFIX, or which are entirely blank are
|
||||
// NoFormatLines; otherwise, they are FormatLines
|
||||
#[derive(Debug)]
|
||||
|
@ -109,7 +117,7 @@ impl FileLines<'_> {
|
|||
for (i, char) in line.char_indices() {
|
||||
if line[i..].starts_with(pfx) {
|
||||
return (true, i);
|
||||
} else if !char.is_whitespace() {
|
||||
} else if !is_fmt_whitespace(char) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +136,7 @@ impl FileLines<'_> {
|
|||
prefix_len = indent_len;
|
||||
}
|
||||
|
||||
if (os >= prefix_end) && !c.is_whitespace() {
|
||||
if (os >= prefix_end) && !is_fmt_whitespace(c) {
|
||||
// found first non-whitespace after prefix, this is indent_end
|
||||
indent_end = os;
|
||||
break;
|
||||
|
@ -154,7 +162,7 @@ impl Iterator for FileLines<'_> {
|
|||
// emit a blank line
|
||||
// Err(true) indicates that this was a linebreak,
|
||||
// which is important to know when detecting mail headers
|
||||
if n.chars().all(char::is_whitespace) {
|
||||
if n.chars().all(is_fmt_whitespace) {
|
||||
return Some(Line::NoFormatLine(String::new(), true));
|
||||
}
|
||||
|
||||
|
@ -174,7 +182,7 @@ impl Iterator for FileLines<'_> {
|
|||
if pmatch
|
||||
&& n[poffset + self.opts.prefix.as_ref().map_or(0, |s| s.len())..]
|
||||
.chars()
|
||||
.all(char::is_whitespace)
|
||||
.all(is_fmt_whitespace)
|
||||
{
|
||||
return Some(Line::NoFormatLine(n, false));
|
||||
}
|
||||
|
@ -498,7 +506,7 @@ impl WordSplit<'_> {
|
|||
let mut aftertab = 0;
|
||||
let mut word_start = None;
|
||||
for (os, c) in string.char_indices() {
|
||||
if !c.is_whitespace() {
|
||||
if !is_fmt_whitespace(c) {
|
||||
word_start = Some(os);
|
||||
break;
|
||||
} else if c == '\t' {
|
||||
|
@ -519,7 +527,7 @@ impl WordSplit<'_> {
|
|||
impl WordSplit<'_> {
|
||||
fn new<'b>(opts: &'b FmtOptions, string: &'b str) -> WordSplit<'b> {
|
||||
// wordsplits *must* start at a non-whitespace character
|
||||
let trim_string = string.trim_start();
|
||||
let trim_string = string.trim_start_matches(is_fmt_whitespace);
|
||||
WordSplit {
|
||||
opts,
|
||||
string: trim_string,
|
||||
|
@ -571,7 +579,7 @@ impl<'a> Iterator for WordSplit<'a> {
|
|||
// points to whitespace character OR end of string
|
||||
let mut word_nchars = 0;
|
||||
self.position = match self.string[word_start..].find(|x: char| {
|
||||
if x.is_whitespace() {
|
||||
if is_fmt_whitespace(x) {
|
||||
true
|
||||
} else {
|
||||
word_nchars += char_width(x);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
use clap::{Arg, ArgAction, Command};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Read, stdin};
|
||||
use std::io::{BufRead, BufReader, Read, Write, stdin, stdout};
|
||||
use std::path::Path;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{FromIo, UResult, USimpleError};
|
||||
|
@ -16,6 +16,9 @@ use uucore::format_usage;
|
|||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
const TAB_WIDTH: usize = 8;
|
||||
const NL: u8 = b'\n';
|
||||
const CR: u8 = b'\r';
|
||||
const TAB: u8 = b'\t';
|
||||
|
||||
mod options {
|
||||
pub const BYTES: &str = "bytes";
|
||||
|
@ -141,18 +144,18 @@ fn fold(filenames: &[String], bytes: bool, spaces: bool, width: usize) -> UResul
|
|||
///
|
||||
/// If `spaces` is `true`, attempt to break lines at whitespace boundaries.
|
||||
fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> UResult<()> {
|
||||
let mut line = String::new();
|
||||
let mut line = Vec::new();
|
||||
|
||||
loop {
|
||||
if file
|
||||
.read_line(&mut line)
|
||||
.read_until(NL, &mut line)
|
||||
.map_err_context(|| get_message("fold-error-readline"))?
|
||||
== 0
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if line == "\n" {
|
||||
if line == [NL] {
|
||||
println!();
|
||||
line.truncate(0);
|
||||
continue;
|
||||
|
@ -166,8 +169,13 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
|
|||
let slice = {
|
||||
let slice = &line[i..i + width];
|
||||
if spaces && i + width < len {
|
||||
match slice.rfind(|c: char| c.is_whitespace() && c != '\r') {
|
||||
Some(m) => &slice[..=m],
|
||||
match slice
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find(|(_, c)| c.is_ascii_whitespace() && **c != CR)
|
||||
{
|
||||
Some((m, _)) => &slice[..=m],
|
||||
None => slice,
|
||||
}
|
||||
} else {
|
||||
|
@ -178,7 +186,7 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
|
|||
// Don't duplicate trailing newlines: if the slice is "\n", the
|
||||
// previous iteration folded just before the end of the line and
|
||||
// has already printed this newline.
|
||||
if slice == "\n" {
|
||||
if slice == [NL] {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -187,9 +195,10 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
|
|||
let at_eol = i >= len;
|
||||
|
||||
if at_eol {
|
||||
print!("{slice}");
|
||||
stdout().write_all(slice)?;
|
||||
} else {
|
||||
println!("{slice}");
|
||||
stdout().write_all(slice)?;
|
||||
stdout().write_all(&[NL])?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,8 +218,8 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
|
|||
#[allow(unused_assignments)]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> UResult<()> {
|
||||
let mut line = String::new();
|
||||
let mut output = String::new();
|
||||
let mut line = Vec::new();
|
||||
let mut output = Vec::new();
|
||||
let mut col_count = 0;
|
||||
let mut last_space = None;
|
||||
|
||||
|
@ -226,8 +235,9 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
|
|||
None => output.len(),
|
||||
};
|
||||
|
||||
println!("{}", &output[..consume]);
|
||||
output.replace_range(..consume, "");
|
||||
stdout().write_all(&output[..consume])?;
|
||||
stdout().write_all(&[NL])?;
|
||||
output.drain(..consume);
|
||||
|
||||
// we know there are no tabs left in output, so each char counts
|
||||
// as 1 column
|
||||
|
@ -239,15 +249,15 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
|
|||
|
||||
loop {
|
||||
if file
|
||||
.read_line(&mut line)
|
||||
.read_until(NL, &mut line)
|
||||
.map_err_context(|| get_message("fold-error-readline"))?
|
||||
== 0
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for ch in line.chars() {
|
||||
if ch == '\n' {
|
||||
for ch in &line {
|
||||
if *ch == NL {
|
||||
// make sure to _not_ split output at whitespace, since we
|
||||
// know the entire output will fit
|
||||
last_space = None;
|
||||
|
@ -259,9 +269,9 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
|
|||
emit_output!();
|
||||
}
|
||||
|
||||
match ch {
|
||||
'\r' => col_count = 0,
|
||||
'\t' => {
|
||||
match *ch {
|
||||
CR => col_count = 0,
|
||||
TAB => {
|
||||
let next_tab_stop = col_count + TAB_WIDTH - col_count % TAB_WIDTH;
|
||||
|
||||
if next_tab_stop > width && !output.is_empty() {
|
||||
|
@ -271,21 +281,21 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
|
|||
col_count = next_tab_stop;
|
||||
last_space = if spaces { Some(output.len()) } else { None };
|
||||
}
|
||||
'\x08' => {
|
||||
0x08 => {
|
||||
col_count = col_count.saturating_sub(1);
|
||||
}
|
||||
_ if spaces && ch.is_whitespace() => {
|
||||
_ if spaces && ch.is_ascii_whitespace() => {
|
||||
last_space = Some(output.len());
|
||||
col_count += 1;
|
||||
}
|
||||
_ => col_count += 1,
|
||||
}
|
||||
|
||||
output.push(ch);
|
||||
output.push(*ch);
|
||||
}
|
||||
|
||||
if !output.is_empty() {
|
||||
print!("{output}");
|
||||
stdout().write_all(&output)?;
|
||||
output.truncate(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,59 @@
|
|||
install-about = Copy SOURCE to DEST or multiple SOURCE(s) to the existing
|
||||
DIRECTORY, while setting permission modes and owner/group
|
||||
install-usage = install [OPTION]... [FILE]...
|
||||
|
||||
# Help messages
|
||||
install-help-ignored = ignored
|
||||
install-help-compare = compare each pair of source and destination files, and in some cases, do not modify the destination at all
|
||||
install-help-directory = treat all arguments as directory names. create all components of the specified directories
|
||||
install-help-create-leading = create all leading components of DEST except the last, then copy SOURCE to DEST
|
||||
install-help-group = set group ownership, instead of process's current group
|
||||
install-help-mode = set permission mode (as in chmod), instead of rwxr-xr-x
|
||||
install-help-owner = set ownership (super-user only)
|
||||
install-help-preserve-timestamps = apply access/modification times of SOURCE files to corresponding destination files
|
||||
install-help-strip = strip symbol tables (no action Windows)
|
||||
install-help-strip-program = program used to strip binaries (no action Windows)
|
||||
install-help-target-directory = move all SOURCE arguments into DIRECTORY
|
||||
install-help-no-target-directory = treat DEST as a normal file
|
||||
install-help-verbose = explain what is being done
|
||||
install-help-preserve-context = preserve security context
|
||||
install-help-context = set security context of files and directories
|
||||
|
||||
# Error messages
|
||||
install-error-dir-needs-arg = { $util_name } with -d requires at least one argument.
|
||||
install-error-create-dir-failed = failed to create { $path }
|
||||
install-error-chmod-failed = failed to chmod { $path }
|
||||
install-error-chmod-failed-detailed = { $path }: chmod failed with error { $error }
|
||||
install-error-chown-failed = failed to chown { $path }: { $error }
|
||||
install-error-invalid-target = invalid target { $path }: No such file or directory
|
||||
install-error-target-not-dir = target { $path } is not a directory
|
||||
install-error-backup-failed = cannot backup { $from } to { $to }
|
||||
install-error-install-failed = cannot install { $from } to { $to }
|
||||
install-error-strip-failed = strip program failed: { $error }
|
||||
install-error-strip-abnormal = strip process terminated abnormally - exit code: { $code }
|
||||
install-error-metadata-failed = metadata error
|
||||
install-error-invalid-user = invalid user: { $user }
|
||||
install-error-invalid-group = invalid group: { $group }
|
||||
install-error-omitting-directory = omitting directory { $path }
|
||||
install-error-not-a-directory = failed to access { $path }: Not a directory
|
||||
install-error-override-directory-failed = cannot overwrite directory { $dir } with non-directory { $file }
|
||||
install-error-same-file = '{ $file1 }' and '{ $file2 }' are the same file
|
||||
install-error-extra-operand = extra operand { $operand }
|
||||
{ $usage }
|
||||
install-error-invalid-mode = Invalid mode string: { $error }
|
||||
install-error-mutually-exclusive-target = Options --target-directory and --no-target-directory are mutually exclusive
|
||||
install-error-mutually-exclusive-compare-preserve = Options --compare and --preserve-timestamps are mutually exclusive
|
||||
install-error-mutually-exclusive-compare-strip = Options --compare and --strip are mutually exclusive
|
||||
install-error-missing-file-operand = missing file operand
|
||||
install-error-missing-destination-operand = missing destination file operand after '{ $path }'
|
||||
install-error-failed-to-remove = Failed to remove existing file { $path }. Error: { $error }
|
||||
|
||||
# Warning messages
|
||||
install-warning-compare-ignored = the --compare (-C) option is ignored when you specify a mode with non-permission bits
|
||||
|
||||
# Verbose output
|
||||
install-verbose-creating-directory = creating directory { $path }
|
||||
install-verbose-creating-directory-step = install: creating directory { $path }
|
||||
install-verbose-removed = removed { $path }
|
||||
install-verbose-copy = { $from } -> { $to }
|
||||
install-verbose-backup = (backup: { $backup })
|
||||
|
|
59
src/uu/install/locales/fr-FR.ftl
Normal file
59
src/uu/install/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,59 @@
|
|||
install-about = Copier SOURCE vers DEST ou plusieurs SOURCE(s) vers le
|
||||
RÉPERTOIRE existant, tout en définissant les modes de permission et propriétaire/groupe
|
||||
install-usage = install [OPTION]... [FICHIER]...
|
||||
|
||||
# Messages d'aide
|
||||
install-help-ignored = ignoré
|
||||
install-help-compare = comparer chaque paire de fichiers source et destination, et dans certains cas, ne pas modifier la destination du tout
|
||||
install-help-directory = traiter tous les arguments comme des noms de répertoires. créer tous les composants des répertoires spécifiés
|
||||
install-help-create-leading = créer tous les composants principaux de DEST sauf le dernier, puis copier SOURCE vers DEST
|
||||
install-help-group = définir la propriété du groupe, au lieu du groupe actuel du processus
|
||||
install-help-mode = définir le mode de permission (comme dans chmod), au lieu de rwxr-xr-x
|
||||
install-help-owner = définir la propriété (super-utilisateur uniquement)
|
||||
install-help-preserve-timestamps = appliquer les temps d'accès/modification des fichiers SOURCE aux fichiers de destination correspondants
|
||||
install-help-strip = supprimer les tables de symboles (aucune action Windows)
|
||||
install-help-strip-program = programme utilisé pour supprimer les binaires (aucune action Windows)
|
||||
install-help-target-directory = déplacer tous les arguments SOURCE dans RÉPERTOIRE
|
||||
install-help-no-target-directory = traiter DEST comme un fichier normal
|
||||
install-help-verbose = expliquer ce qui est fait
|
||||
install-help-preserve-context = préserver le contexte de sécurité
|
||||
install-help-context = définir le contexte de sécurité des fichiers et répertoires
|
||||
|
||||
# Messages d'erreur
|
||||
install-error-dir-needs-arg = { $util_name } avec -d nécessite au moins un argument.
|
||||
install-error-create-dir-failed = échec de la création de { $path }
|
||||
install-error-chmod-failed = échec du chmod { $path }
|
||||
install-error-chmod-failed-detailed = { $path } : échec du chmod avec l'erreur { $error }
|
||||
install-error-chown-failed = échec du chown { $path } : { $error }
|
||||
install-error-invalid-target = cible invalide { $path } : Aucun fichier ou répertoire de ce type
|
||||
install-error-target-not-dir = la cible { $path } n'est pas un répertoire
|
||||
install-error-backup-failed = impossible de sauvegarder { $from } vers { $to }
|
||||
install-error-install-failed = impossible d'installer { $from } vers { $to }
|
||||
install-error-strip-failed = échec du programme strip : { $error }
|
||||
install-error-strip-abnormal = le processus strip s'est terminé anormalement - code de sortie : { $code }
|
||||
install-error-metadata-failed = erreur de métadonnées
|
||||
install-error-invalid-user = utilisateur invalide : { $user }
|
||||
install-error-invalid-group = groupe invalide : { $group }
|
||||
install-error-omitting-directory = omission du répertoire { $path }
|
||||
install-error-not-a-directory = échec de l'accès à { $path } : N'est pas un répertoire
|
||||
install-error-override-directory-failed = impossible d'écraser le répertoire { $dir } avec un non-répertoire { $file }
|
||||
install-error-same-file = '{ $file1 }' et '{ $file2 }' sont le même fichier
|
||||
install-error-extra-operand = opérande supplémentaire { $operand }
|
||||
{ $usage }
|
||||
install-error-invalid-mode = Chaîne de mode invalide : { $error }
|
||||
install-error-mutually-exclusive-target = Les options --target-directory et --no-target-directory sont mutuellement exclusives
|
||||
install-error-mutually-exclusive-compare-preserve = Les options --compare et --preserve-timestamps sont mutuellement exclusives
|
||||
install-error-mutually-exclusive-compare-strip = Les options --compare et --strip sont mutuellement exclusives
|
||||
install-error-missing-file-operand = opérande de fichier manquant
|
||||
install-error-missing-destination-operand = opérande de fichier de destination manquant après '{ $path }'
|
||||
install-error-failed-to-remove = Échec de la suppression du fichier existant { $path }. Erreur : { $error }
|
||||
|
||||
# Messages d'avertissement
|
||||
install-warning-compare-ignored = l'option --compare (-C) est ignorée quand un mode est indiqué avec des bits non liés à des droits
|
||||
|
||||
# Sortie détaillée
|
||||
install-verbose-creating-directory = création du répertoire { $path }
|
||||
install-verbose-creating-directory-step = install : création du répertoire { $path }
|
||||
install-verbose-removed = supprimé { $path }
|
||||
install-verbose-copy = { $from } -> { $to }
|
||||
install-verbose-backup = (sauvegarde : { $backup })
|
|
@ -10,6 +10,7 @@ mod mode;
|
|||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use file_diff::diff;
|
||||
use filetime::{FileTime, set_file_times};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::fs::File;
|
||||
use std::fs::{self, metadata};
|
||||
|
@ -33,7 +34,7 @@ use uucore::{format_usage, show, show_error, show_if_err};
|
|||
use std::os::unix::fs::{FileTypeExt, MetadataExt};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::prelude::OsStrExt;
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
const DEFAULT_MODE: u32 = 0o755;
|
||||
const DEFAULT_STRIP_PROGRAM: &str = "strip";
|
||||
|
@ -60,55 +61,55 @@ pub struct Behavior {
|
|||
|
||||
#[derive(Error, Debug)]
|
||||
enum InstallError {
|
||||
#[error("{} with -d requires at least one argument.", uucore::util_name())]
|
||||
#[error("{}", get_message_with_args("install-error-dir-needs-arg", HashMap::from([("util_name".to_string(), uucore::util_name().to_string())])))]
|
||||
DirNeedsArg,
|
||||
|
||||
#[error("failed to create {0}")]
|
||||
#[error("{}", get_message_with_args("install-error-create-dir-failed", HashMap::from([("path".to_string(), .0.quote().to_string())])))]
|
||||
CreateDirFailed(PathBuf, #[source] std::io::Error),
|
||||
|
||||
#[error("failed to chmod {}", .0.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-chmod-failed", HashMap::from([("path".to_string(), .0.quote().to_string())])))]
|
||||
ChmodFailed(PathBuf),
|
||||
|
||||
#[error("failed to chown {}: {}", .0.quote(), .1)]
|
||||
#[error("{}", get_message_with_args("install-error-chown-failed", HashMap::from([("path".to_string(), .0.quote().to_string()), ("error".to_string(), .1.clone())])))]
|
||||
ChownFailed(PathBuf, String),
|
||||
|
||||
#[error("invalid target {}: No such file or directory", .0.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-invalid-target", HashMap::from([("path".to_string(), .0.quote().to_string())])))]
|
||||
InvalidTarget(PathBuf),
|
||||
|
||||
#[error("target {} is not a directory", .0.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-target-not-dir", HashMap::from([("path".to_string(), .0.quote().to_string())])))]
|
||||
TargetDirIsntDir(PathBuf),
|
||||
|
||||
#[error("cannot backup {0} to {1}")]
|
||||
#[error("{}", get_message_with_args("install-error-backup-failed", HashMap::from([("from".to_string(), .0.to_string_lossy().to_string()), ("to".to_string(), .1.to_string_lossy().to_string())])))]
|
||||
BackupFailed(PathBuf, PathBuf, #[source] std::io::Error),
|
||||
|
||||
#[error("cannot install {0} to {1}")]
|
||||
#[error("{}", get_message_with_args("install-error-install-failed", HashMap::from([("from".to_string(), .0.to_string_lossy().to_string()), ("to".to_string(), .1.to_string_lossy().to_string())])))]
|
||||
InstallFailed(PathBuf, PathBuf, #[source] std::io::Error),
|
||||
|
||||
#[error("strip program failed: {0}")]
|
||||
#[error("{}", get_message_with_args("install-error-strip-failed", HashMap::from([("error".to_string(), .0.clone())])))]
|
||||
StripProgramFailed(String),
|
||||
|
||||
#[error("metadata error")]
|
||||
#[error("{}", get_message("install-error-metadata-failed"))]
|
||||
MetadataFailed(#[source] std::io::Error),
|
||||
|
||||
#[error("invalid user: {}", .0.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-invalid-user", HashMap::from([("user".to_string(), .0.quote().to_string())])))]
|
||||
InvalidUser(String),
|
||||
|
||||
#[error("invalid group: {}", .0.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-invalid-group", HashMap::from([("group".to_string(), .0.quote().to_string())])))]
|
||||
InvalidGroup(String),
|
||||
|
||||
#[error("omitting directory {}", .0.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-omitting-directory", HashMap::from([("path".to_string(), .0.quote().to_string())])))]
|
||||
OmittingDirectory(PathBuf),
|
||||
|
||||
#[error("failed to access {}: Not a directory", .0.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-not-a-directory", HashMap::from([("path".to_string(), .0.quote().to_string())])))]
|
||||
NotADirectory(PathBuf),
|
||||
|
||||
#[error("cannot overwrite directory {} with non-directory {}", .0.quote(), .1.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-override-directory-failed", HashMap::from([("dir".to_string(), .0.quote().to_string()), ("file".to_string(), .1.quote().to_string())])))]
|
||||
OverrideDirectoryFailed(PathBuf, PathBuf),
|
||||
|
||||
#[error("'{0}' and '{1}' are the same file")]
|
||||
#[error("{}", get_message_with_args("install-error-same-file", HashMap::from([("file1".to_string(), .0.to_string_lossy().to_string()), ("file2".to_string(), .1.to_string_lossy().to_string())])))]
|
||||
SameFile(PathBuf, PathBuf),
|
||||
|
||||
#[error("extra operand {}\n{}", .0.quote(), .1.quote())]
|
||||
#[error("{}", get_message_with_args("install-error-extra-operand", HashMap::from([("operand".to_string(), .0.quote().to_string()), ("usage".to_string(), .1.clone())])))]
|
||||
ExtraOperand(String, String),
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
|
@ -186,62 +187,54 @@ pub fn uu_app() -> Command {
|
|||
.about(get_message("install-about"))
|
||||
.override_usage(format_usage(&get_message("install-usage")))
|
||||
.infer_long_args(true)
|
||||
.args_override_self(true)
|
||||
.arg(backup_control::arguments::backup())
|
||||
.arg(backup_control::arguments::backup_no_args())
|
||||
.arg(
|
||||
Arg::new(OPT_IGNORED)
|
||||
.short('c')
|
||||
.help("ignored")
|
||||
.help(get_message("install-help-ignored"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_COMPARE)
|
||||
.short('C')
|
||||
.long(OPT_COMPARE)
|
||||
.help(
|
||||
"compare each pair of source and destination files, and in some cases, \
|
||||
do not modify the destination at all",
|
||||
)
|
||||
.help(get_message("install-help-compare"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_DIRECTORY)
|
||||
.short('d')
|
||||
.long(OPT_DIRECTORY)
|
||||
.help(
|
||||
"treat all arguments as directory names. create all components of \
|
||||
the specified directories",
|
||||
)
|
||||
.help(get_message("install-help-directory"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_CREATE_LEADING)
|
||||
.short('D')
|
||||
.help(
|
||||
"create all leading components of DEST except the last, then copy \
|
||||
SOURCE to DEST",
|
||||
)
|
||||
.help(get_message("install-help-create-leading"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_GROUP)
|
||||
.short('g')
|
||||
.long(OPT_GROUP)
|
||||
.help("set group ownership, instead of process's current group")
|
||||
.help(get_message("install-help-group"))
|
||||
.value_name("GROUP"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_MODE)
|
||||
.short('m')
|
||||
.long(OPT_MODE)
|
||||
.help("set permission mode (as in chmod), instead of rwxr-xr-x")
|
||||
.help(get_message("install-help-mode"))
|
||||
.value_name("MODE"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_OWNER)
|
||||
.short('o')
|
||||
.long(OPT_OWNER)
|
||||
.help("set ownership (super-user only)")
|
||||
.help(get_message("install-help-owner"))
|
||||
.value_name("OWNER")
|
||||
.value_hint(clap::ValueHint::Username),
|
||||
)
|
||||
|
@ -249,23 +242,20 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_PRESERVE_TIMESTAMPS)
|
||||
.short('p')
|
||||
.long(OPT_PRESERVE_TIMESTAMPS)
|
||||
.help(
|
||||
"apply access/modification times of SOURCE files to \
|
||||
corresponding destination files",
|
||||
)
|
||||
.help(get_message("install-help-preserve-timestamps"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_STRIP)
|
||||
.short('s')
|
||||
.long(OPT_STRIP)
|
||||
.help("strip symbol tables (no action Windows)")
|
||||
.help(get_message("install-help-strip"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_STRIP_PROGRAM)
|
||||
.long(OPT_STRIP_PROGRAM)
|
||||
.help("program used to strip binaries (no action Windows)")
|
||||
.help(get_message("install-help-strip-program"))
|
||||
.value_name("PROGRAM")
|
||||
.value_hint(clap::ValueHint::CommandName),
|
||||
)
|
||||
|
@ -274,7 +264,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_TARGET_DIRECTORY)
|
||||
.short('t')
|
||||
.long(OPT_TARGET_DIRECTORY)
|
||||
.help("move all SOURCE arguments into DIRECTORY")
|
||||
.help(get_message("install-help-target-directory"))
|
||||
.value_name("DIRECTORY")
|
||||
.value_hint(clap::ValueHint::DirPath),
|
||||
)
|
||||
|
@ -282,28 +272,28 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_NO_TARGET_DIRECTORY)
|
||||
.short('T')
|
||||
.long(OPT_NO_TARGET_DIRECTORY)
|
||||
.help("treat DEST as a normal file")
|
||||
.help(get_message("install-help-no-target-directory"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_VERBOSE)
|
||||
.short('v')
|
||||
.long(OPT_VERBOSE)
|
||||
.help("explain what is being done")
|
||||
.help(get_message("install-help-verbose"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_PRESERVE_CONTEXT)
|
||||
.short('P')
|
||||
.long(OPT_PRESERVE_CONTEXT)
|
||||
.help("preserve security context")
|
||||
.help(get_message("install-help-preserve-context"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_CONTEXT)
|
||||
.short('Z')
|
||||
.long(OPT_CONTEXT)
|
||||
.help("set security context of files and directories")
|
||||
.help(get_message("install-help-context"))
|
||||
.value_name("CONTEXT")
|
||||
.value_parser(clap::value_parser!(String))
|
||||
.num_args(0..=1),
|
||||
|
@ -336,7 +326,13 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
|
|||
let specified_mode: Option<u32> = if matches.contains_id(OPT_MODE) {
|
||||
let x = matches.get_one::<String>(OPT_MODE).ok_or(1)?;
|
||||
Some(mode::parse(x, considering_dir, get_umask()).map_err(|err| {
|
||||
show_error!("Invalid mode string: {err}");
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"install-error-invalid-mode",
|
||||
HashMap::from([("error".to_string(), err)])
|
||||
)
|
||||
);
|
||||
1
|
||||
})?)
|
||||
} else {
|
||||
|
@ -347,7 +343,7 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
|
|||
let target_dir = matches.get_one::<String>(OPT_TARGET_DIRECTORY).cloned();
|
||||
let no_target_dir = matches.get_flag(OPT_NO_TARGET_DIRECTORY);
|
||||
if target_dir.is_some() && no_target_dir {
|
||||
show_error!("Options --target-directory and --no-target-directory are mutually exclusive");
|
||||
show_error!("{}", get_message("install-error-mutually-exclusive-target"));
|
||||
return Err(1.into());
|
||||
}
|
||||
|
||||
|
@ -355,14 +351,29 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
|
|||
let compare = matches.get_flag(OPT_COMPARE);
|
||||
let strip = matches.get_flag(OPT_STRIP);
|
||||
if preserve_timestamps && compare {
|
||||
show_error!("Options --compare and --preserve-timestamps are mutually exclusive");
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message("install-error-mutually-exclusive-compare-preserve")
|
||||
);
|
||||
return Err(1.into());
|
||||
}
|
||||
if compare && strip {
|
||||
show_error!("Options --compare and --strip are mutually exclusive");
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message("install-error-mutually-exclusive-compare-strip")
|
||||
);
|
||||
return Err(1.into());
|
||||
}
|
||||
|
||||
// Check if compare is used with non-permission mode bits
|
||||
if compare && specified_mode.is_some() {
|
||||
let mode = specified_mode.unwrap();
|
||||
let non_permission_bits = 0o7000; // setuid, setgid, sticky bits
|
||||
if mode & non_permission_bits != 0 {
|
||||
show_error!("{}", get_message("install-warning-compare-ignored"));
|
||||
}
|
||||
}
|
||||
|
||||
let owner = matches
|
||||
.get_one::<String>(OPT_OWNER)
|
||||
.map(|s| s.as_str())
|
||||
|
@ -456,7 +467,16 @@ fn directory(paths: &[String], b: &Behavior) -> UResult<()> {
|
|||
}
|
||||
|
||||
if b.verbose {
|
||||
println!("creating directory {}", path_to_create.quote());
|
||||
println!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"install-verbose-creating-directory",
|
||||
HashMap::from([(
|
||||
"path".to_string(),
|
||||
path_to_create.quote().to_string()
|
||||
)])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +531,10 @@ fn is_potential_directory_path(path: &Path) -> bool {
|
|||
fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
|
||||
// first check that paths contains at least one element
|
||||
if paths.is_empty() {
|
||||
return Err(UUsageError::new(1, "missing file operand"));
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
get_message("install-error-missing-file-operand"),
|
||||
));
|
||||
}
|
||||
if b.no_target_dir && paths.len() > 2 {
|
||||
return Err(InstallError::ExtraOperand(
|
||||
|
@ -531,9 +554,9 @@ fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
|
|||
if paths.is_empty() {
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
format!(
|
||||
"missing destination file operand after '{}'",
|
||||
last_path.to_str().unwrap()
|
||||
get_message_with_args(
|
||||
"install-error-missing-destination-operand",
|
||||
HashMap::from([("path".to_string(), last_path.to_str().unwrap().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
@ -570,7 +593,16 @@ fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
|
|||
result.push(part.as_os_str());
|
||||
if !result.is_dir() {
|
||||
// Don't display when the directory already exists
|
||||
println!("install: creating directory {}", result.quote());
|
||||
println!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"install-verbose-creating-directory-step",
|
||||
HashMap::from([(
|
||||
"path".to_string(),
|
||||
result.quote().to_string()
|
||||
)])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,7 +748,13 @@ fn chown_optional_user_group(path: &Path, b: &Behavior) -> UResult<()> {
|
|||
fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
|
||||
if to.exists() {
|
||||
if b.verbose {
|
||||
println!("removed {}", to.quote());
|
||||
println!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"install-verbose-removed",
|
||||
HashMap::from([("path".to_string(), to.quote().to_string())])
|
||||
)
|
||||
);
|
||||
}
|
||||
let backup_path = backup_control::get_backup_path(b.backup_mode, to, &b.suffix);
|
||||
if let Some(ref backup_path) = backup_path {
|
||||
|
@ -777,8 +815,14 @@ fn copy_file(from: &Path, to: &Path) -> UResult<()> {
|
|||
if let Err(e) = fs::remove_file(to) {
|
||||
if e.kind() != std::io::ErrorKind::NotFound {
|
||||
show_error!(
|
||||
"Failed to remove existing file {}. Error: {e:?}",
|
||||
to.display(),
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"install-error-failed-to-remove",
|
||||
HashMap::from([
|
||||
("path".to_string(), to.display().to_string()),
|
||||
("error".to_string(), format!("{e:?}"))
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -832,9 +876,9 @@ fn strip_file(to: &Path, b: &Behavior) -> UResult<()> {
|
|||
if !status.success() {
|
||||
// Follow GNU's behavior: if strip fails, removes the target
|
||||
let _ = fs::remove_file(to);
|
||||
return Err(InstallError::StripProgramFailed(format!(
|
||||
"strip process terminated abnormally - exit code: {}",
|
||||
status.code().unwrap()
|
||||
return Err(InstallError::StripProgramFailed(get_message_with_args(
|
||||
"install-error-strip-abnormal",
|
||||
HashMap::from([("code".to_string(), status.code().unwrap().to_string())]),
|
||||
))
|
||||
.into());
|
||||
}
|
||||
|
@ -912,7 +956,7 @@ fn preserve_timestamps(from: &Path, to: &Path) -> UResult<()> {
|
|||
/// If the copy system call fails, we print a verbose error and return an empty error value.
|
||||
///
|
||||
fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
|
||||
if b.compare && !need_copy(from, to, b)? {
|
||||
if b.compare && !need_copy(from, to, b) {
|
||||
return Ok(());
|
||||
}
|
||||
// Declare the path here as we may need it for the verbose output below.
|
||||
|
@ -940,9 +984,24 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
|
|||
}
|
||||
|
||||
if b.verbose {
|
||||
print!("{} -> {}", from.quote(), to.quote());
|
||||
print!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"install-verbose-copy",
|
||||
HashMap::from([
|
||||
("from".to_string(), from.quote().to_string()),
|
||||
("to".to_string(), to.quote().to_string())
|
||||
])
|
||||
)
|
||||
);
|
||||
match backup_path {
|
||||
Some(path) => println!(" (backup: {})", path.quote()),
|
||||
Some(path) => println!(
|
||||
" {}",
|
||||
get_message_with_args(
|
||||
"install-verbose-backup",
|
||||
HashMap::from([("backup".to_string(), path.quote().to_string())])
|
||||
)
|
||||
),
|
||||
None => println!(),
|
||||
}
|
||||
}
|
||||
|
@ -950,6 +1009,30 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if a file needs to be copied due to ownership differences when no explicit group is specified.
|
||||
/// Returns true if the destination file's ownership would differ from what it should be after installation.
|
||||
fn needs_copy_for_ownership(to: &Path, to_meta: &fs::Metadata) -> bool {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
// Check if the destination file's owner differs from the effective user ID
|
||||
if to_meta.uid() != geteuid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For group, we need to determine what the group would be after installation
|
||||
// If no group is specified, the behavior depends on the directory:
|
||||
// - If the directory has setgid bit, the file inherits the directory's group
|
||||
// - Otherwise, the file gets the user's effective group
|
||||
let expected_gid = to
|
||||
.parent()
|
||||
.and_then(|parent| metadata(parent).ok())
|
||||
.filter(|parent_meta| parent_meta.mode() & 0o2000 != 0)
|
||||
.map(|parent_meta| parent_meta.gid())
|
||||
.unwrap_or(getegid());
|
||||
|
||||
to_meta.gid() != expected_gid
|
||||
}
|
||||
|
||||
/// Return true if a file is necessary to copy. This is the case when:
|
||||
///
|
||||
/// - _from_ or _to_ is nonexistent;
|
||||
|
@ -967,19 +1050,26 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
|
|||
///
|
||||
/// Crashes the program if a nonexistent owner or group is specified in _b_.
|
||||
///
|
||||
fn need_copy(from: &Path, to: &Path, b: &Behavior) -> UResult<bool> {
|
||||
fn need_copy(from: &Path, to: &Path, b: &Behavior) -> bool {
|
||||
// Attempt to retrieve metadata for the source file.
|
||||
// If this fails, assume the file needs to be copied.
|
||||
let Ok(from_meta) = metadata(from) else {
|
||||
return Ok(true);
|
||||
return true;
|
||||
};
|
||||
|
||||
// Attempt to retrieve metadata for the destination file.
|
||||
// If this fails, assume the file needs to be copied.
|
||||
let Ok(to_meta) = metadata(to) else {
|
||||
return Ok(true);
|
||||
return true;
|
||||
};
|
||||
|
||||
// Check if the destination is a symlink (should always be replaced)
|
||||
if let Ok(to_symlink_meta) = fs::symlink_metadata(to) {
|
||||
if to_symlink_meta.file_type().is_symlink() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Define special file mode bits (setuid, setgid, sticky).
|
||||
let extra_mode: u32 = 0o7000;
|
||||
// Define all file mode bits (including permissions).
|
||||
|
@ -988,31 +1078,31 @@ fn need_copy(from: &Path, to: &Path, b: &Behavior) -> UResult<bool> {
|
|||
|
||||
// Check if any special mode bits are set in the specified mode,
|
||||
// source file mode, or destination file mode.
|
||||
if b.specified_mode.unwrap_or(0) & extra_mode != 0
|
||||
if b.mode() & extra_mode != 0
|
||||
|| from_meta.mode() & extra_mode != 0
|
||||
|| to_meta.mode() & extra_mode != 0
|
||||
{
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the mode of the destination file differs from the specified mode.
|
||||
if b.mode() != to_meta.mode() & all_modes {
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if either the source or destination is not a file.
|
||||
if !from_meta.is_file() || !to_meta.is_file() {
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the file sizes differ.
|
||||
if from_meta.len() != to_meta.len() {
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
if b.preserve_context && contexts_differ(from, to) {
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: if -P (#1809) and from/to contexts mismatch, return true.
|
||||
|
@ -1020,30 +1110,25 @@ fn need_copy(from: &Path, to: &Path, b: &Behavior) -> UResult<bool> {
|
|||
// Check if the owner ID is specified and differs from the destination file's owner.
|
||||
if let Some(owner_id) = b.owner_id {
|
||||
if owner_id != to_meta.uid() {
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the group ID is specified and differs from the destination file's group.
|
||||
if let Some(group_id) = b.group_id {
|
||||
if group_id != to_meta.gid() {
|
||||
return Ok(true);
|
||||
}
|
||||
} else {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
// Check if the destination file's owner or group
|
||||
// differs from the effective user/group ID of the process.
|
||||
if to_meta.uid() != geteuid() || to_meta.gid() != getegid() {
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
} else if needs_copy_for_ownership(to, &to_meta) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the contents of the source and destination files differ.
|
||||
if !diff(from.to_str().unwrap(), to.to_str().unwrap()) {
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use uucore::locale::get_message_with_args;
|
||||
#[cfg(not(windows))]
|
||||
use uucore::mode;
|
||||
|
||||
|
@ -25,7 +27,16 @@ pub fn chmod(path: &Path, mode: u32) -> Result<(), ()> {
|
|||
use std::os::unix::fs::PermissionsExt;
|
||||
use uucore::{display::Quotable, show_error};
|
||||
fs::set_permissions(path, fs::Permissions::from_mode(mode)).map_err(|err| {
|
||||
show_error!("{}: chmod failed with error {err}", path.maybe_quote());
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"install-error-chmod-failed-detailed",
|
||||
HashMap::from([
|
||||
("path".to_string(), path.maybe_quote().to_string()),
|
||||
("error".to_string(), err.to_string())
|
||||
])
|
||||
)
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -11,3 +11,28 @@ ln-after-help = In the 1st form, create a link to TARGET with the name LINK_NAME
|
|||
When creating hard links, each TARGET must exist. Symbolic links
|
||||
can hold arbitrary text; if later resolved, a relative link is
|
||||
interpreted in relation to its parent directory.
|
||||
|
||||
ln-help-force = remove existing destination files
|
||||
ln-help-interactive = prompt whether to remove existing destination files
|
||||
ln-help-no-dereference = treat LINK_NAME as a normal file if it is a
|
||||
symbolic link to a directory
|
||||
ln-help-logical = follow TARGETs that are symbolic links
|
||||
ln-help-physical = make hard links directly to symbolic links
|
||||
ln-help-symbolic = make symbolic links instead of hard links
|
||||
ln-help-target-directory = specify the DIRECTORY in which to create the links
|
||||
ln-help-no-target-directory = treat LINK_NAME as a normal file always
|
||||
ln-help-relative = create symbolic links relative to link location
|
||||
ln-help-verbose = print name of each linked file
|
||||
ln-error-target-is-not-directory = target {$target} is not a directory
|
||||
ln-error-same-file = {$file1} and {$file2} are the same file
|
||||
ln-error-missing-destination = missing destination file operand after {$operand}
|
||||
ln-error-extra-operand = extra operand {$operand}
|
||||
Try '{$program} --help' for more information.
|
||||
ln-error-could-not-update = Could not update {$target}: {$error}
|
||||
ln-error-cannot-stat = cannot stat {$path}: No such file or directory
|
||||
ln-error-will-not-overwrite = will not overwrite just-created '{$target}' with '{$source}'
|
||||
ln-prompt-replace = replace {$file}?
|
||||
ln-cannot-backup = cannot backup {$file}
|
||||
ln-failed-to-access = failed to access {$file}
|
||||
ln-failed-to-create-hard-link = failed to create hard link {$source} => {$dest}
|
||||
ln-backup = backup: {$backup}
|
||||
|
|
39
src/uu/ln/locales/fr-FR.ftl
Normal file
39
src/uu/ln/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,39 @@
|
|||
ln-about = Créer des liens entre fichiers
|
||||
ln-usage = ln [OPTION]... [-T] CIBLE NOM_LIEN
|
||||
ln [OPTION]... CIBLE
|
||||
ln [OPTION]... CIBLE... RÉPERTOIRE
|
||||
ln [OPTION]... -t RÉPERTOIRE CIBLE...
|
||||
ln-after-help = Dans la 1ère forme, créer un lien vers CIBLE avec le nom NOM_LIEN.
|
||||
Dans la 2ème forme, créer un lien vers CIBLE dans le répertoire courant.
|
||||
Dans les 3ème et 4ème formes, créer des liens vers chaque CIBLE dans RÉPERTOIRE.
|
||||
Créer des liens physiques par défaut, des liens symboliques avec --symbolic.
|
||||
Par défaut, chaque destination (nom du nouveau lien) ne doit pas déjà exister.
|
||||
Lors de la création de liens physiques, chaque CIBLE doit exister. Les liens symboliques
|
||||
peuvent contenir du texte arbitraire ; s'ils sont résolus plus tard, un lien relatif est
|
||||
interprété en relation avec son répertoire parent.
|
||||
|
||||
ln-help-force = supprimer les fichiers de destination existants
|
||||
ln-help-interactive = demander avant de supprimer les fichiers de destination existants
|
||||
ln-help-no-dereference = traiter NOM_LIEN comme un fichier normal s'il s'agit d'un
|
||||
lien symbolique vers un répertoire
|
||||
ln-help-logical = suivre les CIBLEs qui sont des liens symboliques
|
||||
ln-help-physical = créer des liens physiques directement vers les liens symboliques
|
||||
ln-help-symbolic = créer des liens symboliques au lieu de liens physiques
|
||||
ln-help-target-directory = spécifier le RÉPERTOIRE dans lequel créer les liens
|
||||
ln-help-no-target-directory = toujours traiter NOM_LIEN comme un fichier normal
|
||||
ln-help-relative = créer des liens symboliques relatifs à l'emplacement du lien
|
||||
ln-help-verbose = afficher le nom de chaque fichier lié
|
||||
|
||||
ln-error-target-is-not-directory = la cible {$target} n'est pas un répertoire
|
||||
ln-error-same-file = {$file1} et {$file2} sont le même fichier
|
||||
ln-error-missing-destination = opérande de fichier de destination manquant après {$operand}
|
||||
ln-error-extra-operand = opérande supplémentaire {$operand}
|
||||
Essayez « {$program} --help » pour plus d'informations.
|
||||
ln-error-could-not-update = Impossible de mettre à jour {$target} : {$error}
|
||||
ln-error-cannot-stat = impossible d'analyser {$path} : Aucun fichier ou répertoire de ce nom
|
||||
ln-error-will-not-overwrite = ne remplacera pas le fichier « {$target} » qui vient d'être créé par « {$source} »
|
||||
ln-prompt-replace = remplacer {$file} ?
|
||||
ln-cannot-backup = impossible de sauvegarder {$file}
|
||||
ln-failed-to-access = échec d'accès à {$file}
|
||||
ln-failed-to-create-hard-link = échec de création du lien physique {$source} => {$dest}
|
||||
ln-backup = sauvegarde : {$backup}
|
|
@ -17,6 +17,7 @@ use std::ffi::OsString;
|
|||
use std::fs;
|
||||
use thiserror::Error;
|
||||
|
||||
use std::collections::HashMap;
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
use std::os::unix::fs::symlink;
|
||||
#[cfg(windows)]
|
||||
|
@ -24,7 +25,7 @@ use std::os::windows::fs::{symlink_dir, symlink_file};
|
|||
use std::path::{Path, PathBuf};
|
||||
use uucore::backup_control::{self, BackupMode};
|
||||
use uucore::fs::{MissingHandling, ResolveMode, canonicalize};
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
pub struct Settings {
|
||||
overwrite: OverwriteMode,
|
||||
|
@ -48,20 +49,19 @@ pub enum OverwriteMode {
|
|||
|
||||
#[derive(Error, Debug)]
|
||||
enum LnError {
|
||||
#[error("target {} is not a directory", _0.quote())]
|
||||
#[error("{}", get_message_with_args("ln-error-target-is-not-directory", HashMap::from([("target".to_string(), _0.quote().to_string())])))]
|
||||
TargetIsNotADirectory(PathBuf),
|
||||
|
||||
#[error("")]
|
||||
SomeLinksFailed,
|
||||
|
||||
#[error("{} and {} are the same file", _0.quote(), _1.quote())]
|
||||
#[error("{}", get_message_with_args("ln-error-same-file", HashMap::from([("file1".to_string(), _0.quote().to_string()), ("file2".to_string(), _1.quote().to_string())])))]
|
||||
SameFile(PathBuf, PathBuf),
|
||||
|
||||
#[error("missing destination file operand after {}", _0.quote())]
|
||||
#[error("{}", get_message_with_args("ln-error-missing-destination", HashMap::from([("operand".to_string(), _0.quote().to_string())])))]
|
||||
MissingDestination(PathBuf),
|
||||
|
||||
#[error("extra operand {}\nTry '{} --help' for more information.",
|
||||
format!("{_0:?}").trim_matches('"'), _1)]
|
||||
#[error("{}", get_message_with_args("ln-error-extra-operand", HashMap::from([("operand".to_string(), format!("{_0:?}").trim_matches('"').to_string()), ("program".to_string(), _1.clone())])))]
|
||||
ExtraOperand(OsString, String),
|
||||
}
|
||||
|
||||
|
@ -157,31 +157,28 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::FORCE)
|
||||
.short('f')
|
||||
.long(options::FORCE)
|
||||
.help("remove existing destination files")
|
||||
.help(get_message("ln-help-force"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::INTERACTIVE)
|
||||
.short('i')
|
||||
.long(options::INTERACTIVE)
|
||||
.help("prompt whether to remove existing destination files")
|
||||
.help(get_message("ln-help-interactive"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NO_DEREFERENCE)
|
||||
.short('n')
|
||||
.long(options::NO_DEREFERENCE)
|
||||
.help(
|
||||
"treat LINK_NAME as a normal file if it is a \
|
||||
symbolic link to a directory",
|
||||
)
|
||||
.help(get_message("ln-help-no-dereference"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::LOGICAL)
|
||||
.short('L')
|
||||
.long(options::LOGICAL)
|
||||
.help("follow TARGETs that are symbolic links")
|
||||
.help(get_message("ln-help-logical"))
|
||||
.overrides_with(options::PHYSICAL)
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -190,14 +187,14 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::PHYSICAL)
|
||||
.short('P')
|
||||
.long(options::PHYSICAL)
|
||||
.help("make hard links directly to symbolic links")
|
||||
.help(get_message("ln-help-physical"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SYMBOLIC)
|
||||
.short('s')
|
||||
.long(options::SYMBOLIC)
|
||||
.help("make symbolic links instead of hard links")
|
||||
.help(get_message("ln-help-symbolic"))
|
||||
// override added for https://github.com/uutils/coreutils/issues/2359
|
||||
.overrides_with(options::SYMBOLIC)
|
||||
.action(ArgAction::SetTrue),
|
||||
|
@ -207,7 +204,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::TARGET_DIRECTORY)
|
||||
.short('t')
|
||||
.long(options::TARGET_DIRECTORY)
|
||||
.help("specify the DIRECTORY in which to create the links")
|
||||
.help(get_message("ln-help-target-directory"))
|
||||
.value_name("DIRECTORY")
|
||||
.value_hint(clap::ValueHint::DirPath)
|
||||
.conflicts_with(options::NO_TARGET_DIRECTORY),
|
||||
|
@ -216,14 +213,14 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::NO_TARGET_DIRECTORY)
|
||||
.short('T')
|
||||
.long(options::NO_TARGET_DIRECTORY)
|
||||
.help("treat LINK_NAME as a normal file always")
|
||||
.help(get_message("ln-help-no-target-directory"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::RELATIVE)
|
||||
.short('r')
|
||||
.long(options::RELATIVE)
|
||||
.help("create symbolic links relative to link location")
|
||||
.help(get_message("ln-help-relative"))
|
||||
.requires(options::SYMBOLIC)
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -231,7 +228,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::VERBOSE)
|
||||
.short('v')
|
||||
.long(options::VERBOSE)
|
||||
.help("print name of each linked file")
|
||||
.help(get_message("ln-help-verbose"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -296,7 +293,16 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings)
|
|||
// We need to clean the target
|
||||
if target_dir.is_file() {
|
||||
if let Err(e) = fs::remove_file(target_dir) {
|
||||
show_error!("Could not update {}: {e}", target_dir.quote());
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ln-error-could-not-update",
|
||||
HashMap::from([
|
||||
("target".to_string(), target_dir.quote().to_string()),
|
||||
("error".to_string(), e.to_string())
|
||||
])
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
#[cfg(windows)]
|
||||
|
@ -305,7 +311,16 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings)
|
|||
// considered as a dir
|
||||
// See test_ln::test_symlink_no_deref_dir
|
||||
if let Err(e) = fs::remove_dir(target_dir) {
|
||||
show_error!("Could not update {}: {e}", target_dir.quote());
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ln-error-could-not-update",
|
||||
HashMap::from([
|
||||
("target".to_string(), target_dir.quote().to_string()),
|
||||
("error".to_string(), e.to_string())
|
||||
])
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
target_dir.to_path_buf()
|
||||
|
@ -322,7 +337,13 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings)
|
|||
}
|
||||
}
|
||||
None => {
|
||||
show_error!("cannot stat {}: No such file or directory", srcpath.quote());
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ln-error-cannot-stat",
|
||||
HashMap::from([("path".to_string(), srcpath.quote().to_string())])
|
||||
)
|
||||
);
|
||||
all_successful = false;
|
||||
continue;
|
||||
}
|
||||
|
@ -332,9 +353,14 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings)
|
|||
if linked_destinations.contains(&targetpath) {
|
||||
// If the target file was already created in this ln call, do not overwrite
|
||||
show_error!(
|
||||
"will not overwrite just-created '{}' with '{}'",
|
||||
targetpath.display(),
|
||||
srcpath.display()
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ln-error-will-not-overwrite",
|
||||
HashMap::from([
|
||||
("target".to_string(), targetpath.display().to_string()),
|
||||
("source".to_string(), srcpath.display().to_string())
|
||||
])
|
||||
)
|
||||
);
|
||||
all_successful = false;
|
||||
} else if let Err(e) = link(srcpath, &targetpath, settings) {
|
||||
|
@ -387,12 +413,23 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> {
|
|||
}
|
||||
}
|
||||
if let Some(ref p) = backup_path {
|
||||
fs::rename(dst, p).map_err_context(|| format!("cannot backup {}", dst.quote()))?;
|
||||
fs::rename(dst, p).map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"ln-cannot-backup",
|
||||
HashMap::from([("file".to_string(), dst.quote().to_string())]),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
match settings.overwrite {
|
||||
OverwriteMode::NoClobber => {}
|
||||
OverwriteMode::Interactive => {
|
||||
if !prompt_yes!("replace {}?", dst.quote()) {
|
||||
if !prompt_yes!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ln-prompt-replace",
|
||||
HashMap::from([("file".to_string(), dst.quote().to_string())])
|
||||
)
|
||||
) {
|
||||
return Err(LnError::SomeLinksFailed.into());
|
||||
}
|
||||
|
||||
|
@ -416,16 +453,22 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> {
|
|||
// if we want to have an hard link,
|
||||
// source is a symlink and -L is passed
|
||||
// we want to resolve the symlink to create the hardlink
|
||||
fs::canonicalize(&source)
|
||||
.map_err_context(|| format!("failed to access {}", source.quote()))?
|
||||
fs::canonicalize(&source).map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"ln-failed-to-access",
|
||||
HashMap::from([("file".to_string(), source.quote().to_string())]),
|
||||
)
|
||||
})?
|
||||
} else {
|
||||
source.to_path_buf()
|
||||
};
|
||||
fs::hard_link(p, dst).map_err_context(|| {
|
||||
format!(
|
||||
"failed to create hard link {} => {}",
|
||||
source.quote(),
|
||||
dst.quote()
|
||||
get_message_with_args(
|
||||
"ln-failed-to-create-hard-link",
|
||||
HashMap::from([
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
("dest".to_string(), dst.quote().to_string()),
|
||||
]),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
@ -433,7 +476,13 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> {
|
|||
if settings.verbose {
|
||||
print!("{} -> {}", dst.quote(), source.quote());
|
||||
match backup_path {
|
||||
Some(path) => println!(" (backup: {})", path.quote()),
|
||||
Some(path) => println!(
|
||||
" ({})",
|
||||
get_message_with_args(
|
||||
"ln-backup",
|
||||
HashMap::from([("backup".to_string(), path.quote().to_string())])
|
||||
)
|
||||
),
|
||||
None => println!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,4 +52,4 @@ name = "ls"
|
|||
path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
feat_selinux = ["selinux"]
|
||||
feat_selinux = ["selinux", "uucore/selinux"]
|
||||
|
|
|
@ -2,3 +2,119 @@ ls-about = List directory contents.
|
|||
Ignore files and directories starting with a '.' by default
|
||||
ls-usage = ls [OPTION]... [FILE]...
|
||||
ls-after-help = The TIME_STYLE argument can be full-iso, long-iso, iso, locale or +FORMAT. FORMAT is interpreted like in date. Also the TIME_STYLE environment variable sets the default style to use.
|
||||
|
||||
# Error messages
|
||||
ls-error-invalid-line-width = invalid line width: {$width}
|
||||
ls-error-general-io = general io error: {$error}
|
||||
ls-error-cannot-access-no-such-file = cannot access '{$path}': No such file or directory
|
||||
ls-error-cannot-access-operation-not-permitted = cannot access '{$path}': Operation not permitted
|
||||
ls-error-cannot-open-directory-permission-denied = cannot open directory '{$path}': Permission denied
|
||||
ls-error-cannot-open-file-permission-denied = cannot open file '{$path}': Permission denied
|
||||
ls-error-cannot-open-directory-bad-descriptor = cannot open directory '{$path}': Bad file descriptor
|
||||
ls-error-unknown-io-error = unknown io error: '{$path}', '{$error}'
|
||||
ls-error-invalid-block-size = invalid --block-size argument {$size}
|
||||
ls-error-dired-and-zero-incompatible = --dired and --zero are incompatible
|
||||
ls-error-not-listing-already-listed = {$path}: not listing already-listed directory
|
||||
ls-error-invalid-time-style = invalid --time-style argument {$style}
|
||||
Possible values are: {$values}
|
||||
|
||||
For more information try --help
|
||||
|
||||
# Help messages
|
||||
ls-help-print-help = Print help information.
|
||||
ls-help-set-display-format = Set the display format.
|
||||
ls-help-display-files-columns = Display the files in columns.
|
||||
ls-help-display-detailed-info = Display detailed information.
|
||||
ls-help-list-entries-rows = List entries in rows instead of in columns.
|
||||
ls-help-assume-tab-stops = Assume tab stops at each COLS instead of 8
|
||||
ls-help-list-entries-commas = List entries separated by commas.
|
||||
ls-help-list-entries-nul = List entries separated by ASCII NUL characters.
|
||||
ls-help-generate-dired-output = generate output designed for Emacs' dired (Directory Editor) mode
|
||||
ls-help-hyperlink-filenames = hyperlink file names WHEN
|
||||
ls-help-list-one-file-per-line = List one file per line.
|
||||
ls-help-long-format-no-group = Long format without group information.
|
||||
Identical to --format=long with --no-group.
|
||||
ls-help-long-no-owner = Long format without owner information.
|
||||
ls-help-long-numeric-uid-gid = -l with numeric UIDs and GIDs.
|
||||
ls-help-set-quoting-style = Set quoting style.
|
||||
ls-help-literal-quoting-style = Use literal quoting style. Equivalent to `--quoting-style=literal`
|
||||
ls-help-escape-quoting-style = Use escape quoting style. Equivalent to `--quoting-style=escape`
|
||||
ls-help-c-quoting-style = Use C quoting style. Equivalent to `--quoting-style=c`
|
||||
ls-help-replace-control-chars = Replace control characters with '?' if they are not escaped.
|
||||
ls-help-show-control-chars = Show control characters 'as is' if they are not escaped.
|
||||
ls-help-show-time-field = Show time in <field>:
|
||||
access time (-u): atime, access, use;
|
||||
change time (-t): ctime, status.
|
||||
modification time: mtime, modification.
|
||||
birth time: birth, creation;
|
||||
ls-help-time-change = 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.
|
||||
ls-help-time-access = 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.
|
||||
ls-help-hide-pattern = do not list implied entries matching shell PATTERN (overridden by -a or -A)
|
||||
ls-help-ignore-pattern = do not list implied entries matching shell PATTERN
|
||||
ls-help-ignore-backups = Ignore entries which end with ~.
|
||||
ls-help-sort-by-field = Sort by <field>: name, none (-U), time (-t), size (-S), extension (-X) or width
|
||||
ls-help-sort-by-size = Sort by file size, largest first.
|
||||
ls-help-sort-by-time = Sort by modification time (the 'mtime' in the inode), newest first.
|
||||
ls-help-sort-by-version = Natural sort of (version) numbers in the filenames.
|
||||
ls-help-sort-by-extension = Sort alphabetically by entry extension.
|
||||
ls-help-sort-none = 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.
|
||||
ls-help-dereference-all = When showing file information for a symbolic link, show information for the
|
||||
file the link references rather than the link itself.
|
||||
ls-help-dereference-dir-args = Do not follow symlinks except when they link to directories and are
|
||||
given as command line arguments.
|
||||
ls-help-dereference-args = Do not follow symlinks except when given as command line arguments.
|
||||
ls-help-no-group = Do not show group in long format.
|
||||
ls-help-author = Show author in long format. On the supported platforms,
|
||||
the author always matches the file owner.
|
||||
ls-help-all-files = Do not ignore hidden files (files with names that start with '.').
|
||||
ls-help-almost-all = In a directory, do not ignore all file names that start with '.',
|
||||
only ignore '.' and '..'.
|
||||
ls-help-directory = 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.
|
||||
ls-help-human-readable = Print human readable file sizes (e.g. 1K 234M 56G).
|
||||
ls-help-kibibytes = default to 1024-byte blocks for file system usage; used only with -s and per
|
||||
directory totals
|
||||
ls-help-si = Print human readable file sizes using powers of 1000 instead of 1024.
|
||||
ls-help-block-size = scale sizes by BLOCK_SIZE when printing them
|
||||
ls-help-print-inode = print the index number of each file
|
||||
ls-help-reverse-sort = Reverse whatever the sorting method is e.g., list files in reverse
|
||||
alphabetical order, youngest first, smallest first, or whatever.
|
||||
ls-help-recursive = List the contents of all directories recursively.
|
||||
ls-help-terminal-width = Assume that the terminal is COLS columns wide.
|
||||
ls-help-allocation-size = print the allocated size of each file, in blocks
|
||||
ls-help-color-output = Color output based on file type.
|
||||
ls-help-indicator-style = Append indicator with style WORD to entry names:
|
||||
none (default), slash (-p), file-type (--file-type), classify (-F)
|
||||
ls-help-classify = 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:
|
||||
none - Do not classify. This is the default.
|
||||
auto - Only classify if standard output is a terminal.
|
||||
always - Always classify.
|
||||
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.
|
||||
ls-help-file-type = Same as --classify, but do not append '*'
|
||||
ls-help-slash-directories = Append / indicator to directories.
|
||||
ls-help-time-style = time/date format with -l; see TIME_STYLE below
|
||||
ls-help-full-time = like -l --time-style=full-iso
|
||||
ls-help-context = print any security context of each file
|
||||
ls-help-group-directories-first = group directories before files; can be augmented with
|
||||
a --sort option, but any use of --sort=none (-U) disables grouping
|
||||
ls-invalid-quoting-style = {$program}: Ignoring invalid value of environment variable QUOTING_STYLE: '{$style}'
|
||||
ls-invalid-columns-width = ignoring invalid width in environment variable COLUMNS: {$width}
|
||||
ls-invalid-ignore-pattern = Invalid pattern for ignore: {$pattern}
|
||||
ls-invalid-hide-pattern = Invalid pattern for hide: {$pattern}
|
||||
ls-total = total {$size}
|
||||
|
|
120
src/uu/ls/locales/fr-FR.ftl
Normal file
120
src/uu/ls/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,120 @@
|
|||
ls-about = Lister le contenu des répertoires.
|
||||
Ignorer les fichiers et répertoires commençant par un '.' par défaut
|
||||
ls-usage = ls [OPTION]... [FICHIER]...
|
||||
ls-after-help = L'argument TIME_STYLE peut être full-iso, long-iso, iso, locale ou +FORMAT. FORMAT est interprété comme dans date. De plus, la variable d'environnement TIME_STYLE définit le style par défaut à utiliser.
|
||||
|
||||
# Messages d'erreur
|
||||
ls-error-invalid-line-width = largeur de ligne invalide : {$width}
|
||||
ls-error-general-io = erreur d'E/S générale : {$error}
|
||||
ls-error-cannot-access-no-such-file = impossible d'accéder à '{$path}' : Aucun fichier ou répertoire de ce type
|
||||
ls-error-cannot-access-operation-not-permitted = impossible d'accéder à '{$path}' : Opération non autorisée
|
||||
ls-error-cannot-open-directory-permission-denied = impossible d'ouvrir le répertoire '{$path}' : Permission refusée
|
||||
ls-error-cannot-open-file-permission-denied = impossible d'ouvrir le fichier '{$path}' : Permission refusée
|
||||
ls-error-cannot-open-directory-bad-descriptor = impossible d'ouvrir le répertoire '{$path}' : Mauvais descripteur de fichier
|
||||
ls-error-unknown-io-error = erreur d'E/S inconnue : '{$path}', '{$error}'
|
||||
ls-error-invalid-block-size = argument --block-size invalide {$size}
|
||||
ls-error-dired-and-zero-incompatible = --dired et --zero sont incompatibles
|
||||
ls-error-not-listing-already-listed = {$path} : ne liste pas un répertoire déjà listé
|
||||
ls-error-invalid-time-style = argument --time-style invalide {$style}
|
||||
Les valeurs possibles sont : {$values}
|
||||
|
||||
Pour plus d'informations, essayez --help
|
||||
|
||||
# Messages d'aide
|
||||
ls-help-print-help = Afficher les informations d'aide.
|
||||
ls-help-set-display-format = Définir le format d'affichage.
|
||||
ls-help-display-files-columns = Afficher les fichiers en colonnes.
|
||||
ls-help-display-detailed-info = Afficher des informations détaillées.
|
||||
ls-help-list-entries-rows = Lister les entrées en lignes au lieu de colonnes.
|
||||
ls-help-assume-tab-stops = Supposer des arrêts de tabulation à chaque COLS au lieu de 8
|
||||
ls-help-list-entries-commas = Lister les entrées séparées par des virgules.
|
||||
ls-help-list-entries-nul = Lister les entrées séparées par des caractères NUL ASCII.
|
||||
ls-help-generate-dired-output = générer une sortie conçue pour le mode dired (Directory Editor) d'Emacs
|
||||
ls-help-hyperlink-filenames = créer des hyperliens pour les noms de fichiers QUAND
|
||||
ls-help-list-one-file-per-line = Lister un fichier par ligne.
|
||||
ls-help-long-format-no-group = Format long sans informations de groupe.
|
||||
Identique à --format=long avec --no-group.
|
||||
ls-help-long-no-owner = Format long sans informations de propriétaire.
|
||||
ls-help-long-numeric-uid-gid = -l avec des UID et GID numériques.
|
||||
ls-help-set-quoting-style = Définir le style de citation.
|
||||
ls-help-literal-quoting-style = Utiliser le style de citation littéral. Équivalent à `--quoting-style=literal`
|
||||
ls-help-escape-quoting-style = Utiliser le style de citation d'échappement. Équivalent à `--quoting-style=escape`
|
||||
ls-help-c-quoting-style = Utiliser le style de citation C. Équivalent à `--quoting-style=c`
|
||||
ls-help-replace-control-chars = Remplacer les caractères de contrôle par '?' s'ils ne sont pas échappés.
|
||||
ls-help-show-control-chars = Afficher les caractères de contrôle 'tels quels' s'ils ne sont pas échappés.
|
||||
ls-help-show-time-field = Afficher l'heure dans <champ> :
|
||||
heure d'accès (-u) : atime, access, use ;
|
||||
heure de changement (-t) : ctime, status.
|
||||
heure de modification : mtime, modification.
|
||||
heure de création : birth, creation ;
|
||||
ls-help-time-change = Si le format de liste long (par ex., -l, -o) est utilisé, afficher
|
||||
l'heure de changement de statut (le 'ctime' dans l'inode) au lieu de l'heure
|
||||
de modification. Lors du tri explicite par heure (--sort=time ou -t) ou lors
|
||||
de l'absence de format de liste long, trier selon l'heure de changement de statut.
|
||||
ls-help-time-access = Si le format de liste long (par ex., -l, -o) est utilisé, afficher
|
||||
l'heure d'accès au statut au lieu de l'heure de modification. Lors du tri
|
||||
explicite par heure (--sort=time ou -t) ou lors de l'absence de format de
|
||||
liste long, trier selon l'heure d'accès.
|
||||
ls-help-hide-pattern = ne pas lister les entrées implicites correspondant au MOTIF shell (surchargé par -a ou -A)
|
||||
ls-help-ignore-pattern = ne pas lister les entrées implicites correspondant au MOTIF shell
|
||||
ls-help-ignore-backups = Ignorer les entrées qui se terminent par ~.
|
||||
ls-help-sort-by-field = Trier par <champ> : name, none (-U), time (-t), size (-S), extension (-X) ou width
|
||||
ls-help-sort-by-size = Trier par taille de fichier, le plus grand en premier.
|
||||
ls-help-sort-by-time = Trier par heure de modification (le 'mtime' dans l'inode), le plus récent en premier.
|
||||
ls-help-sort-by-version = Tri naturel des numéros (de version) dans les noms de fichiers.
|
||||
ls-help-sort-by-extension = Trier alphabétiquement par extension d'entrée.
|
||||
ls-help-sort-none = Ne pas trier ; lister les fichiers dans l'ordre où ils sont stockés dans le
|
||||
répertoire. Ceci est particulièrement utile lors de l'affichage de très grands répertoires,
|
||||
car ne pas trier peut être sensiblement plus rapide.
|
||||
ls-help-dereference-all = Lors de l'affichage d'informations de fichier pour un lien symbolique, afficher les informations pour le
|
||||
fichier référencé par le lien plutôt que le lien lui-même.
|
||||
ls-help-dereference-dir-args = Ne pas suivre les liens symboliques sauf quand ils pointent vers des répertoires et sont
|
||||
donnés comme arguments de ligne de commande.
|
||||
ls-help-dereference-args = Ne pas suivre les liens symboliques sauf quand ils sont donnés comme arguments de ligne de commande.
|
||||
ls-help-no-group = Ne pas afficher le groupe en format long.
|
||||
ls-help-author = Afficher l'auteur en format long. Sur les plateformes supportées,
|
||||
l'auteur correspond toujours au propriétaire du fichier.
|
||||
ls-help-all-files = Ne pas ignorer les fichiers cachés (fichiers dont les noms commencent par '.').
|
||||
ls-help-almost-all = Dans un répertoire, ne pas ignorer tous les noms de fichiers qui commencent par '.',
|
||||
ignorer seulement '.' et '..'.
|
||||
ls-help-directory = Lister seulement les noms des répertoires, plutôt que le contenu des répertoires.
|
||||
Ceci ne suivra pas les liens symboliques à moins qu'une des options
|
||||
`--dereference-command-line (-H)`, `--dereference (-L)`, ou
|
||||
`--dereference-command-line-symlink-to-dir` soit spécifiée.
|
||||
ls-help-human-readable = Afficher les tailles de fichiers lisibles par l'homme (par ex. 1K 234M 56G).
|
||||
ls-help-kibibytes = par défaut aux blocs de 1024 octets pour l'utilisation du système de fichiers ; utilisé seulement avec -s et par
|
||||
totaux de répertoire
|
||||
ls-help-si = Afficher les tailles de fichiers lisibles par l'homme utilisant des puissances de 1000 au lieu de 1024.
|
||||
ls-help-block-size = dimensionner les tailles par BLOCK_SIZE lors de l'affichage
|
||||
ls-help-print-inode = afficher le numéro d'index de chaque fichier
|
||||
ls-help-reverse-sort = Inverser quelle que soit la méthode de tri, par ex., lister les fichiers en ordre
|
||||
alphabétique inverse, le plus jeune en premier, le plus petit en premier, ou autre.
|
||||
ls-help-recursive = Lister le contenu de tous les répertoires récursivement.
|
||||
ls-help-terminal-width = Supposer que le terminal a COLS colonnes de largeur.
|
||||
ls-help-allocation-size = afficher la taille allouée de chaque fichier, en blocs
|
||||
ls-help-color-output = Colorier la sortie basée sur le type de fichier.
|
||||
ls-help-indicator-style = Ajouter un indicateur avec le style WORD aux noms d'entrée :
|
||||
none (par défaut), slash (-p), file-type (--file-type), classify (-F)
|
||||
ls-help-classify = Ajouter un caractère à chaque nom de fichier indiquant le type de fichier. Aussi, pour
|
||||
les fichiers réguliers qui sont exécutables, ajouter '*'. Les indicateurs de type de fichier sont
|
||||
'/' pour les répertoires, '@' pour les liens symboliques, '|' pour les FIFOs, '=' pour les sockets,
|
||||
'>' pour les portes, et rien pour les fichiers réguliers. when peut être omis, ou un de :
|
||||
none - Ne pas classifier. C'est la valeur par défaut.
|
||||
auto - Classifier seulement si la sortie standard est un terminal.
|
||||
always - Toujours classifier.
|
||||
Spécifier --classify et aucun when est équivalent à --classify=always. Ceci ne
|
||||
suivra pas les liens symboliques listés sur la ligne de commande à moins que les
|
||||
options --dereference-command-line (-H), --dereference (-L), ou
|
||||
--dereference-command-line-symlink-to-dir soient spécifiées.
|
||||
ls-help-file-type = Identique à --classify, mais ne pas ajouter '*'
|
||||
ls-help-slash-directories = Ajouter l'indicateur / aux répertoires.
|
||||
ls-help-time-style = format de date/heure avec -l ; voir TIME_STYLE ci-dessous
|
||||
ls-help-full-time = comme -l --time-style=full-iso
|
||||
ls-help-context = afficher tout contexte de sécurité de chaque fichier
|
||||
ls-help-group-directories-first = grouper les répertoires avant les fichiers ; peut être augmenté avec
|
||||
une option --sort, mais toute utilisation de --sort=none (-U) désactive le groupement
|
||||
ls-invalid-quoting-style = {$program} : Ignorer la valeur invalide de la variable d'environnement QUOTING_STYLE : '{$style}'
|
||||
ls-invalid-columns-width = ignorer la largeur invalide dans la variable d'environnement COLUMNS : {$width}
|
||||
ls-invalid-ignore-pattern = Motif invalide pour ignore : {$pattern}
|
||||
ls-invalid-hide-pattern = Motif invalide pour hide : {$pattern}
|
||||
ls-total = total {$size}
|
|
@ -6,6 +6,8 @@
|
|||
// spell-checker:ignore (ToDO) somegroup nlink tabsize dired subdired dtype colorterm stringly nohash strtime
|
||||
|
||||
use std::iter;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::{FileTypeExt, MetadataExt};
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
use std::{cell::LazyCell, cell::OnceCell, num::IntErrorKind};
|
||||
|
@ -18,12 +20,10 @@ use std::{
|
|||
path::{Path, PathBuf},
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
#[cfg(unix)]
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
os::unix::fs::{FileTypeExt, MetadataExt},
|
||||
collections::{HashMap, HashSet},
|
||||
io::IsTerminal,
|
||||
};
|
||||
use std::{collections::HashSet, io::IsTerminal};
|
||||
|
||||
use ansi_width::ansi_width;
|
||||
use clap::{
|
||||
|
@ -60,8 +60,8 @@ use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR};
|
|||
))]
|
||||
use uucore::libc::{dev_t, major, minor};
|
||||
use uucore::line_ending::LineEnding;
|
||||
use uucore::locale::get_message;
|
||||
use uucore::quoting_style::{self, QuotingStyle, escape_name};
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
use uucore::quoting_style::{QuotingStyle, locale_aware_escape_dir_name, locale_aware_escape_name};
|
||||
use uucore::{
|
||||
display::Quotable,
|
||||
error::{UError, UResult, set_exit_code},
|
||||
|
@ -79,11 +79,6 @@ use dired::{DiredOutput, is_dired_arg_present};
|
|||
mod colors;
|
||||
use colors::{StyleManager, color_name};
|
||||
|
||||
#[cfg(not(feature = "selinux"))]
|
||||
static CONTEXT_HELP_TEXT: &str = "print any security context of each file (not enabled)";
|
||||
#[cfg(feature = "selinux")]
|
||||
static CONTEXT_HELP_TEXT: &str = "print any security context of each file";
|
||||
|
||||
pub mod options {
|
||||
pub mod format {
|
||||
pub static ONE_LINE: &str = "1";
|
||||
|
@ -177,39 +172,39 @@ const DEFAULT_FILE_SIZE_BLOCK_SIZE: u64 = 1;
|
|||
|
||||
#[derive(Error, Debug)]
|
||||
enum LsError {
|
||||
#[error("invalid line width: '{0}'")]
|
||||
#[error("{}", get_message_with_args("ls-error-invalid-line-width", HashMap::from([("width".to_string(), format!("'{}'", _0))])))]
|
||||
InvalidLineWidth(String),
|
||||
|
||||
#[error("general io error: {0}")]
|
||||
#[error("{}", get_message_with_args("ls-error-general-io", HashMap::from([("error".to_string(), _0.to_string())])))]
|
||||
IOError(#[from] std::io::Error),
|
||||
|
||||
#[error("{}", match .1.kind() {
|
||||
ErrorKind::NotFound => format!("cannot access '{}': No such file or directory", .0.to_string_lossy()),
|
||||
ErrorKind::NotFound => get_message_with_args("ls-error-cannot-access-no-such-file", HashMap::from([("path".to_string(), .0.to_string_lossy().to_string())])),
|
||||
ErrorKind::PermissionDenied => match .1.raw_os_error().unwrap_or(1) {
|
||||
1 => format!("cannot access '{}': Operation not permitted", .0.to_string_lossy()),
|
||||
1 => get_message_with_args("ls-error-cannot-access-operation-not-permitted", HashMap::from([("path".to_string(), .0.to_string_lossy().to_string())])),
|
||||
_ => if .0.is_dir() {
|
||||
format!("cannot open directory '{}': Permission denied", .0.to_string_lossy())
|
||||
get_message_with_args("ls-error-cannot-open-directory-permission-denied", HashMap::from([("path".to_string(), .0.to_string_lossy().to_string())]))
|
||||
} else {
|
||||
format!("cannot open file '{}': Permission denied", .0.to_string_lossy())
|
||||
get_message_with_args("ls-error-cannot-open-file-permission-denied", HashMap::from([("path".to_string(), .0.to_string_lossy().to_string())]))
|
||||
},
|
||||
},
|
||||
_ => match .1.raw_os_error().unwrap_or(1) {
|
||||
9 => format!("cannot open directory '{}': Bad file descriptor", .0.to_string_lossy()),
|
||||
_ => format!("unknown io error: '{:?}', '{:?}'", .0.to_string_lossy(), .1),
|
||||
9 => get_message_with_args("ls-error-cannot-open-directory-bad-descriptor", HashMap::from([("path".to_string(), .0.to_string_lossy().to_string())])),
|
||||
_ => get_message_with_args("ls-error-unknown-io-error", HashMap::from([("path".to_string(), .0.to_string_lossy().to_string()), ("error".to_string(), format!("{:?}", .1))])),
|
||||
},
|
||||
})]
|
||||
IOErrorContext(PathBuf, std::io::Error, bool),
|
||||
|
||||
#[error("invalid --block-size argument '{0}'")]
|
||||
#[error("{}", get_message_with_args("ls-error-invalid-block-size", HashMap::from([("size".to_string(), format!("'{}'", _0))])))]
|
||||
BlockSizeParseError(String),
|
||||
|
||||
#[error("--dired and --zero are incompatible")]
|
||||
#[error("{}", get_message("ls-error-dired-and-zero-incompatible"))]
|
||||
DiredAndZeroAreIncompatible,
|
||||
|
||||
#[error("{}: not listing already-listed directory", .0.to_string_lossy())]
|
||||
#[error("{}", get_message_with_args("ls-error-not-listing-already-listed", HashMap::from([("path".to_string(), .0.to_string_lossy().to_string())])))]
|
||||
AlreadyListedError(PathBuf),
|
||||
|
||||
#[error("invalid --time-style argument {}\nPossible values are: {:?}\n\nFor more information try --help", .0.quote(), .1)]
|
||||
#[error("{}", get_message_with_args("ls-error-invalid-time-style", HashMap::from([("style".to_string(), .0.quote().to_string()), ("values".to_string(), format!("{:?}", .1))])))]
|
||||
TimeStyleParseError(String, Vec<String>),
|
||||
}
|
||||
|
||||
|
@ -601,34 +596,15 @@ fn extract_hyperlink(options: &clap::ArgMatches) -> bool {
|
|||
fn match_quoting_style_name(style: &str, show_control: bool) -> Option<QuotingStyle> {
|
||||
match style {
|
||||
"literal" => Some(QuotingStyle::Literal { show_control }),
|
||||
"shell" => Some(QuotingStyle::Shell {
|
||||
escape: false,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
}),
|
||||
"shell-always" => Some(QuotingStyle::Shell {
|
||||
escape: false,
|
||||
always_quote: true,
|
||||
show_control,
|
||||
}),
|
||||
"shell-escape" => Some(QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
}),
|
||||
"shell-escape-always" => Some(QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: true,
|
||||
show_control,
|
||||
}),
|
||||
"c" => Some(QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::Double,
|
||||
}),
|
||||
"escape" => Some(QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::None,
|
||||
}),
|
||||
"shell" => Some(QuotingStyle::SHELL),
|
||||
"shell-always" => Some(QuotingStyle::SHELL_QUOTE),
|
||||
"shell-escape" => Some(QuotingStyle::SHELL_ESCAPE),
|
||||
"shell-escape-always" => Some(QuotingStyle::SHELL_ESCAPE_QUOTE),
|
||||
"c" => Some(QuotingStyle::C_DOUBLE),
|
||||
"escape" => Some(QuotingStyle::C_NO_QUOTES),
|
||||
_ => None,
|
||||
}
|
||||
.map(|qs| qs.show_control(show_control))
|
||||
}
|
||||
|
||||
/// Extracts the quoting style to use based on the options provided.
|
||||
|
@ -654,13 +630,9 @@ fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> Quot
|
|||
} else if options.get_flag(options::quoting::LITERAL) {
|
||||
QuotingStyle::Literal { show_control }
|
||||
} else if options.get_flag(options::quoting::ESCAPE) {
|
||||
QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::None,
|
||||
}
|
||||
QuotingStyle::C_NO_QUOTES
|
||||
} else if options.get_flag(options::quoting::C) {
|
||||
QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::Double,
|
||||
}
|
||||
QuotingStyle::C_DOUBLE
|
||||
} else if options.get_flag(options::DIRED) {
|
||||
QuotingStyle::Literal { show_control }
|
||||
} else {
|
||||
|
@ -669,8 +641,17 @@ fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> Quot
|
|||
match match_quoting_style_name(style.as_str(), show_control) {
|
||||
Some(qs) => return qs,
|
||||
None => eprintln!(
|
||||
"{}: Ignoring invalid value of environment variable QUOTING_STYLE: '{style}'",
|
||||
std::env::args().next().unwrap_or_else(|| "ls".to_string()),
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ls-invalid-quoting-style",
|
||||
HashMap::from([
|
||||
(
|
||||
"program".to_string(),
|
||||
std::env::args().next().unwrap_or_else(|| "ls".to_string())
|
||||
),
|
||||
("style".to_string(), style.clone())
|
||||
])
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -678,11 +659,7 @@ fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> Quot
|
|||
// By default, `ls` uses Shell escape quoting style when writing to a terminal file
|
||||
// descriptor and Literal otherwise.
|
||||
if stdout().is_terminal() {
|
||||
QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
}
|
||||
QuotingStyle::SHELL_ESCAPE.show_control(show_control)
|
||||
} else {
|
||||
QuotingStyle::Literal { show_control }
|
||||
}
|
||||
|
@ -747,8 +724,11 @@ fn parse_width(width_match: Option<&String>) -> Result<u16, LsError> {
|
|||
Some(columns) => columns,
|
||||
None => {
|
||||
show_error!(
|
||||
"ignoring invalid width in environment variable COLUMNS: {}",
|
||||
columns.quote()
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ls-invalid-columns-width",
|
||||
HashMap::from([("width".to_string(), columns.quote().to_string())])
|
||||
)
|
||||
);
|
||||
DEFAULT_TERM_WIDTH
|
||||
}
|
||||
|
@ -966,7 +946,13 @@ impl Config {
|
|||
Ok(p) => {
|
||||
ignore_patterns.push(p);
|
||||
}
|
||||
Err(_) => show_warning!("Invalid pattern for ignore: {}", pattern.quote()),
|
||||
Err(_) => show_warning!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ls-invalid-ignore-pattern",
|
||||
HashMap::from([("pattern".to_string(), pattern.quote().to_string())])
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -980,7 +966,13 @@ impl Config {
|
|||
Ok(p) => {
|
||||
ignore_patterns.push(p);
|
||||
}
|
||||
Err(_) => show_warning!("Invalid pattern for hide: {}", pattern.quote()),
|
||||
Err(_) => show_warning!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"ls-invalid-hide-pattern",
|
||||
HashMap::from([("pattern".to_string(), pattern.quote().to_string())])
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1184,14 +1176,14 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::HELP)
|
||||
.long(options::HELP)
|
||||
.help("Print help information.")
|
||||
.help(get_message("ls-help-print-help"))
|
||||
.action(ArgAction::Help),
|
||||
)
|
||||
// Format arguments
|
||||
.arg(
|
||||
Arg::new(options::FORMAT)
|
||||
.long(options::FORMAT)
|
||||
.help("Set the display format.")
|
||||
.help(get_message("ls-help-set-display-format"))
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
"long",
|
||||
"verbose",
|
||||
|
@ -1216,7 +1208,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::format::COLUMNS)
|
||||
.short('C')
|
||||
.help("Display the files in columns.")
|
||||
.help(get_message("ls-help-display-files-columns"))
|
||||
.overrides_with_all([
|
||||
options::FORMAT,
|
||||
options::format::COLUMNS,
|
||||
|
@ -1230,7 +1222,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::format::LONG)
|
||||
.short('l')
|
||||
.long(options::format::LONG)
|
||||
.help("Display detailed information.")
|
||||
.help(get_message("ls-help-display-detailed-info"))
|
||||
.overrides_with_all([
|
||||
options::FORMAT,
|
||||
options::format::COLUMNS,
|
||||
|
@ -1243,7 +1235,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::format::ACROSS)
|
||||
.short('x')
|
||||
.help("List entries in rows instead of in columns.")
|
||||
.help(get_message("ls-help-list-entries-rows"))
|
||||
.overrides_with_all([
|
||||
options::FORMAT,
|
||||
options::format::COLUMNS,
|
||||
|
@ -1259,12 +1251,12 @@ pub fn uu_app() -> Command {
|
|||
.long(options::format::TAB_SIZE)
|
||||
.env("TABSIZE")
|
||||
.value_name("COLS")
|
||||
.help("Assume tab stops at each COLS instead of 8"),
|
||||
.help(get_message("ls-help-assume-tab-stops")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::format::COMMAS)
|
||||
.short('m')
|
||||
.help("List entries separated by commas.")
|
||||
.help(get_message("ls-help-list-entries-commas"))
|
||||
.overrides_with_all([
|
||||
options::FORMAT,
|
||||
options::format::COLUMNS,
|
||||
|
@ -1278,21 +1270,21 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::ZERO)
|
||||
.long(options::ZERO)
|
||||
.overrides_with(options::ZERO)
|
||||
.help("List entries separated by ASCII NUL characters.")
|
||||
.help(get_message("ls-help-list-entries-nul"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::DIRED)
|
||||
.long(options::DIRED)
|
||||
.short('D')
|
||||
.help("generate output designed for Emacs' dired (Directory Editor) mode")
|
||||
.help(get_message("ls-help-generate-dired-output"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::HYPERLINK),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::HYPERLINK)
|
||||
.long(options::HYPERLINK)
|
||||
.help("hyperlink file names WHEN")
|
||||
.help(get_message("ls-help-hyperlink-filenames"))
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
PossibleValue::new("always").alias("yes").alias("force"),
|
||||
PossibleValue::new("auto").alias("tty").alias("if-tty"),
|
||||
|
@ -1314,36 +1306,33 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::format::ONE_LINE)
|
||||
.short('1')
|
||||
.help("List one file per line.")
|
||||
.help(get_message("ls-help-list-one-file-per-line"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::format::LONG_NO_GROUP)
|
||||
.short('o')
|
||||
.help(
|
||||
"Long format without group information. \
|
||||
Identical to --format=long with --no-group.",
|
||||
)
|
||||
.help(get_message("ls-help-long-format-no-group"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::format::LONG_NO_OWNER)
|
||||
.short('g')
|
||||
.help("Long format without owner information.")
|
||||
.help(get_message("ls-help-long-no-owner"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.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.")
|
||||
.help(get_message("ls-help-long-numeric-uid-gid"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
// Quoting style
|
||||
.arg(
|
||||
Arg::new(options::QUOTING_STYLE)
|
||||
.long(options::QUOTING_STYLE)
|
||||
.help("Set quoting style.")
|
||||
.help(get_message("ls-help-set-quoting-style"))
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
PossibleValue::new("literal"),
|
||||
PossibleValue::new("shell"),
|
||||
|
@ -1365,7 +1354,7 @@ pub fn uu_app() -> Command {
|
|||
.short('N')
|
||||
.long(options::quoting::LITERAL)
|
||||
.alias("l")
|
||||
.help("Use literal quoting style. Equivalent to `--quoting-style=literal`")
|
||||
.help(get_message("ls-help-literal-quoting-style"))
|
||||
.overrides_with_all([
|
||||
options::QUOTING_STYLE,
|
||||
options::quoting::LITERAL,
|
||||
|
@ -1378,7 +1367,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::quoting::ESCAPE)
|
||||
.short('b')
|
||||
.long(options::quoting::ESCAPE)
|
||||
.help("Use escape quoting style. Equivalent to `--quoting-style=escape`")
|
||||
.help(get_message("ls-help-escape-quoting-style"))
|
||||
.overrides_with_all([
|
||||
options::QUOTING_STYLE,
|
||||
options::quoting::LITERAL,
|
||||
|
@ -1391,7 +1380,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::quoting::C)
|
||||
.short('Q')
|
||||
.long(options::quoting::C)
|
||||
.help("Use C quoting style. Equivalent to `--quoting-style=c`")
|
||||
.help(get_message("ls-help-c-quoting-style"))
|
||||
.overrides_with_all([
|
||||
options::QUOTING_STYLE,
|
||||
options::quoting::LITERAL,
|
||||
|
@ -1405,14 +1394,14 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::HIDE_CONTROL_CHARS)
|
||||
.short('q')
|
||||
.long(options::HIDE_CONTROL_CHARS)
|
||||
.help("Replace control characters with '?' if they are not escaped.")
|
||||
.help(get_message("ls-help-replace-control-chars"))
|
||||
.overrides_with_all([options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SHOW_CONTROL_CHARS)
|
||||
.long(options::SHOW_CONTROL_CHARS)
|
||||
.help("Show control characters 'as is' if they are not escaped.")
|
||||
.help(get_message("ls-help-show-control-chars"))
|
||||
.overrides_with_all([options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -1420,13 +1409,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::TIME)
|
||||
.long(options::TIME)
|
||||
.help(
|
||||
"Show time in <field>:\n\
|
||||
\taccess time (-u): atime, access, use;\n\
|
||||
\tchange time (-t): ctime, status.\n\
|
||||
\tmodification time: mtime, modification.\n\
|
||||
\tbirth time: birth, creation;",
|
||||
)
|
||||
.help(get_message("ls-help-show-time-field"))
|
||||
.value_name("field")
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
PossibleValue::new("atime").alias("access").alias("use"),
|
||||
|
@ -1441,24 +1424,14 @@ pub fn uu_app() -> Command {
|
|||
.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.",
|
||||
)
|
||||
.help(get_message("ls-help-time-change"))
|
||||
.overrides_with_all([options::TIME, options::time::ACCESS, options::time::CHANGE])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.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.",
|
||||
)
|
||||
.help(get_message("ls-help-time-access"))
|
||||
.overrides_with_all([options::TIME, options::time::ACCESS, options::time::CHANGE])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -1468,9 +1441,7 @@ pub fn uu_app() -> Command {
|
|||
.long(options::HIDE)
|
||||
.action(ArgAction::Append)
|
||||
.value_name("PATTERN")
|
||||
.help(
|
||||
"do not list implied entries matching shell PATTERN (overridden by -a or -A)",
|
||||
),
|
||||
.help(get_message("ls-help-hide-pattern")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::IGNORE)
|
||||
|
@ -1478,22 +1449,30 @@ pub fn uu_app() -> Command {
|
|||
.long(options::IGNORE)
|
||||
.action(ArgAction::Append)
|
||||
.value_name("PATTERN")
|
||||
.help("do not list implied entries matching shell PATTERN"),
|
||||
.help(get_message("ls-help-ignore-pattern")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::IGNORE_BACKUPS)
|
||||
.short('B')
|
||||
.long(options::IGNORE_BACKUPS)
|
||||
.help("Ignore entries which end with ~.")
|
||||
.help(get_message("ls-help-ignore-backups"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
// Sort arguments
|
||||
.arg(
|
||||
Arg::new(options::SORT)
|
||||
.long(options::SORT)
|
||||
.help("Sort by <field>: name, none (-U), time (-t), size (-S), extension (-X) or width")
|
||||
.help(get_message("ls-help-sort-by-field"))
|
||||
.value_name("field")
|
||||
.value_parser(ShortcutValueParser::new(["name", "none", "time", "size", "version", "extension", "width"]))
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
"name",
|
||||
"none",
|
||||
"time",
|
||||
"size",
|
||||
"version",
|
||||
"extension",
|
||||
"width",
|
||||
]))
|
||||
.require_equals(true)
|
||||
.overrides_with_all([
|
||||
options::SORT,
|
||||
|
@ -1507,7 +1486,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::sort::SIZE)
|
||||
.short('S')
|
||||
.help("Sort by file size, largest first.")
|
||||
.help(get_message("ls-help-sort-by-size"))
|
||||
.overrides_with_all([
|
||||
options::SORT,
|
||||
options::sort::SIZE,
|
||||
|
@ -1521,7 +1500,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::sort::TIME)
|
||||
.short('t')
|
||||
.help("Sort by modification time (the 'mtime' in the inode), newest first.")
|
||||
.help(get_message("ls-help-sort-by-time"))
|
||||
.overrides_with_all([
|
||||
options::SORT,
|
||||
options::sort::SIZE,
|
||||
|
@ -1535,7 +1514,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::sort::VERSION)
|
||||
.short('v')
|
||||
.help("Natural sort of (version) numbers in the filenames.")
|
||||
.help(get_message("ls-help-sort-by-version"))
|
||||
.overrides_with_all([
|
||||
options::SORT,
|
||||
options::sort::SIZE,
|
||||
|
@ -1549,7 +1528,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::sort::EXTENSION)
|
||||
.short('X')
|
||||
.help("Sort alphabetically by entry extension.")
|
||||
.help(get_message("ls-help-sort-by-extension"))
|
||||
.overrides_with_all([
|
||||
options::SORT,
|
||||
options::sort::SIZE,
|
||||
|
@ -1563,11 +1542,7 @@ pub fn uu_app() -> Command {
|
|||
.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.",
|
||||
)
|
||||
.help(get_message("ls-help-sort-none"))
|
||||
.overrides_with_all([
|
||||
options::SORT,
|
||||
options::sort::SIZE,
|
||||
|
@ -1583,10 +1558,7 @@ pub fn uu_app() -> Command {
|
|||
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.",
|
||||
)
|
||||
.help(get_message("ls-help-dereference-all"))
|
||||
.overrides_with_all([
|
||||
options::dereference::ALL,
|
||||
options::dereference::DIR_ARGS,
|
||||
|
@ -1597,10 +1569,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::dereference::DIR_ARGS)
|
||||
.long(options::dereference::DIR_ARGS)
|
||||
.help(
|
||||
"Do not follow symlinks except when they link to directories and are \
|
||||
given as command line arguments.",
|
||||
)
|
||||
.help(get_message("ls-help-dereference-dir-args"))
|
||||
.overrides_with_all([
|
||||
options::dereference::ALL,
|
||||
options::dereference::DIR_ARGS,
|
||||
|
@ -1612,7 +1581,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::dereference::ARGS)
|
||||
.short('H')
|
||||
.long(options::dereference::ARGS)
|
||||
.help("Do not follow symlinks except when given as command line arguments.")
|
||||
.help(get_message("ls-help-dereference-args"))
|
||||
.overrides_with_all([
|
||||
options::dereference::ALL,
|
||||
options::dereference::DIR_ARGS,
|
||||
|
@ -1625,13 +1594,15 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::NO_GROUP)
|
||||
.long(options::NO_GROUP)
|
||||
.short('G')
|
||||
.help("Do not show group in long format.")
|
||||
.help(get_message("ls-help-no-group"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::AUTHOR)
|
||||
.long(options::AUTHOR)
|
||||
.help(get_message("ls-help-author"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.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.",
|
||||
).action(ArgAction::SetTrue))
|
||||
// Other Flags
|
||||
.arg(
|
||||
Arg::new(options::files::ALL)
|
||||
|
@ -1639,7 +1610,7 @@ pub fn uu_app() -> Command {
|
|||
.long(options::files::ALL)
|
||||
// Overrides -A (as the order matters)
|
||||
.overrides_with_all([options::files::ALL, options::files::ALMOST_ALL])
|
||||
.help("Do not ignore hidden files (files with names that start with '.').")
|
||||
.help(get_message("ls-help-all-files"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -1648,29 +1619,21 @@ pub fn uu_app() -> Command {
|
|||
.long(options::files::ALMOST_ALL)
|
||||
// Overrides -a (as the order matters)
|
||||
.overrides_with_all([options::files::ALL, options::files::ALMOST_ALL])
|
||||
.help(
|
||||
"In a directory, do not ignore all file names that start with '.', \
|
||||
only ignore '.' and '..'.",
|
||||
)
|
||||
.help(get_message("ls-help-almost-all"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.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.",
|
||||
)
|
||||
.help(get_message("ls-help-directory"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.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).")
|
||||
.help(get_message("ls-help-human-readable"))
|
||||
.overrides_with_all([options::size::BLOCK_SIZE, options::size::SI])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -1678,16 +1641,13 @@ pub fn uu_app() -> Command {
|
|||
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",
|
||||
)
|
||||
.help(get_message("ls-help-kibibytes"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::size::SI)
|
||||
.long(options::size::SI)
|
||||
.help("Print human readable file sizes using powers of 1000 instead of 1024.")
|
||||
.help(get_message("ls-help-si"))
|
||||
.overrides_with_all([options::size::BLOCK_SIZE, options::size::HUMAN_READABLE])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -1696,51 +1656,48 @@ pub fn uu_app() -> Command {
|
|||
.long(options::size::BLOCK_SIZE)
|
||||
.require_equals(true)
|
||||
.value_name("BLOCK_SIZE")
|
||||
.help("scale sizes by BLOCK_SIZE when printing them")
|
||||
.help(get_message("ls-help-block-size"))
|
||||
.overrides_with_all([options::size::SI, options::size::HUMAN_READABLE]),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::INODE)
|
||||
.short('i')
|
||||
.long(options::INODE)
|
||||
.help("print the index number of each file")
|
||||
.help(get_message("ls-help-print-inode"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.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.",
|
||||
)
|
||||
.help(get_message("ls-help-reverse-sort"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::RECURSIVE)
|
||||
.short('R')
|
||||
.long(options::RECURSIVE)
|
||||
.help("List the contents of all directories recursively.")
|
||||
.help(get_message("ls-help-recursive"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::WIDTH)
|
||||
.long(options::WIDTH)
|
||||
.short('w')
|
||||
.help("Assume that the terminal is COLS columns wide.")
|
||||
.help(get_message("ls-help-terminal-width"))
|
||||
.value_name("COLS"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::size::ALLOCATION_SIZE)
|
||||
.short('s')
|
||||
.long(options::size::ALLOCATION_SIZE)
|
||||
.help("print the allocated size of each file, in blocks")
|
||||
.help(get_message("ls-help-allocation-size"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::COLOR)
|
||||
.long(options::COLOR)
|
||||
.help("Color output based on file type.")
|
||||
.help(get_message("ls-help-color-output"))
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
PossibleValue::new("always").alias("yes").alias("force"),
|
||||
PossibleValue::new("auto").alias("tty").alias("if-tty"),
|
||||
|
@ -1752,11 +1709,13 @@ pub fn uu_app() -> Command {
|
|||
.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)",
|
||||
)
|
||||
.value_parser(ShortcutValueParser::new(["none", "slash", "file-type", "classify"]))
|
||||
.help(get_message("ls-help-indicator-style"))
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
"none",
|
||||
"slash",
|
||||
"file-type",
|
||||
"classify",
|
||||
]))
|
||||
.overrides_with_all([
|
||||
options::indicator_style::FILE_TYPE,
|
||||
options::indicator_style::SLASH,
|
||||
|
@ -1773,19 +1732,7 @@ pub fn uu_app() -> Command {
|
|||
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.",
|
||||
)
|
||||
.help(get_message("ls-help-classify"))
|
||||
.value_name("when")
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
PossibleValue::new("always").alias("yes").alias("force"),
|
||||
|
@ -1805,7 +1752,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::indicator_style::FILE_TYPE)
|
||||
.long(options::indicator_style::FILE_TYPE)
|
||||
.help("Same as --classify, but do not append '*'")
|
||||
.help(get_message("ls-help-file-type"))
|
||||
.overrides_with_all([
|
||||
options::indicator_style::FILE_TYPE,
|
||||
options::indicator_style::SLASH,
|
||||
|
@ -1817,7 +1764,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::indicator_style::SLASH)
|
||||
.short('p')
|
||||
.help("Append / indicator to directories.")
|
||||
.help(get_message("ls-help-slash-directories"))
|
||||
.overrides_with_all([
|
||||
options::indicator_style::FILE_TYPE,
|
||||
options::indicator_style::SLASH,
|
||||
|
@ -1830,7 +1777,7 @@ pub fn uu_app() -> Command {
|
|||
//This still needs support for posix-*
|
||||
Arg::new(options::TIME_STYLE)
|
||||
.long(options::TIME_STYLE)
|
||||
.help("time/date format with -l; see TIME_STYLE below")
|
||||
.help(get_message("ls-help-time-style"))
|
||||
.value_name("TIME_STYLE")
|
||||
.env("TIME_STYLE")
|
||||
.value_parser(NonEmptyStringValueParser::new())
|
||||
|
@ -1840,23 +1787,20 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::FULL_TIME)
|
||||
.long(options::FULL_TIME)
|
||||
.overrides_with(options::FULL_TIME)
|
||||
.help("like -l --time-style=full-iso")
|
||||
.help(get_message("ls-help-full-time"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::CONTEXT)
|
||||
.short('Z')
|
||||
.long(options::CONTEXT)
|
||||
.help(CONTEXT_HELP_TEXT)
|
||||
.help(get_message("ls-help-context"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::GROUP_DIRECTORIES_FIRST)
|
||||
.long(options::GROUP_DIRECTORIES_FIRST)
|
||||
.help(
|
||||
"group directories before files; can be augmented with \
|
||||
a --sort option, but any use of --sort=none (-U) disables grouping",
|
||||
)
|
||||
.help(get_message("ls-help-group-directories-first"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
// Positional arguments
|
||||
|
@ -1956,11 +1900,7 @@ impl PathData {
|
|||
None => OnceCell::new(),
|
||||
};
|
||||
|
||||
let security_context = if config.context {
|
||||
get_security_context(config, &p_buf, must_dereference)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let security_context = get_security_context(config, &p_buf, must_dereference);
|
||||
|
||||
Self {
|
||||
md: OnceCell::new(),
|
||||
|
@ -2037,7 +1977,7 @@ fn show_dir_name(
|
|||
config: &Config,
|
||||
) -> std::io::Result<()> {
|
||||
let escaped_name =
|
||||
quoting_style::escape_dir_name(path_data.p_buf.as_os_str(), &config.quoting_style);
|
||||
locale_aware_escape_dir_name(path_data.p_buf.as_os_str(), config.quoting_style);
|
||||
|
||||
let name = if config.hyperlink && !config.dired {
|
||||
create_hyperlink(&escaped_name, path_data)
|
||||
|
@ -2482,8 +2422,11 @@ fn return_total(
|
|||
dired::indent(out)?;
|
||||
}
|
||||
Ok(format!(
|
||||
"total {}{}",
|
||||
display_size(total_size, config),
|
||||
"{}{}",
|
||||
get_message_with_args(
|
||||
"ls-total",
|
||||
HashMap::from([("size".to_string(), display_size(total_size, config))])
|
||||
),
|
||||
config.line_ending
|
||||
))
|
||||
}
|
||||
|
@ -2535,7 +2478,7 @@ fn display_items(
|
|||
// option, print the security context to the left of the size column.
|
||||
|
||||
let quoted = items.iter().any(|item| {
|
||||
let name = escape_name(&item.display_name, &config.quoting_style);
|
||||
let name = locale_aware_escape_name(&item.display_name, config.quoting_style);
|
||||
os_str_starts_with(&name, b"'")
|
||||
});
|
||||
|
||||
|
@ -3178,7 +3121,7 @@ fn classify_file(path: &PathData, out: &mut BufWriter<Stdout>) -> Option<char> {
|
|||
/// Takes a [`PathData`] struct and returns a cell with a name ready for displaying.
|
||||
///
|
||||
/// This function relies on the following parameters in the provided `&Config`:
|
||||
/// * `config.quoting_style` to decide how we will escape `name` using [`escape_name`].
|
||||
/// * `config.quoting_style` to decide how we will escape `name` using [`locale_aware_escape_name`].
|
||||
/// * `config.inode` decides whether to display inode numbers beside names using [`get_inode`].
|
||||
/// * `config.color` decides whether it's going to color `name` using [`color_name`].
|
||||
/// * `config.indicator_style` to append specific characters to `name` using [`classify_file`].
|
||||
|
@ -3199,7 +3142,7 @@ fn display_item_name(
|
|||
current_column: LazyCell<usize, Box<dyn FnOnce() -> usize + '_>>,
|
||||
) -> OsString {
|
||||
// This is our return value. We start by `&path.display_name` and modify it along the way.
|
||||
let mut name = escape_name(&path.display_name, &config.quoting_style);
|
||||
let mut name = locale_aware_escape_name(&path.display_name, config.quoting_style);
|
||||
|
||||
let is_wrap =
|
||||
|namelen: usize| config.width != 0 && *current_column + namelen > config.width.into();
|
||||
|
@ -3291,7 +3234,7 @@ fn display_item_name(
|
|||
name.push(path.p_buf.read_link().unwrap());
|
||||
} else {
|
||||
name.push(color_name(
|
||||
escape_name(target.as_os_str(), &config.quoting_style),
|
||||
locale_aware_escape_name(target.as_os_str(), config.quoting_style),
|
||||
path,
|
||||
style_manager,
|
||||
&mut state.out,
|
||||
|
@ -3302,7 +3245,10 @@ fn display_item_name(
|
|||
} else {
|
||||
// If no coloring is required, we just use target as is.
|
||||
// Apply the right quoting
|
||||
name.push(escape_name(target.as_os_str(), &config.quoting_style));
|
||||
name.push(locale_aware_escape_name(
|
||||
target.as_os_str(),
|
||||
config.quoting_style,
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
|
@ -3389,7 +3335,10 @@ fn get_security_context(config: &Config, p_buf: &Path, must_dereference: bool) -
|
|||
Err(err) => {
|
||||
// The Path couldn't be dereferenced, so return early and set exit code 1
|
||||
// to indicate a minor error
|
||||
show!(LsError::IOErrorContext(p_buf.to_path_buf(), err, false));
|
||||
// Only show error when context display is requested to avoid duplicate messages
|
||||
if config.context {
|
||||
show!(LsError::IOErrorContext(p_buf.to_path_buf(), err, false));
|
||||
}
|
||||
return substitute_string;
|
||||
}
|
||||
Ok(_md) => (),
|
||||
|
|
|
@ -1,2 +1,30 @@
|
|||
more-about = Display the contents of a text file
|
||||
more-usage = more [OPTIONS] FILE...
|
||||
|
||||
# Error messages
|
||||
more-error-is-directory = {$path} is a directory.
|
||||
more-error-cannot-open-no-such-file = cannot open {$path}: No such file or directory
|
||||
more-error-cannot-open-io-error = cannot open {$path}: {$error}
|
||||
more-error-bad-usage = bad usage
|
||||
more-error-cannot-seek-to-line = Cannot seek to line number {$line}
|
||||
more-error-pattern-not-found = Pattern not found
|
||||
more-error-unknown-key = Unknown key: '{$key}'. Press 'h' for instructions. (unimplemented)
|
||||
|
||||
# Help messages
|
||||
more-help-silent = Display help instead of ringing bell when an illegal key is pressed
|
||||
more-help-logical = Do not pause after any line containing a ^L (form feed)
|
||||
more-help-exit-on-eof = Exit on End-Of-File
|
||||
more-help-no-pause = Count logical lines, rather than screen lines
|
||||
more-help-print-over = Do not scroll, clear screen and display text
|
||||
more-help-clean-print = Do not scroll, display text and clean line ends
|
||||
more-help-squeeze = Squeeze multiple blank lines into one
|
||||
more-help-plain = Suppress underlining
|
||||
more-help-lines = The number of lines per screen full
|
||||
more-help-number = Same as --lines option argument
|
||||
more-help-from-line = Start displaying each file at line number
|
||||
more-help-pattern = The string to be searched in each file before starting to display it
|
||||
more-help-files = Path to the files to be read
|
||||
|
||||
# Other messages
|
||||
more-help-message = [Press space to continue, 'q' to quit.]
|
||||
more-press-return = press RETURN
|
||||
|
|
30
src/uu/more/locales/fr-FR.ftl
Normal file
30
src/uu/more/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,30 @@
|
|||
more-about = Afficher le contenu d'un fichier texte
|
||||
more-usage = more [OPTIONS] FICHIER...
|
||||
|
||||
# Messages d'erreur
|
||||
more-error-is-directory = {$path} est un répertoire.
|
||||
more-error-cannot-open-no-such-file = impossible d'ouvrir {$path} : Aucun fichier ou répertoire de ce nom
|
||||
more-error-cannot-open-io-error = impossible d'ouvrir {$path} : {$error}
|
||||
more-error-bad-usage = mauvaise utilisation
|
||||
more-error-cannot-seek-to-line = Impossible d'atteindre la ligne numéro {$line}
|
||||
more-error-pattern-not-found = Motif non trouvé
|
||||
more-error-unknown-key = Touche inconnue : '{$key}'. Appuyez sur 'h' pour les instructions. (non implémenté)
|
||||
|
||||
# Messages d'aide
|
||||
more-help-silent = Afficher l'aide au lieu de sonner la cloche lorsqu'une touche illégale est pressée
|
||||
more-help-logical = Ne pas faire de pause après une ligne contenant un ^L (saut de page)
|
||||
more-help-exit-on-eof = Quitter à la fin du fichier
|
||||
more-help-no-pause = Compter les lignes logiques plutôt que les lignes d'écran
|
||||
more-help-print-over = Ne pas défiler, effacer l'écran et afficher le texte
|
||||
more-help-clean-print = Ne pas défiler, afficher le texte et nettoyer les fins de ligne
|
||||
more-help-squeeze = Compresser plusieurs lignes vides en une seule
|
||||
more-help-plain = Supprimer le soulignement
|
||||
more-help-lines = Le nombre de lignes par écran complet
|
||||
more-help-number = Identique à l'argument de l'option --lines
|
||||
more-help-from-line = Commencer l'affichage de chaque fichier au numéro de ligne
|
||||
more-help-pattern = La chaîne à rechercher dans chaque fichier avant de commencer à l'afficher
|
||||
more-help-files = Chemin vers les fichiers à lire
|
||||
|
||||
# Autres messages
|
||||
more-help-message = [Appuyez sur espace pour continuer, 'q' pour quitter.]
|
||||
more-press-return = appuyez sur ENTRÉE
|
|
@ -4,6 +4,7 @@
|
|||
// file that was distributed with this source code.
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::File,
|
||||
io::{BufRead, BufReader, Stdin, Stdout, Write, stdin, stdout},
|
||||
panic::set_hook,
|
||||
|
@ -26,13 +27,66 @@ use uucore::error::{UResult, USimpleError, UUsageError};
|
|||
use uucore::format_usage;
|
||||
use uucore::{display::Quotable, show};
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum MoreError {
|
||||
IsDirectory(String),
|
||||
CannotOpenNoSuchFile(String),
|
||||
CannotOpenIOError(String, std::io::ErrorKind),
|
||||
BadUsage,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MoreError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
MoreError::IsDirectory(path) => {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"more-error-is-directory",
|
||||
HashMap::from([("path".to_string(), path.quote().to_string())])
|
||||
)
|
||||
)
|
||||
}
|
||||
MoreError::CannotOpenNoSuchFile(path) => {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"more-error-cannot-open-no-such-file",
|
||||
HashMap::from([("path".to_string(), path.quote().to_string())])
|
||||
)
|
||||
)
|
||||
}
|
||||
MoreError::CannotOpenIOError(path, error) => {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"more-error-cannot-open-io-error",
|
||||
HashMap::from([
|
||||
("path".to_string(), path.quote().to_string()),
|
||||
("error".to_string(), error.to_string())
|
||||
])
|
||||
)
|
||||
)
|
||||
}
|
||||
MoreError::BadUsage => {
|
||||
write!(f, "{}", get_message("more-error-bad-usage"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MoreError {}
|
||||
|
||||
const BELL: char = '\x07'; // Printing this character will ring the bell
|
||||
|
||||
// The prompt to be displayed at the top of the screen when viewing multiple files,
|
||||
// with the file name in the middle
|
||||
const MULTI_FILE_TOP_PROMPT: &str = "\r::::::::::::::\n\r{}\n\r::::::::::::::\n";
|
||||
const HELP_MESSAGE: &str = "[Press space to continue, 'q' to quit.]";
|
||||
|
||||
pub mod options {
|
||||
pub const SILENT: &str = "silent";
|
||||
|
@ -111,14 +165,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if file.is_dir() {
|
||||
show!(UUsageError::new(
|
||||
0,
|
||||
format!("{} is a directory.", file.quote()),
|
||||
MoreError::IsDirectory(file.to_string_lossy().to_string()).to_string(),
|
||||
));
|
||||
continue;
|
||||
}
|
||||
if !file.exists() {
|
||||
show!(USimpleError::new(
|
||||
0,
|
||||
format!("cannot open {}: No such file or directory", file.quote()),
|
||||
MoreError::CannotOpenNoSuchFile(file.to_string_lossy().to_string()).to_string(),
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
@ -126,7 +180,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
Err(why) => {
|
||||
show!(USimpleError::new(
|
||||
0,
|
||||
format!("cannot open {}: {}", file.quote(), why.kind()),
|
||||
MoreError::CannotOpenIOError(
|
||||
file.to_string_lossy().to_string(),
|
||||
why.kind()
|
||||
)
|
||||
.to_string(),
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
@ -144,7 +202,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let stdin = stdin();
|
||||
if stdin.is_tty() {
|
||||
// stdin is not a pipe
|
||||
return Err(UUsageError::new(1, "bad usage"));
|
||||
return Err(UUsageError::new(1, MoreError::BadUsage.to_string()));
|
||||
}
|
||||
more(InputType::Stdin(stdin), false, None, None, &mut options)?;
|
||||
}
|
||||
|
@ -163,49 +221,49 @@ pub fn uu_app() -> Command {
|
|||
.short('d')
|
||||
.long(options::SILENT)
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Display help instead of ringing bell when an illegal key is pressed"),
|
||||
.help(get_message("more-help-silent")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::LOGICAL)
|
||||
.short('l')
|
||||
.long(options::LOGICAL)
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Do not pause after any line containing a ^L (form feed)"),
|
||||
.help(get_message("more-help-logical")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::EXIT_ON_EOF)
|
||||
.short('e')
|
||||
.long(options::EXIT_ON_EOF)
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Exit on End-Of-File"),
|
||||
.help(get_message("more-help-exit-on-eof")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NO_PAUSE)
|
||||
.short('f')
|
||||
.long(options::NO_PAUSE)
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Count logical lines, rather than screen lines"),
|
||||
.help(get_message("more-help-no-pause")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PRINT_OVER)
|
||||
.short('p')
|
||||
.long(options::PRINT_OVER)
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Do not scroll, clear screen and display text"),
|
||||
.help(get_message("more-help-print-over")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::CLEAN_PRINT)
|
||||
.short('c')
|
||||
.long(options::CLEAN_PRINT)
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Do not scroll, display text and clean line ends"),
|
||||
.help(get_message("more-help-clean-print")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SQUEEZE)
|
||||
.short('s')
|
||||
.long(options::SQUEEZE)
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Squeeze multiple blank lines into one"),
|
||||
.help(get_message("more-help-squeeze")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PLAIN)
|
||||
|
@ -213,7 +271,7 @@ pub fn uu_app() -> Command {
|
|||
.long(options::PLAIN)
|
||||
.action(ArgAction::SetTrue)
|
||||
.hide(true)
|
||||
.help("Suppress underlining"),
|
||||
.help(get_message("more-help-plain")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::LINES)
|
||||
|
@ -222,14 +280,14 @@ pub fn uu_app() -> Command {
|
|||
.value_name("number")
|
||||
.num_args(1)
|
||||
.value_parser(value_parser!(u16).range(0..))
|
||||
.help("The number of lines per screen full"),
|
||||
.help(get_message("more-help-lines")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NUMBER)
|
||||
.long(options::NUMBER)
|
||||
.num_args(1)
|
||||
.value_parser(value_parser!(u16).range(0..))
|
||||
.help("Same as --lines option argument"),
|
||||
.help(get_message("more-help-number")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FROM_LINE)
|
||||
|
@ -238,7 +296,7 @@ pub fn uu_app() -> Command {
|
|||
.num_args(1)
|
||||
.value_name("number")
|
||||
.value_parser(value_parser!(usize))
|
||||
.help("Start displaying each file at line number"),
|
||||
.help(get_message("more-help-from-line")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::PATTERN)
|
||||
|
@ -247,13 +305,13 @@ pub fn uu_app() -> Command {
|
|||
.allow_hyphen_values(true)
|
||||
.required(false)
|
||||
.value_name("pattern")
|
||||
.help("The string to be searched in each file before starting to display it"),
|
||||
.help(get_message("more-help-pattern")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FILES)
|
||||
.required(false)
|
||||
.action(ArgAction::Append)
|
||||
.help("Path to the files to be read")
|
||||
.help(get_message("more-help-files"))
|
||||
.value_hint(clap::ValueHint::FilePath),
|
||||
)
|
||||
}
|
||||
|
@ -454,9 +512,13 @@ impl<'a> Pager<'a> {
|
|||
if !self.read_until_line(self.upper_mark)? {
|
||||
write!(
|
||||
self.stdout,
|
||||
"\r{}Cannot seek to line number {} (press RETURN){}",
|
||||
"\r{}{} ({}){}",
|
||||
Attribute::Reverse,
|
||||
self.upper_mark + 1,
|
||||
get_message_with_args(
|
||||
"more-error-cannot-seek-to-line",
|
||||
HashMap::from([("line".to_string(), (self.upper_mark + 1).to_string())])
|
||||
),
|
||||
get_message("more-press-return"),
|
||||
Attribute::Reset,
|
||||
)?;
|
||||
self.stdout.flush()?;
|
||||
|
@ -515,8 +577,10 @@ impl<'a> Pager<'a> {
|
|||
self.pattern = None;
|
||||
write!(
|
||||
self.stdout,
|
||||
"\r{}Pattern not found (press RETURN){}",
|
||||
"\r{}{} ({}){}",
|
||||
Attribute::Reverse,
|
||||
get_message("more-error-pattern-not-found"),
|
||||
get_message("more-press-return"),
|
||||
Attribute::Reset,
|
||||
)?;
|
||||
self.stdout.flush()?;
|
||||
|
@ -807,9 +871,13 @@ impl<'a> Pager<'a> {
|
|||
// - In normal mode: ring bell (BELL char) on wrong key or show basic prompt
|
||||
let banner = match (self.silent, wrong_key) {
|
||||
(true, Some(key)) => format!(
|
||||
"{status}[Unknown key: '{key}'. Press 'h' for instructions. (unimplemented)]"
|
||||
"{status}[{}]",
|
||||
get_message_with_args(
|
||||
"more-error-unknown-key",
|
||||
HashMap::from([("key".to_string(), key.to_string())])
|
||||
)
|
||||
),
|
||||
(true, None) => format!("{status}{HELP_MESSAGE}"),
|
||||
(true, None) => format!("{status}{}", get_message("more-help-message")),
|
||||
(false, Some(_)) => format!("{status}{BELL}"),
|
||||
(false, None) => status,
|
||||
};
|
||||
|
@ -1007,7 +1075,7 @@ mod tests {
|
|||
.build();
|
||||
pager.draw_status_bar(None);
|
||||
let stdout = String::from_utf8_lossy(&pager.stdout);
|
||||
assert!(stdout.contains(HELP_MESSAGE));
|
||||
assert!(stdout.contains(&get_message("more-help-message")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1080,7 +1148,10 @@ mod tests {
|
|||
assert!(pager.handle_from_line().is_ok());
|
||||
assert_eq!(pager.upper_mark, 0);
|
||||
let stdout = String::from_utf8_lossy(&pager.stdout);
|
||||
assert!(stdout.contains("Cannot seek to line number 100"));
|
||||
assert!(stdout.contains(&get_message_with_args(
|
||||
"more-error-cannot-seek-to-line",
|
||||
HashMap::from([("line".to_string(), "100".to_string())])
|
||||
)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1101,7 +1172,7 @@ mod tests {
|
|||
let mut pager = TestPagerBuilder::new(content).pattern("qux").build();
|
||||
assert!(pager.handle_pattern_search().is_ok());
|
||||
let stdout = String::from_utf8_lossy(&pager.stdout);
|
||||
assert!(stdout.contains("Pattern not found"));
|
||||
assert!(stdout.contains(&get_message("more-error-pattern-not-found")));
|
||||
assert_eq!(pager.pattern, None);
|
||||
assert_eq!(pager.upper_mark, 0);
|
||||
}
|
||||
|
@ -1111,11 +1182,14 @@ mod tests {
|
|||
let mut pager = TestPagerBuilder::default().silent().build();
|
||||
pager.draw_status_bar(Some('x'));
|
||||
let stdout = String::from_utf8_lossy(&pager.stdout);
|
||||
assert!(stdout.contains("Unknown key: 'x'"));
|
||||
assert!(stdout.contains(&get_message_with_args(
|
||||
"more-error-unknown-key",
|
||||
HashMap::from([("key".to_string(), "x".to_string())])
|
||||
)));
|
||||
|
||||
pager = TestPagerBuilder::default().build();
|
||||
pager.draw_status_bar(Some('x'));
|
||||
let stdout = String::from_utf8_lossy(&pager.stdout);
|
||||
assert!(stdout.contains(BELL));
|
||||
assert!(stdout.contains(&BELL.to_string()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,3 +14,50 @@ mv-after-help = When specifying more than one of -i, -f, -n, only the final one
|
|||
- all This is the default operation when an --update option is not specified, and results in all existing files in the destination being replaced.
|
||||
- none This is similar to the --no-clobber option, in that no files in the destination are replaced, but also skipping a file does not induce a failure.
|
||||
- older This is the default operation when --update is specified, and results in files being replaced if they’re older than the corresponding source file.
|
||||
|
||||
# Error messages
|
||||
mv-error-no-such-file = cannot stat {$path}: No such file or directory
|
||||
mv-error-cannot-stat-not-directory = cannot stat {$path}: Not a directory
|
||||
mv-error-same-file = {$source} and {$target} are the same file
|
||||
mv-error-self-target-subdirectory = cannot move {$source} to a subdirectory of itself, {$target}
|
||||
mv-error-directory-to-non-directory = cannot overwrite directory {$path} with non-directory
|
||||
mv-error-non-directory-to-directory = cannot overwrite non-directory {$target} with directory {$source}
|
||||
mv-error-not-directory = target {$path}: Not a directory
|
||||
mv-error-target-not-directory = target directory {$path}: Not a directory
|
||||
mv-error-failed-access-not-directory = failed to access {$path}: Not a directory
|
||||
mv-error-backup-with-no-clobber = cannot combine --backup with -n/--no-clobber or --update=none-fail
|
||||
mv-error-extra-operand = mv: extra operand {$operand}
|
||||
mv-error-backup-might-destroy-source = backing up {$target} might destroy source; {$source} not moved
|
||||
mv-error-will-not-overwrite-just-created = will not overwrite just-created '{$target}' with '{$source}'
|
||||
mv-error-not-replacing = not replacing {$target}
|
||||
mv-error-cannot-move = cannot move {$source} to {$target}
|
||||
mv-error-directory-not-empty = Directory not empty
|
||||
mv-error-dangling-symlink = can't determine symlink type, since it is dangling
|
||||
mv-error-no-symlink-support = your operating system does not support symlinks
|
||||
mv-error-permission-denied = Permission denied
|
||||
mv-error-inter-device-move-failed = inter-device move failed: '{$from}' to '{$to}'; unable to remove target: {$err}
|
||||
|
||||
# Help messages
|
||||
mv-help-force = do not prompt before overwriting
|
||||
mv-help-interactive = prompt before override
|
||||
mv-help-no-clobber = do not overwrite an existing file
|
||||
mv-help-strip-trailing-slashes = remove any trailing slashes from each SOURCE argument
|
||||
mv-help-target-directory = move all SOURCE arguments into DIRECTORY
|
||||
mv-help-no-target-directory = treat DEST as a normal file
|
||||
mv-help-verbose = explain what is being done
|
||||
mv-help-progress = Display a progress bar.
|
||||
Note: this feature is not supported by GNU coreutils.
|
||||
mv-help-debug = explain how a file is copied. Implies -v
|
||||
|
||||
# Verbose messages
|
||||
mv-verbose-renamed = renamed {$from} -> {$to}
|
||||
mv-verbose-renamed-with-backup = renamed {$from} -> {$to} (backup: {$backup})
|
||||
|
||||
# Debug messages
|
||||
mv-debug-skipped = skipped {$target}
|
||||
|
||||
# Prompt messages
|
||||
mv-prompt-overwrite = overwrite {$target}?
|
||||
|
||||
# Progress messages
|
||||
mv-progress-moving = moving
|
||||
|
|
63
src/uu/mv/locales/fr-FR.ftl
Normal file
63
src/uu/mv/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,63 @@
|
|||
mv-about = Déplacer SOURCE vers DEST, ou plusieurs SOURCE(s) vers RÉPERTOIRE.
|
||||
mv-usage = mv [OPTION]... [-T] SOURCE DEST
|
||||
mv [OPTION]... SOURCE... RÉPERTOIRE
|
||||
mv [OPTION]... -t RÉPERTOIRE SOURCE...
|
||||
mv-after-help = Lors de la spécification de plus d'une option parmi -i, -f, -n, seule la dernière prend effet.
|
||||
|
||||
Ne pas déplacer un non-répertoire qui a une destination existante avec un horodatage de modification identique ou plus récent ;
|
||||
au lieu de cela, ignorer silencieusement le fichier sans échouer. Si le déplacement traverse les limites du système de fichiers, la comparaison est
|
||||
avec l'horodatage source tronqué aux résolutions du système de fichiers de destination et des appels système utilisés
|
||||
pour mettre à jour les horodatages ; cela évite le travail en double si plusieurs commandes mv -u sont exécutées avec la même source
|
||||
et destination. Cette option est ignorée si l'option -n ou --no-clobber est également spécifiée, qui donne plus de contrôle
|
||||
sur quels fichiers existants dans la destination sont remplacés, et sa valeur peut être une des suivantes :
|
||||
|
||||
- all C'est l'opération par défaut quand une option --update n'est pas spécifiée, et résulte en tous les fichiers existants dans la destination étant remplacés.
|
||||
- none C'est similaire à l'option --no-clobber, en ce que aucun fichier dans la destination n'est remplacé, mais aussi ignorer un fichier n'induit pas un échec.
|
||||
- older C'est l'opération par défaut quand --update est spécifié, et résulte en des fichiers étant remplacés s'ils sont plus anciens que le fichier source correspondant.
|
||||
|
||||
# Messages d'erreur
|
||||
mv-error-no-such-file = impossible de lire {$path} : Aucun fichier ou répertoire de ce nom
|
||||
mv-error-cannot-stat-not-directory = impossible de lire {$path} : N'est pas un répertoire
|
||||
mv-error-same-file = {$source} et {$target} sont le même fichier
|
||||
mv-error-self-target-subdirectory = impossible de déplacer {$source} vers un sous-répertoire de lui-même, {$target}
|
||||
mv-error-directory-to-non-directory = impossible d'écraser le répertoire {$path} avec un non-répertoire
|
||||
mv-error-non-directory-to-directory = impossible d'écraser le non-répertoire {$target} avec le répertoire {$source}
|
||||
mv-error-not-directory = cible {$path} : N'est pas un répertoire
|
||||
mv-error-target-not-directory = répertoire cible {$path} : N'est pas un répertoire
|
||||
mv-error-failed-access-not-directory = impossible d'accéder à {$path} : N'est pas un répertoire
|
||||
mv-error-backup-with-no-clobber = impossible de combiner --backup avec -n/--no-clobber ou --update=none-fail
|
||||
mv-error-extra-operand = mv : opérande supplémentaire {$operand}
|
||||
mv-error-backup-might-destroy-source = sauvegarder {$target} pourrait détruire la source ; {$source} non déplacé
|
||||
mv-error-will-not-overwrite-just-created = ne va pas écraser le fichier qui vient d'être créé '{$target}' avec '{$source}'
|
||||
mv-error-not-replacing = ne remplace pas {$target}
|
||||
mv-error-cannot-move = impossible de déplacer {$source} vers {$target}
|
||||
mv-error-directory-not-empty = Répertoire non vide
|
||||
mv-error-dangling-symlink = impossible de déterminer le type de lien symbolique, car il est suspendu
|
||||
mv-error-no-symlink-support = votre système d'exploitation ne prend pas en charge les liens symboliques
|
||||
mv-error-permission-denied = Permission refusée
|
||||
mv-error-inter-device-move-failed = échec du déplacement inter-périphérique : '{$from}' vers '{$to}' ; impossible de supprimer la cible : {$err}
|
||||
|
||||
# Messages d'aide
|
||||
mv-help-force = ne pas demander avant d'écraser
|
||||
mv-help-interactive = demander avant d'écraser
|
||||
mv-help-no-clobber = ne pas écraser un fichier existant
|
||||
mv-help-strip-trailing-slashes = supprimer toutes les barres obliques de fin de chaque argument SOURCE
|
||||
mv-help-target-directory = déplacer tous les arguments SOURCE dans RÉPERTOIRE
|
||||
mv-help-no-target-directory = traiter DEST comme un fichier normal
|
||||
mv-help-verbose = expliquer ce qui est fait
|
||||
mv-help-progress = Afficher une barre de progression.
|
||||
Note : cette fonctionnalité n'est pas supportée par GNU coreutils.
|
||||
mv-help-debug = expliquer comment un fichier est copié. Implique -v
|
||||
|
||||
# Messages verbeux
|
||||
mv-verbose-renamed = renommé {$from} -> {$to}
|
||||
mv-verbose-renamed-with-backup = renommé {$from} -> {$to} (sauvegarde : {$backup})
|
||||
|
||||
# Messages de débogage
|
||||
mv-debug-skipped = ignoré {$target}
|
||||
|
||||
# Messages de confirmation
|
||||
mv-prompt-overwrite = écraser {$target} ?
|
||||
|
||||
# Messages de progression
|
||||
mv-progress-moving = déplacement
|
|
@ -2,36 +2,30 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
use uucore::error::UError;
|
||||
use uucore::locale::get_message_with_args;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MvError {
|
||||
#[error("cannot stat {0}: No such file or directory")]
|
||||
#[error("{}", get_message_with_args("mv-error-no-such-file", HashMap::from([("path".to_string(), .0.clone())])))]
|
||||
NoSuchFile(String),
|
||||
|
||||
#[error("cannot stat {0}: Not a directory")]
|
||||
#[error("{}", get_message_with_args("mv-error-cannot-stat-not-directory", HashMap::from([("path".to_string(), .0.clone())])))]
|
||||
CannotStatNotADirectory(String),
|
||||
|
||||
#[error("{0} and {1} are the same file")]
|
||||
#[error("{}", get_message_with_args("mv-error-same-file", HashMap::from([("source".to_string(), .0.clone()), ("target".to_string(), .1.clone())])))]
|
||||
SameFile(String, String),
|
||||
|
||||
#[error("cannot move {0} to a subdirectory of itself, {1}")]
|
||||
#[error("{}", get_message_with_args("mv-error-self-target-subdirectory", HashMap::from([("source".to_string(), .0.clone()), ("target".to_string(), .1.clone())])))]
|
||||
SelfTargetSubdirectory(String, String),
|
||||
|
||||
#[error("cannot overwrite directory {0} with non-directory")]
|
||||
#[error("{}", get_message_with_args("mv-error-directory-to-non-directory", HashMap::from([("path".to_string(), .0.clone())])))]
|
||||
DirectoryToNonDirectory(String),
|
||||
|
||||
#[error("cannot overwrite non-directory {1} with directory {0}")]
|
||||
#[error("{}", get_message_with_args("mv-error-non-directory-to-directory", HashMap::from([("source".to_string(), .0.clone()), ("target".to_string(), .1.clone())])))]
|
||||
NonDirectoryToDirectory(String, String),
|
||||
|
||||
#[error("target {0}: Not a directory")]
|
||||
#[error("{}", get_message_with_args("mv-error-not-directory", HashMap::from([("path".to_string(), .0.clone())])))]
|
||||
NotADirectory(String),
|
||||
|
||||
#[error("target directory {0}: Not a directory")]
|
||||
#[error("{}", get_message_with_args("mv-error-target-not-directory", HashMap::from([("path".to_string(), .0.clone())])))]
|
||||
TargetNotADirectory(String),
|
||||
|
||||
#[error("failed to access {0}: Not a directory")]
|
||||
#[error("{}", get_message_with_args("mv-error-failed-access-not-directory", HashMap::from([("path".to_string(), .0.clone())])))]
|
||||
FailedToAccessNotADirectory(String),
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use clap::builder::ValueParser;
|
|||
use clap::{Arg, ArgAction, ArgMatches, Command, error::ErrorKind};
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
|
@ -48,7 +48,7 @@ use fs_extra::dir::{
|
|||
};
|
||||
|
||||
use crate::error::MvError;
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
/// Options contains all the possible behaviors and flags for mv.
|
||||
///
|
||||
|
@ -167,7 +167,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
{
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
"cannot combine --backup with -n/--no-clobber or --update=none-fail",
|
||||
get_message("mv-error-backup-with-no-clobber"),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_FORCE)
|
||||
.short('f')
|
||||
.long(OPT_FORCE)
|
||||
.help("do not prompt before overwriting")
|
||||
.help(get_message("mv-help-force"))
|
||||
.overrides_with_all([OPT_INTERACTIVE, OPT_NO_CLOBBER])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -222,7 +222,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_INTERACTIVE)
|
||||
.short('i')
|
||||
.long(OPT_INTERACTIVE)
|
||||
.help("prompt before override")
|
||||
.help(get_message("mv-help-interactive"))
|
||||
.overrides_with_all([OPT_FORCE, OPT_NO_CLOBBER])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
|
@ -230,14 +230,14 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_NO_CLOBBER)
|
||||
.short('n')
|
||||
.long(OPT_NO_CLOBBER)
|
||||
.help("do not overwrite an existing file")
|
||||
.help(get_message("mv-help-no-clobber"))
|
||||
.overrides_with_all([OPT_FORCE, OPT_INTERACTIVE])
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_STRIP_TRAILING_SLASHES)
|
||||
.long(OPT_STRIP_TRAILING_SLASHES)
|
||||
.help("remove any trailing slashes from each SOURCE argument")
|
||||
.help(get_message("mv-help-strip-trailing-slashes"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(backup_control::arguments::backup())
|
||||
|
@ -249,7 +249,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_TARGET_DIRECTORY)
|
||||
.short('t')
|
||||
.long(OPT_TARGET_DIRECTORY)
|
||||
.help("move all SOURCE arguments into DIRECTORY")
|
||||
.help(get_message("mv-help-target-directory"))
|
||||
.value_name("DIRECTORY")
|
||||
.value_hint(clap::ValueHint::DirPath)
|
||||
.conflicts_with(OPT_NO_TARGET_DIRECTORY)
|
||||
|
@ -259,24 +259,21 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(OPT_NO_TARGET_DIRECTORY)
|
||||
.short('T')
|
||||
.long(OPT_NO_TARGET_DIRECTORY)
|
||||
.help("treat DEST as a normal file")
|
||||
.help(get_message("mv-help-no-target-directory"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_VERBOSE)
|
||||
.short('v')
|
||||
.long(OPT_VERBOSE)
|
||||
.help("explain what is being done")
|
||||
.help(get_message("mv-help-verbose"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_PROGRESS)
|
||||
.short('g')
|
||||
.long(OPT_PROGRESS)
|
||||
.help(
|
||||
"Display a progress bar. \n\
|
||||
Note: this feature is not supported by GNU coreutils.",
|
||||
)
|
||||
.help(get_message("mv-help-progress"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
|
@ -290,7 +287,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(OPT_DEBUG)
|
||||
.long(OPT_DEBUG)
|
||||
.help("explain how a file is copied. Implies -v")
|
||||
.help(get_message("mv-help-debug"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
}
|
||||
|
@ -326,10 +323,12 @@ fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()>
|
|||
if opts.backup == BackupMode::Simple && source_is_target_backup(source, target, &opts.suffix) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!(
|
||||
"backing up {} might destroy source; {} not moved",
|
||||
target.quote(),
|
||||
source.quote()
|
||||
get_message_with_args(
|
||||
"mv-error-backup-might-destroy-source",
|
||||
HashMap::from([
|
||||
("target".to_string(), target.quote().to_string()),
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
]),
|
||||
),
|
||||
)
|
||||
.into());
|
||||
|
@ -359,7 +358,13 @@ fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()>
|
|||
if opts.no_target_dir {
|
||||
if source.is_dir() {
|
||||
rename(source, target, opts, None).map_err_context(|| {
|
||||
format!("cannot move {} to {}", source.quote(), target.quote())
|
||||
get_message_with_args(
|
||||
"mv-error-cannot-move",
|
||||
HashMap::from([
|
||||
("source".to_string(), source.quote().to_string()),
|
||||
("target".to_string(), target.quote().to_string()),
|
||||
]),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
Err(MvError::DirectoryToNonDirectory(target.quote().to_string()).into())
|
||||
|
@ -371,7 +376,13 @@ fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()>
|
|||
match opts.overwrite {
|
||||
OverwriteMode::NoClobber => return Ok(()),
|
||||
OverwriteMode::Interactive => {
|
||||
if !prompt_yes!("overwrite {}? ", target.quote()) {
|
||||
if !prompt_yes!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"mv-prompt-overwrite",
|
||||
HashMap::from([("target".to_string(), target.quote().to_string())]),
|
||||
)
|
||||
) {
|
||||
return Err(io::Error::other("").into());
|
||||
}
|
||||
}
|
||||
|
@ -473,7 +484,10 @@ fn handle_multiple_paths(paths: &[PathBuf], opts: &Options) -> UResult<()> {
|
|||
if opts.no_target_dir {
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
format!("mv: extra operand {}", paths[2].quote()),
|
||||
get_message_with_args(
|
||||
"mv-error-extra-operand",
|
||||
HashMap::from([("operand".to_string(), paths[2].quote().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
let target_dir = paths.last().unwrap();
|
||||
|
@ -511,11 +525,17 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, options: &Options)
|
|||
|
||||
let count_progress = if let Some(ref multi_progress) = multi_progress {
|
||||
if files.len() > 1 {
|
||||
Some(multi_progress.add(
|
||||
ProgressBar::new(files.len().try_into().unwrap()).with_style(
|
||||
ProgressStyle::with_template("moving {msg} {wide_bar} {pos}/{len}").unwrap(),
|
||||
Some(
|
||||
multi_progress.add(
|
||||
ProgressBar::new(files.len().try_into().unwrap()).with_style(
|
||||
ProgressStyle::with_template(&format!(
|
||||
"{} {{msg}} {{wide_bar}} {{pos}}/{{len}}",
|
||||
get_message("mv-progress-moving")
|
||||
))
|
||||
.unwrap(),
|
||||
),
|
||||
),
|
||||
))
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -545,10 +565,12 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, options: &Options)
|
|||
// If the target file was already created in this mv call, do not overwrite
|
||||
show!(USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"will not overwrite just-created '{}' with '{}'",
|
||||
targetpath.display(),
|
||||
sourcepath.display()
|
||||
get_message_with_args(
|
||||
"mv-error-will-not-overwrite-just-created",
|
||||
HashMap::from([
|
||||
("target".to_string(), targetpath.display().to_string()),
|
||||
("source".to_string(), sourcepath.display().to_string())
|
||||
])
|
||||
),
|
||||
));
|
||||
continue;
|
||||
|
@ -565,10 +587,12 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, options: &Options)
|
|||
Err(e) if e.to_string().is_empty() => set_exit_code(1),
|
||||
Err(e) => {
|
||||
let e = e.map_err_context(|| {
|
||||
format!(
|
||||
"cannot move {} to {}",
|
||||
sourcepath.quote(),
|
||||
targetpath.quote()
|
||||
get_message_with_args(
|
||||
"mv-error-cannot-move",
|
||||
HashMap::from([
|
||||
("source".to_string(), sourcepath.quote().to_string()),
|
||||
("target".to_string(), targetpath.quote().to_string()),
|
||||
]),
|
||||
)
|
||||
});
|
||||
match multi_progress {
|
||||
|
@ -597,7 +621,13 @@ fn rename(
|
|||
if to.exists() {
|
||||
if opts.update == UpdateMode::None {
|
||||
if opts.debug {
|
||||
println!("skipped {}", to.quote());
|
||||
println!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"mv-debug-skipped",
|
||||
HashMap::from([("target".to_string(), to.quote().to_string())])
|
||||
)
|
||||
);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -609,19 +639,34 @@ fn rename(
|
|||
}
|
||||
|
||||
if opts.update == UpdateMode::NoneFail {
|
||||
let err_msg = format!("not replacing {}", to.quote());
|
||||
let err_msg = get_message_with_args(
|
||||
"mv-error-not-replacing",
|
||||
HashMap::from([("target".to_string(), to.quote().to_string())]),
|
||||
);
|
||||
return Err(io::Error::other(err_msg));
|
||||
}
|
||||
|
||||
match opts.overwrite {
|
||||
OverwriteMode::NoClobber => {
|
||||
if opts.debug {
|
||||
println!("skipped {}", to.quote());
|
||||
println!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"mv-debug-skipped",
|
||||
HashMap::from([("target".to_string(), to.quote().to_string())])
|
||||
)
|
||||
);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
OverwriteMode::Interactive => {
|
||||
if !prompt_yes!("overwrite {}?", to.quote()) {
|
||||
if !prompt_yes!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"mv-prompt-overwrite",
|
||||
HashMap::from([("target".to_string(), to.quote().to_string())]),
|
||||
)
|
||||
) {
|
||||
return Err(io::Error::other(""));
|
||||
}
|
||||
}
|
||||
|
@ -641,7 +686,9 @@ fn rename(
|
|||
if is_empty_dir(to) {
|
||||
fs::remove_dir(to)?;
|
||||
} else {
|
||||
return Err(io::Error::other("Directory not empty"));
|
||||
return Err(io::Error::other(get_message(
|
||||
"mv-error-directory-not-empty",
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -650,13 +697,21 @@ fn rename(
|
|||
|
||||
if opts.verbose {
|
||||
let message = match backup_path {
|
||||
Some(path) => format!(
|
||||
"renamed {} -> {} (backup: {})",
|
||||
from.quote(),
|
||||
to.quote(),
|
||||
path.quote()
|
||||
Some(path) => get_message_with_args(
|
||||
"mv-verbose-renamed-with-backup",
|
||||
HashMap::from([
|
||||
("from".to_string(), from.quote().to_string()),
|
||||
("to".to_string(), to.quote().to_string()),
|
||||
("backup".to_string(), path.quote().to_string()),
|
||||
]),
|
||||
),
|
||||
None => get_message_with_args(
|
||||
"mv-verbose-renamed",
|
||||
HashMap::from([
|
||||
("from".to_string(), from.quote().to_string()),
|
||||
("to".to_string(), to.quote().to_string()),
|
||||
]),
|
||||
),
|
||||
None => format!("renamed {} -> {}", from.quote(), to.quote()),
|
||||
};
|
||||
|
||||
match multi_progress {
|
||||
|
@ -751,7 +806,7 @@ fn rename_symlink_fallback(from: &Path, to: &Path) -> io::Result<()> {
|
|||
} else {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"can't determine symlink type, since it is dangling",
|
||||
get_message("mv-error-dangling-symlink"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -761,7 +816,7 @@ fn rename_symlink_fallback(from: &Path, to: &Path) -> io::Result<()> {
|
|||
let path_symlink_points_to = fs::read_link(from)?;
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"your operating system does not support symlinks",
|
||||
get_message("mv-error-no-symlink-support"),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -802,8 +857,7 @@ fn rename_dir_fallback(
|
|||
};
|
||||
|
||||
#[cfg(all(unix, not(any(target_os = "macos", target_os = "redox"))))]
|
||||
let xattrs =
|
||||
fsxattr::retrieve_xattrs(from).unwrap_or_else(|_| std::collections::HashMap::new());
|
||||
let xattrs = fsxattr::retrieve_xattrs(from).unwrap_or_else(|_| HashMap::new());
|
||||
|
||||
let result = if let Some(ref pb) = progress_bar {
|
||||
move_dir_with_progress(from, to, &options, |process_info: TransitProcess| {
|
||||
|
@ -822,7 +876,7 @@ fn rename_dir_fallback(
|
|||
Err(err) => match err.kind {
|
||||
fs_extra::error::ErrorKind::PermissionDenied => Err(io::Error::new(
|
||||
io::ErrorKind::PermissionDenied,
|
||||
"Permission denied",
|
||||
get_message("mv-error-permission-denied"),
|
||||
)),
|
||||
_ => Err(io::Error::other(format!("{err:?}"))),
|
||||
},
|
||||
|
@ -837,9 +891,13 @@ fn rename_file_fallback(from: &Path, to: &Path) -> io::Result<()> {
|
|||
let from = from.to_string_lossy();
|
||||
io::Error::new(
|
||||
err.kind(),
|
||||
format!(
|
||||
"inter-device move failed: '{from}' to '{to}'\
|
||||
; unable to remove target: {err}"
|
||||
get_message_with_args(
|
||||
"mv-error-inter-device-move-failed",
|
||||
HashMap::from([
|
||||
("from".to_string(), from.to_string()),
|
||||
("to".to_string(), to.to_string()),
|
||||
("err".to_string(), err.to_string()),
|
||||
]),
|
||||
),
|
||||
)
|
||||
})?;
|
||||
|
|
|
@ -4,11 +4,9 @@ nice-about = Run COMMAND with an adjusted niceness, which affects process schedu
|
|||
nice-usage = nice [OPTION] [COMMAND [ARG]...]
|
||||
|
||||
# Error messages
|
||||
nice-error-getpriority = getpriority: { $error }
|
||||
nice-error-command-required-with-adjustment = A command must be given with an adjustment.
|
||||
nice-error-invalid-number = "{ $value }" is not a valid number: { $error }
|
||||
nice-warning-setpriority = { $util_name }: warning: setpriority: { $error }
|
||||
nice-error-execvp = execvp: { $error }
|
||||
|
||||
# Help text for command-line arguments
|
||||
nice-help-adjustment = add N to the niceness (default is 10)
|
||||
|
|
|
@ -111,10 +111,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if Error::last_os_error().raw_os_error().unwrap() != 0 {
|
||||
return Err(USimpleError::new(
|
||||
125,
|
||||
get_message_with_args(
|
||||
"nice-error-getpriority",
|
||||
HashMap::from([("error".to_string(), Error::last_os_error().to_string())]),
|
||||
),
|
||||
format!("getpriority: {}", Error::last_os_error()),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -183,13 +180,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
execvp(args[0], args.as_mut_ptr());
|
||||
}
|
||||
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"nice-error-execvp",
|
||||
HashMap::from([("error".to_string(), Error::last_os_error().to_string())])
|
||||
)
|
||||
);
|
||||
show_error!("execvp: {}", Error::last_os_error());
|
||||
|
||||
let exit_code = if Error::last_os_error().raw_os_error().unwrap() as c_int == libc::ENOENT {
|
||||
127
|
||||
|
|
|
@ -13,3 +13,27 @@ nl-after-help = STYLE is one of:
|
|||
- ln left justified, no leading zeros
|
||||
- rn right justified, no leading zeros
|
||||
- rz right justified, leading zeros
|
||||
|
||||
# Help messages
|
||||
nl-help-help = Print help information.
|
||||
nl-help-body-numbering = use STYLE for numbering body lines
|
||||
nl-help-section-delimiter = use CC for separating logical pages
|
||||
nl-help-footer-numbering = use STYLE for numbering footer lines
|
||||
nl-help-header-numbering = use STYLE for numbering header lines
|
||||
nl-help-line-increment = line number increment at each line
|
||||
nl-help-join-blank-lines = group of NUMBER empty lines counted as one
|
||||
nl-help-number-format = insert line numbers according to FORMAT
|
||||
nl-help-no-renumber = do not reset line numbers at logical pages
|
||||
nl-help-number-separator = add STRING after (possible) line number
|
||||
nl-help-starting-line-number = first line number on each logical page
|
||||
nl-help-number-width = use NUMBER columns for line numbers
|
||||
|
||||
# Error messages
|
||||
nl-error-invalid-arguments = Invalid arguments supplied.
|
||||
nl-error-could-not-read-line = could not read line
|
||||
nl-error-line-number-overflow = line number overflow
|
||||
nl-error-invalid-line-width = Invalid line number field width: ‘{ $value }’: Numerical result out of range
|
||||
nl-error-invalid-blank-lines = Invalid line number of blank lines: ‘{ $value }’: Numerical result out of range
|
||||
nl-error-invalid-regex = invalid regular expression
|
||||
nl-error-invalid-numbering-style = invalid numbering style: '{ $style }'
|
||||
nl-error-is-directory = { $path }: Is a directory
|
||||
|
|
39
src/uu/nl/locales/fr-FR.ftl
Normal file
39
src/uu/nl/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,39 @@
|
|||
nl-about = Numéroter les lignes des fichiers
|
||||
nl-usage = nl [OPTION]... [FICHIER]...
|
||||
nl-after-help = STYLE est l'un des suivants :
|
||||
|
||||
- a numéroter toutes les lignes
|
||||
- t numéroter seulement les lignes non vides
|
||||
- n ne numéroter aucune ligne
|
||||
- pBRE numéroter seulement les lignes qui contiennent une correspondance pour
|
||||
l'expression régulière de base, BRE
|
||||
|
||||
FORMAT est l'un des suivants :
|
||||
|
||||
- ln justifié à gauche, sans zéros en tête
|
||||
- rn justifié à droite, sans zéros en tête
|
||||
- rz justifié à droite, avec zéros en tête
|
||||
|
||||
# Messages d'aide
|
||||
nl-help-help = Afficher les informations d'aide.
|
||||
nl-help-body-numbering = utiliser STYLE pour numéroter les lignes du corps
|
||||
nl-help-section-delimiter = utiliser CC pour séparer les pages logiques
|
||||
nl-help-footer-numbering = utiliser STYLE pour numéroter les lignes de pied de page
|
||||
nl-help-header-numbering = utiliser STYLE pour numéroter les lignes d'en-tête
|
||||
nl-help-line-increment = incrément du numéro de ligne à chaque ligne
|
||||
nl-help-join-blank-lines = groupe de NUMBER lignes vides comptées comme une seule
|
||||
nl-help-number-format = insérer les numéros de ligne selon FORMAT
|
||||
nl-help-no-renumber = ne pas remettre à zéro les numéros de ligne aux pages logiques
|
||||
nl-help-number-separator = ajouter STRING après le numéro de ligne (éventuel)
|
||||
nl-help-starting-line-number = premier numéro de ligne sur chaque page logique
|
||||
nl-help-number-width = utiliser NUMBER colonnes pour les numéros de ligne
|
||||
|
||||
# Messages d'erreur
|
||||
nl-error-invalid-arguments = Arguments fournis invalides.
|
||||
nl-error-could-not-read-line = impossible de lire la ligne
|
||||
nl-error-line-number-overflow = débordement du numéro de ligne
|
||||
nl-error-invalid-line-width = Largeur de champ de numéro de ligne invalide : ‘{ $value }’ : Résultat numérique hors limites
|
||||
nl-error-invalid-blank-lines = Nombre de lignes vides invalide : ‘{ $value }’ : Résultat numérique hors limites
|
||||
nl-error-invalid-regex = expression régulière invalide
|
||||
nl-error-invalid-numbering-style = style de numérotation invalide : '{ $style }'
|
||||
nl-error-is-directory = { $path } : Est un répertoire
|
|
@ -5,6 +5,8 @@
|
|||
// spell-checker:ignore (ToDO) conv
|
||||
|
||||
use crate::options;
|
||||
use std::collections::HashMap;
|
||||
use uucore::locale::get_message_with_args;
|
||||
|
||||
// parse_options loads the options into the settings, returning an array of
|
||||
// error messages.
|
||||
|
@ -59,15 +61,17 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) ->
|
|||
match opts.get_one::<usize>(options::NUMBER_WIDTH) {
|
||||
None => {}
|
||||
Some(num) if *num > 0 => settings.number_width = *num,
|
||||
Some(_) => errs.push(String::from(
|
||||
"Invalid line number field width: ‘0’: Numerical result out of range",
|
||||
Some(_) => errs.push(get_message_with_args(
|
||||
"nl-error-invalid-line-width",
|
||||
HashMap::from([("value".to_string(), "0".to_string())]),
|
||||
)),
|
||||
}
|
||||
match opts.get_one::<u64>(options::JOIN_BLANK_LINES) {
|
||||
None => {}
|
||||
Some(num) if *num > 0 => settings.join_blank_lines = *num,
|
||||
Some(_) => errs.push(String::from(
|
||||
"Invalid line number of blank lines: ‘0’: Numerical result out of range",
|
||||
Some(_) => errs.push(get_message_with_args(
|
||||
"nl-error-invalid-blank-lines",
|
||||
HashMap::from([("value".to_string(), "0".to_string())]),
|
||||
)),
|
||||
}
|
||||
if let Some(num) = opts.get_one::<i64>(options::LINE_INCREMENT) {
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
// file that was distributed with this source code.
|
||||
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Read, stdin};
|
||||
use std::path::Path;
|
||||
use uucore::error::{FromIo, UResult, USimpleError, set_exit_code};
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
use uucore::{format_usage, show_error};
|
||||
|
||||
mod helper;
|
||||
|
@ -89,9 +90,12 @@ impl TryFrom<&str> for NumberingStyle {
|
|||
"n" => Ok(Self::None),
|
||||
_ if s.starts_with('p') => match regex::Regex::new(&s[1..]) {
|
||||
Ok(re) => Ok(Self::Regex(Box::new(re))),
|
||||
Err(_) => Err(String::from("invalid regular expression")),
|
||||
Err(_) => Err(get_message("nl-error-invalid-regex")),
|
||||
},
|
||||
_ => Err(format!("invalid numbering style: '{s}'")),
|
||||
_ => Err(get_message_with_args(
|
||||
"nl-error-invalid-numbering-style",
|
||||
HashMap::from([("style".to_string(), s.to_string())]),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +189,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if !parse_errors.is_empty() {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("Invalid arguments supplied.\n{}", parse_errors.join("\n")),
|
||||
format!(
|
||||
"{}\n{}",
|
||||
get_message("nl-error-invalid-arguments"),
|
||||
parse_errors.join("\n")
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -204,7 +212,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let path = Path::new(file);
|
||||
|
||||
if path.is_dir() {
|
||||
show_error!("{}: Is a directory", path.display());
|
||||
show_error!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"nl-error-is-directory",
|
||||
HashMap::from([("path".to_string(), path.display().to_string())])
|
||||
)
|
||||
);
|
||||
set_exit_code(1);
|
||||
} else {
|
||||
let reader = File::open(path).map_err_context(|| file.to_string())?;
|
||||
|
@ -228,7 +242,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::HELP)
|
||||
.long(options::HELP)
|
||||
.help("Print help information.")
|
||||
.help(get_message("nl-help-help"))
|
||||
.action(ArgAction::Help),
|
||||
)
|
||||
.arg(
|
||||
|
@ -241,35 +255,35 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::BODY_NUMBERING)
|
||||
.short('b')
|
||||
.long(options::BODY_NUMBERING)
|
||||
.help("use STYLE for numbering body lines")
|
||||
.help(get_message("nl-help-body-numbering"))
|
||||
.value_name("STYLE"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::SECTION_DELIMITER)
|
||||
.short('d')
|
||||
.long(options::SECTION_DELIMITER)
|
||||
.help("use CC for separating logical pages")
|
||||
.help(get_message("nl-help-section-delimiter"))
|
||||
.value_name("CC"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::FOOTER_NUMBERING)
|
||||
.short('f')
|
||||
.long(options::FOOTER_NUMBERING)
|
||||
.help("use STYLE for numbering footer lines")
|
||||
.help(get_message("nl-help-footer-numbering"))
|
||||
.value_name("STYLE"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::HEADER_NUMBERING)
|
||||
.short('h')
|
||||
.long(options::HEADER_NUMBERING)
|
||||
.help("use STYLE for numbering header lines")
|
||||
.help(get_message("nl-help-header-numbering"))
|
||||
.value_name("STYLE"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::LINE_INCREMENT)
|
||||
.short('i')
|
||||
.long(options::LINE_INCREMENT)
|
||||
.help("line number increment at each line")
|
||||
.help(get_message("nl-help-line-increment"))
|
||||
.value_name("NUMBER")
|
||||
.value_parser(clap::value_parser!(i64)),
|
||||
)
|
||||
|
@ -277,7 +291,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::JOIN_BLANK_LINES)
|
||||
.short('l')
|
||||
.long(options::JOIN_BLANK_LINES)
|
||||
.help("group of NUMBER empty lines counted as one")
|
||||
.help(get_message("nl-help-join-blank-lines"))
|
||||
.value_name("NUMBER")
|
||||
.value_parser(clap::value_parser!(u64)),
|
||||
)
|
||||
|
@ -285,7 +299,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::NUMBER_FORMAT)
|
||||
.short('n')
|
||||
.long(options::NUMBER_FORMAT)
|
||||
.help("insert line numbers according to FORMAT")
|
||||
.help(get_message("nl-help-number-format"))
|
||||
.value_name("FORMAT")
|
||||
.value_parser(["ln", "rn", "rz"]),
|
||||
)
|
||||
|
@ -293,21 +307,21 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::NO_RENUMBER)
|
||||
.short('p')
|
||||
.long(options::NO_RENUMBER)
|
||||
.help("do not reset line numbers at logical pages")
|
||||
.help(get_message("nl-help-no-renumber"))
|
||||
.action(ArgAction::SetFalse),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NUMBER_SEPARATOR)
|
||||
.short('s')
|
||||
.long(options::NUMBER_SEPARATOR)
|
||||
.help("add STRING after (possible) line number")
|
||||
.help(get_message("nl-help-number-separator"))
|
||||
.value_name("STRING"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::STARTING_LINE_NUMBER)
|
||||
.short('v')
|
||||
.long(options::STARTING_LINE_NUMBER)
|
||||
.help("first line number on each logical page")
|
||||
.help(get_message("nl-help-starting-line-number"))
|
||||
.value_name("NUMBER")
|
||||
.value_parser(clap::value_parser!(i64)),
|
||||
)
|
||||
|
@ -315,7 +329,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::NUMBER_WIDTH)
|
||||
.short('w')
|
||||
.long(options::NUMBER_WIDTH)
|
||||
.help("use NUMBER columns for line numbers")
|
||||
.help(get_message("nl-help-number-width"))
|
||||
.value_name("NUMBER")
|
||||
.value_parser(clap::value_parser!(usize)),
|
||||
)
|
||||
|
@ -326,7 +340,7 @@ fn nl<T: Read>(reader: &mut BufReader<T>, stats: &mut Stats, settings: &Settings
|
|||
let mut current_numbering_style = &settings.body_numbering;
|
||||
|
||||
for line in reader.lines() {
|
||||
let line = line.map_err_context(|| "could not read line".to_string())?;
|
||||
let line = line.map_err_context(|| get_message("nl-error-could-not-read-line"))?;
|
||||
|
||||
if line.is_empty() {
|
||||
stats.consecutive_empty_lines += 1;
|
||||
|
@ -366,7 +380,10 @@ fn nl<T: Read>(reader: &mut BufReader<T>, stats: &mut Stats, settings: &Settings
|
|||
|
||||
if is_line_numbered {
|
||||
let Some(line_number) = stats.line_number else {
|
||||
return Err(USimpleError::new(1, "line number overflow"));
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
get_message("nl-error-line-number-overflow"),
|
||||
));
|
||||
};
|
||||
println!(
|
||||
"{}{}{line}",
|
||||
|
|
|
@ -34,3 +34,41 @@ numfmt-after-help = UNIT options:
|
|||
Optional width value (%10f) will pad output. Optional zero (%010f) width
|
||||
will zero pad the number. Optional negative values (%-10f) will left align.
|
||||
Optional precision (%.1f) will override the input determined precision.
|
||||
|
||||
# Help messages
|
||||
numfmt-help-delimiter = use X instead of whitespace for field delimiter
|
||||
numfmt-help-field = replace the numbers in these input fields; see FIELDS below
|
||||
numfmt-help-format = use printf style floating-point FORMAT; see FORMAT below for details
|
||||
numfmt-help-from = auto-scale input numbers to UNITs; see UNIT below
|
||||
numfmt-help-from-unit = specify the input unit size
|
||||
numfmt-help-to = auto-scale output numbers to UNITs; see UNIT below
|
||||
numfmt-help-to-unit = the output unit size
|
||||
numfmt-help-padding = pad the output to N characters; positive N will right-align; negative N will left-align; padding is ignored if the output is wider than N; the default is to automatically pad if a whitespace is found
|
||||
numfmt-help-header = print (without converting) the first N header lines; N defaults to 1 if not specified
|
||||
numfmt-help-round = use METHOD for rounding when scaling
|
||||
numfmt-help-suffix = print SUFFIX after each formatted number, and accept inputs optionally ending with SUFFIX
|
||||
numfmt-help-invalid = set the failure mode for invalid input
|
||||
numfmt-help-zero-terminated = line delimiter is NUL, not newline
|
||||
|
||||
# Error messages
|
||||
numfmt-error-unsupported-unit = Unsupported unit is specified
|
||||
numfmt-error-invalid-unit-size = invalid unit size: { $size }
|
||||
numfmt-error-invalid-padding = invalid padding value { $value }
|
||||
numfmt-error-invalid-header = invalid header value { $value }
|
||||
numfmt-error-grouping-cannot-be-combined-with-to = grouping cannot be combined with --to
|
||||
numfmt-error-delimiter-must-be-single-character = the delimiter must be a single character
|
||||
numfmt-error-invalid-number-empty = invalid number: ''
|
||||
numfmt-error-invalid-suffix = invalid suffix in input: { $input }
|
||||
numfmt-error-invalid-number = invalid number: { $input }
|
||||
numfmt-error-missing-i-suffix = missing 'i' suffix in input: '{ $number }{ $suffix }' (e.g Ki/Mi/Gi)
|
||||
numfmt-error-rejecting-suffix = rejecting suffix in input: '{ $number }{ $suffix }' (consider using --from)
|
||||
numfmt-error-suffix-unsupported-for-unit = This suffix is unsupported for specified unit
|
||||
numfmt-error-unit-auto-not-supported-with-to = Unit 'auto' isn't supported with --to options
|
||||
numfmt-error-number-too-big = Number is too big and unsupported
|
||||
numfmt-error-format-no-percent = format '{ $format }' has no % directive
|
||||
numfmt-error-format-ends-in-percent = format '{ $format }' ends in %
|
||||
numfmt-error-invalid-format-directive = invalid format '{ $format }', directive must be %[0]['][-][N][.][N]f
|
||||
numfmt-error-invalid-format-width-overflow = invalid format '{ $format }' (width overflow)
|
||||
numfmt-error-invalid-precision = invalid precision in format '{ $format }'
|
||||
numfmt-error-format-too-many-percent = format '{ $format }' has too many % directives
|
||||
numfmt-error-unknown-invalid-mode = Unknown invalid mode: { $mode }
|
||||
|
|
74
src/uu/numfmt/locales/fr-FR.ftl
Normal file
74
src/uu/numfmt/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,74 @@
|
|||
numfmt-about = Convertir les nombres vers/depuis des chaînes lisibles par l'homme
|
||||
numfmt-usage = numfmt [OPTION]... [NOMBRE]...
|
||||
numfmt-after-help = Options d'UNITÉ :
|
||||
|
||||
- none : aucune mise à l'échelle automatique n'est effectuée ; les suffixes déclencheront une erreur
|
||||
- auto : accepter un suffixe optionnel d'une/deux lettres :
|
||||
|
||||
1K = 1000, 1Ki = 1024, 1M = 1000000, 1Mi = 1048576,
|
||||
|
||||
- si : accepter un suffixe optionnel d'une lettre :
|
||||
|
||||
1K = 1000, 1M = 1000000, ...
|
||||
|
||||
- iec : accepter un suffixe optionnel d'une lettre :
|
||||
|
||||
1K = 1024, 1M = 1048576, ...
|
||||
|
||||
- iec-i : accepter un suffixe optionnel de deux lettres :
|
||||
|
||||
1Ki = 1024, 1Mi = 1048576, ...
|
||||
|
||||
- FIELDS supporte les plages de champs de style cut(1) :
|
||||
|
||||
N N-ième champ, compté à partir de 1
|
||||
N- du N-ième champ jusqu'à la fin de la ligne
|
||||
N-M du N-ième au M-ième champ (inclus)
|
||||
-M du premier au M-ième champ (inclus)
|
||||
- tous les champs
|
||||
|
||||
Plusieurs champs/plages peuvent être séparés par des virgules
|
||||
|
||||
FORMAT doit être adapté pour imprimer un argument à virgule flottante %f.
|
||||
Une guillemet optionnelle (%'f) activera --grouping (si supporté par la locale actuelle).
|
||||
Une valeur de largeur optionnelle (%10f) remplira la sortie. Un zéro optionnel (%010f)
|
||||
remplira le nombre de zéros. Des valeurs négatives optionnelles (%-10f) aligneront à gauche.
|
||||
Une précision optionnelle (%.1f) remplacera la précision déterminée par l'entrée.
|
||||
|
||||
# Messages d'aide
|
||||
numfmt-help-delimiter = utiliser X au lieu d'espaces pour le délimiteur de champ
|
||||
numfmt-help-field = remplacer les nombres dans ces champs d'entrée ; voir FIELDS ci-dessous
|
||||
numfmt-help-format = utiliser le FORMAT à virgule flottante de style printf ; voir FORMAT ci-dessous pour les détails
|
||||
numfmt-help-from = mettre automatiquement à l'échelle les nombres d'entrée vers les UNITÉs ; voir UNIT ci-dessous
|
||||
numfmt-help-from-unit = spécifier la taille de l'unité d'entrée
|
||||
numfmt-help-to = mettre automatiquement à l'échelle les nombres de sortie vers les UNITÉs ; voir UNIT ci-dessous
|
||||
numfmt-help-to-unit = la taille de l'unité de sortie
|
||||
numfmt-help-padding = remplir la sortie à N caractères ; N positif alignera à droite ; N négatif alignera à gauche ; le remplissage est ignoré si la sortie est plus large que N ; la valeur par défaut est de remplir automatiquement si un espace est trouvé
|
||||
numfmt-help-header = imprimer (sans convertir) les N premières lignes d'en-tête ; N vaut 1 par défaut si non spécifié
|
||||
numfmt-help-round = utiliser METHOD pour l'arrondi lors de la mise à l'échelle
|
||||
numfmt-help-suffix = imprimer SUFFIX après chaque nombre formaté, et accepter les entrées se terminant optionnellement par SUFFIX
|
||||
numfmt-help-invalid = définir le mode d'échec pour les entrées invalides
|
||||
numfmt-help-zero-terminated = le délimiteur de ligne est NUL, pas retour à la ligne
|
||||
|
||||
# Messages d'erreur
|
||||
numfmt-error-unsupported-unit = Une unité non supportée est spécifiée
|
||||
numfmt-error-invalid-unit-size = taille d'unité invalide : { $size }
|
||||
numfmt-error-invalid-padding = valeur de remplissage invalide { $value }
|
||||
numfmt-error-invalid-header = valeur d'en-tête invalide { $value }
|
||||
numfmt-error-grouping-cannot-be-combined-with-to = le groupement ne peut pas être combiné avec --to
|
||||
numfmt-error-delimiter-must-be-single-character = le délimiteur doit être un seul caractère
|
||||
numfmt-error-invalid-number-empty = nombre invalide : ''
|
||||
numfmt-error-invalid-suffix = suffixe invalide dans l'entrée : { $input }
|
||||
numfmt-error-invalid-number = nombre invalide : { $input }
|
||||
numfmt-error-missing-i-suffix = suffixe 'i' manquant dans l'entrée : '{ $number }{ $suffix }' (par ex. Ki/Mi/Gi)
|
||||
numfmt-error-rejecting-suffix = rejet du suffixe dans l'entrée : '{ $number }{ $suffix }' (considérez utiliser --from)
|
||||
numfmt-error-suffix-unsupported-for-unit = Ce suffixe n'est pas supporté pour l'unité spécifiée
|
||||
numfmt-error-unit-auto-not-supported-with-to = L'unité 'auto' n'est pas supportée avec les options --to
|
||||
numfmt-error-number-too-big = Le nombre est trop grand et non supporté
|
||||
numfmt-error-format-no-percent = le format '{ $format }' n'a pas de directive %
|
||||
numfmt-error-format-ends-in-percent = le format '{ $format }' se termine par %
|
||||
numfmt-error-invalid-format-directive = format invalide '{ $format }', la directive doit être %[0]['][-][N][.][N]f
|
||||
numfmt-error-invalid-format-width-overflow = format invalide '{ $format }' (débordement de largeur)
|
||||
numfmt-error-invalid-precision = précision invalide dans le format '{ $format }'
|
||||
numfmt-error-format-too-many-percent = le format '{ $format }' a trop de directives %
|
||||
numfmt-error-unknown-invalid-mode = Mode invalide inconnu : { $mode }
|
|
@ -3,7 +3,9 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
// spell-checker:ignore powf
|
||||
use std::collections::HashMap;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
use crate::options::{NumfmtOptions, RoundMethod, TransformOptions};
|
||||
use crate::units::{DisplayableSuffix, IEC_BASES, RawSuffix, Result, SI_BASES, Suffix, Unit};
|
||||
|
@ -63,7 +65,7 @@ impl<'a> Iterator for WhitespaceSplitter<'a> {
|
|||
|
||||
fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
|
||||
if s.is_empty() {
|
||||
return Err("invalid number: ''".to_string());
|
||||
return Err(get_message("numfmt-error-invalid-number-empty"));
|
||||
}
|
||||
|
||||
let with_i = s.ends_with('i');
|
||||
|
@ -81,7 +83,12 @@ fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
|
|||
Some('Z') => Some((RawSuffix::Z, with_i)),
|
||||
Some('Y') => Some((RawSuffix::Y, with_i)),
|
||||
Some('0'..='9') if !with_i => None,
|
||||
_ => return Err(format!("invalid suffix in input: {}", s.quote())),
|
||||
_ => {
|
||||
return Err(get_message_with_args(
|
||||
"numfmt-error-invalid-suffix",
|
||||
HashMap::from([("input".to_string(), s.quote().to_string())]),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let suffix_len = match suffix {
|
||||
|
@ -90,9 +97,12 @@ fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
|
|||
Some((_, true)) => 2,
|
||||
};
|
||||
|
||||
let number = s[..s.len() - suffix_len]
|
||||
.parse::<f64>()
|
||||
.map_err(|_| format!("invalid number: {}", s.quote()))?;
|
||||
let number = s[..s.len() - suffix_len].parse::<f64>().map_err(|_| {
|
||||
get_message_with_args(
|
||||
"numfmt-error-invalid-number",
|
||||
HashMap::from([("input".to_string(), s.quote().to_string())]),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok((number, suffix))
|
||||
}
|
||||
|
@ -132,15 +142,25 @@ fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
|
|||
RawSuffix::Z => Ok(i * IEC_BASES[7]),
|
||||
RawSuffix::Y => Ok(i * IEC_BASES[8]),
|
||||
},
|
||||
(Some((raw_suffix, false)), &Unit::Iec(true)) => Err(format!(
|
||||
"missing 'i' suffix in input: '{i}{raw_suffix:?}' (e.g Ki/Mi/Gi)"
|
||||
(Some((raw_suffix, false)), &Unit::Iec(true)) => Err(get_message_with_args(
|
||||
"numfmt-error-missing-i-suffix",
|
||||
HashMap::from([
|
||||
("number".to_string(), i.to_string()),
|
||||
("suffix".to_string(), format!("{raw_suffix:?}")),
|
||||
]),
|
||||
)),
|
||||
(Some((raw_suffix, with_i)), &Unit::None) => Err(format!(
|
||||
"rejecting suffix in input: '{i}{raw_suffix:?}{}' (consider using --from)",
|
||||
if with_i { "i" } else { "" }
|
||||
(Some((raw_suffix, with_i)), &Unit::None) => Err(get_message_with_args(
|
||||
"numfmt-error-rejecting-suffix",
|
||||
HashMap::from([
|
||||
("number".to_string(), i.to_string()),
|
||||
(
|
||||
"suffix".to_string(),
|
||||
format!("{raw_suffix:?}{}", if with_i { "i" } else { "" }),
|
||||
),
|
||||
]),
|
||||
)),
|
||||
(None, _) => Ok(i),
|
||||
(_, _) => Err("This suffix is unsupported for specified unit".to_owned()),
|
||||
(_, _) => Err(get_message("numfmt-error-suffix-unsupported-for-unit")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,7 +238,7 @@ fn consider_suffix(
|
|||
let (bases, with_i) = match *u {
|
||||
Unit::Si => (&SI_BASES, false),
|
||||
Unit::Iec(with_i) => (&IEC_BASES, with_i),
|
||||
Unit::Auto => return Err("Unit 'auto' isn't supported with --to options".to_owned()),
|
||||
Unit::Auto => return Err(get_message("numfmt-error-unit-auto-not-supported-with-to")),
|
||||
Unit::None => return Ok((n, None)),
|
||||
};
|
||||
|
||||
|
@ -232,7 +252,7 @@ fn consider_suffix(
|
|||
_ if abs_n < bases[7] => 6,
|
||||
_ if abs_n < bases[8] => 7,
|
||||
_ if abs_n < bases[9] => 8,
|
||||
_ => return Err("Number is too big and unsupported".to_string()),
|
||||
_ => return Err(get_message("numfmt-error-number-too-big")),
|
||||
};
|
||||
|
||||
let v = if precision > 0 {
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::format::format_and_print;
|
|||
use crate::options::*;
|
||||
use crate::units::{Result, Unit};
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command, parser::ValueSource};
|
||||
use std::collections::HashMap;
|
||||
use std::io::{BufRead, Error, Write};
|
||||
use std::result::Result as StdResult;
|
||||
use std::str::FromStr;
|
||||
|
@ -15,7 +16,7 @@ use std::str::FromStr;
|
|||
use units::{IEC_BASES, SI_BASES};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::UResult;
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
use uucore::parser::shortcut_value_parser::ShortcutValueParser;
|
||||
use uucore::ranges::Range;
|
||||
use uucore::{format_usage, show, show_error};
|
||||
|
@ -97,7 +98,7 @@ fn parse_unit(s: &str) -> Result<Unit> {
|
|||
"iec" => Ok(Unit::Iec(false)),
|
||||
"iec-i" => Ok(Unit::Iec(true)),
|
||||
"none" => Ok(Unit::None),
|
||||
_ => Err("Unsupported unit is specified".to_owned()),
|
||||
_ => Err(get_message("numfmt-error-unsupported-unit")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,7 +120,10 @@ fn parse_unit_size(s: &str) -> Result<usize> {
|
|||
}
|
||||
}
|
||||
|
||||
Err(format!("invalid unit size: {}", s.quote()))
|
||||
Err(get_message_with_args(
|
||||
"numfmt-error-invalid-unit-size",
|
||||
HashMap::from([("size".to_string(), s.quote().to_string())]),
|
||||
))
|
||||
}
|
||||
|
||||
// Parses a suffix of a unit size and returns the corresponding multiplier. For example,
|
||||
|
@ -170,7 +174,12 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
|
|||
0 => Err(s),
|
||||
_ => Ok(n),
|
||||
})
|
||||
.map_err(|s| format!("invalid padding value {}", s.quote())),
|
||||
.map_err(|s| {
|
||||
get_message_with_args(
|
||||
"numfmt-error-invalid-padding",
|
||||
HashMap::from([("value".to_string(), s.quote().to_string())]),
|
||||
)
|
||||
}),
|
||||
None => Ok(0),
|
||||
}?;
|
||||
|
||||
|
@ -184,7 +193,12 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
|
|||
0 => Err(value),
|
||||
_ => Ok(n),
|
||||
})
|
||||
.map_err(|value| format!("invalid header value {}", value.quote()))
|
||||
.map_err(|value| {
|
||||
get_message_with_args(
|
||||
"numfmt-error-invalid-header",
|
||||
HashMap::from([("value".to_string(), value.quote().to_string())]),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
Ok(0)
|
||||
}?;
|
||||
|
@ -206,14 +220,18 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
|
|||
};
|
||||
|
||||
if format.grouping && to != Unit::None {
|
||||
return Err("grouping cannot be combined with --to".to_string());
|
||||
return Err(get_message(
|
||||
"numfmt-error-grouping-cannot-be-combined-with-to",
|
||||
));
|
||||
}
|
||||
|
||||
let delimiter = args.get_one::<String>(DELIMITER).map_or(Ok(None), |arg| {
|
||||
if arg.len() == 1 {
|
||||
Ok(Some(arg.to_string()))
|
||||
} else {
|
||||
Err("the delimiter must be a single character".to_string())
|
||||
Err(get_message(
|
||||
"numfmt-error-delimiter-must-be-single-character",
|
||||
))
|
||||
}
|
||||
})?;
|
||||
|
||||
|
@ -284,12 +302,12 @@ pub fn uu_app() -> Command {
|
|||
.short('d')
|
||||
.long(DELIMITER)
|
||||
.value_name("X")
|
||||
.help("use X instead of whitespace for field delimiter"),
|
||||
.help(get_message("numfmt-help-delimiter")),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FIELD)
|
||||
.long(FIELD)
|
||||
.help("replace the numbers in these input fields; see FIELDS below")
|
||||
.help(get_message("numfmt-help-field"))
|
||||
.value_name("FIELDS")
|
||||
.allow_hyphen_values(true)
|
||||
.default_value(FIELD_DEFAULT),
|
||||
|
@ -297,56 +315,48 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(FORMAT)
|
||||
.long(FORMAT)
|
||||
.help("use printf style floating-point FORMAT; see FORMAT below for details")
|
||||
.help(get_message("numfmt-help-format"))
|
||||
.value_name("FORMAT")
|
||||
.allow_hyphen_values(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FROM)
|
||||
.long(FROM)
|
||||
.help("auto-scale input numbers to UNITs; see UNIT below")
|
||||
.help(get_message("numfmt-help-from"))
|
||||
.value_name("UNIT")
|
||||
.default_value(FROM_DEFAULT),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FROM_UNIT)
|
||||
.long(FROM_UNIT)
|
||||
.help("specify the input unit size")
|
||||
.help(get_message("numfmt-help-from-unit"))
|
||||
.value_name("N")
|
||||
.default_value(FROM_UNIT_DEFAULT),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(TO)
|
||||
.long(TO)
|
||||
.help("auto-scale output numbers to UNITs; see UNIT below")
|
||||
.help(get_message("numfmt-help-to"))
|
||||
.value_name("UNIT")
|
||||
.default_value(TO_DEFAULT),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(TO_UNIT)
|
||||
.long(TO_UNIT)
|
||||
.help("the output unit size")
|
||||
.help(get_message("numfmt-help-to-unit"))
|
||||
.value_name("N")
|
||||
.default_value(TO_UNIT_DEFAULT),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(PADDING)
|
||||
.long(PADDING)
|
||||
.help(
|
||||
"pad the output to N characters; positive N will \
|
||||
right-align; negative N will left-align; padding is \
|
||||
ignored if the output is wider than N; the default is \
|
||||
to automatically pad if a whitespace is found",
|
||||
)
|
||||
.help(get_message("numfmt-help-padding"))
|
||||
.value_name("N"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(HEADER)
|
||||
.long(HEADER)
|
||||
.help(
|
||||
"print (without converting) the first N header lines; \
|
||||
N defaults to 1 if not specified",
|
||||
)
|
||||
.help(get_message("numfmt-help-header"))
|
||||
.num_args(..=1)
|
||||
.value_name("N")
|
||||
.default_missing_value(HEADER_DEFAULT)
|
||||
|
@ -355,7 +365,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(ROUND)
|
||||
.long(ROUND)
|
||||
.help("use METHOD for rounding when scaling")
|
||||
.help(get_message("numfmt-help-round"))
|
||||
.value_name("METHOD")
|
||||
.default_value("from-zero")
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
|
@ -369,16 +379,13 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(SUFFIX)
|
||||
.long(SUFFIX)
|
||||
.help(
|
||||
"print SUFFIX after each formatted number, and accept \
|
||||
inputs optionally ending with SUFFIX",
|
||||
)
|
||||
.help(get_message("numfmt-help-suffix"))
|
||||
.value_name("SUFFIX"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(INVALID)
|
||||
.long(INVALID)
|
||||
.help("set the failure mode for invalid input")
|
||||
.help(get_message("numfmt-help-invalid"))
|
||||
.default_value("abort")
|
||||
.value_parser(["abort", "fail", "warn", "ignore"])
|
||||
.value_name("INVALID"),
|
||||
|
@ -387,7 +394,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(ZERO_TERMINATED)
|
||||
.long(ZERO_TERMINATED)
|
||||
.short('z')
|
||||
.help("line delimiter is NUL, not newline")
|
||||
.help(get_message("numfmt-help-zero-terminated"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(Arg::new(NUMBER).hide(true).action(ArgAction::Append))
|
||||
|
@ -465,9 +472,9 @@ mod tests {
|
|||
let result_display = format!("{result}");
|
||||
assert_eq!(
|
||||
result_debug,
|
||||
"FormattingError(\"invalid suffix in input: 'hello'\")"
|
||||
"FormattingError(\"numfmt-error-invalid-suffix\")"
|
||||
);
|
||||
assert_eq!(result_display, "invalid suffix in input: 'hello'");
|
||||
assert_eq!(result_display, "numfmt-error-invalid-suffix");
|
||||
assert_eq!(result.code(), 2);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::units::Unit;
|
||||
use uucore::locale::get_message_with_args;
|
||||
use uucore::ranges::Range;
|
||||
|
||||
pub const DELIMITER: &str = "delimiter";
|
||||
|
@ -145,9 +147,15 @@ impl FromStr for FormatOptions {
|
|||
|
||||
if iter.peek().is_none() {
|
||||
return if options.prefix == s {
|
||||
Err(format!("format '{s}' has no % directive"))
|
||||
Err(get_message_with_args(
|
||||
"numfmt-error-format-no-percent",
|
||||
HashMap::from([("format".to_string(), s.to_string())]),
|
||||
))
|
||||
} else {
|
||||
Err(format!("format '{s}' ends in %"))
|
||||
Err(get_message_with_args(
|
||||
"numfmt-error-format-ends-in-percent",
|
||||
HashMap::from([("format".to_string(), s.to_string())]),
|
||||
))
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -167,8 +175,9 @@ impl FromStr for FormatOptions {
|
|||
match iter.peek() {
|
||||
Some(c) if c.is_ascii_digit() => padding.push('-'),
|
||||
_ => {
|
||||
return Err(format!(
|
||||
"invalid format '{s}', directive must be %[0]['][-][N][.][N]f"
|
||||
return Err(get_message_with_args(
|
||||
"numfmt-error-invalid-format-directive",
|
||||
HashMap::from([("format".to_string(), s.to_string())]),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +196,10 @@ impl FromStr for FormatOptions {
|
|||
if let Ok(p) = padding.parse() {
|
||||
options.padding = Some(p);
|
||||
} else {
|
||||
return Err(format!("invalid format '{s}' (width overflow)"));
|
||||
return Err(get_message_with_args(
|
||||
"numfmt-error-invalid-format-width-overflow",
|
||||
HashMap::from([("format".to_string(), s.to_string())]),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +207,10 @@ impl FromStr for FormatOptions {
|
|||
iter.next();
|
||||
|
||||
if matches!(iter.peek(), Some(' ' | '+' | '-')) {
|
||||
return Err(format!("invalid precision in format '{s}'"));
|
||||
return Err(get_message_with_args(
|
||||
"numfmt-error-invalid-precision",
|
||||
HashMap::from([("format".to_string(), s.to_string())]),
|
||||
));
|
||||
}
|
||||
|
||||
while let Some(c) = iter.peek() {
|
||||
|
@ -212,15 +227,19 @@ impl FromStr for FormatOptions {
|
|||
} else if let Ok(p) = precision.parse() {
|
||||
options.precision = Some(p);
|
||||
} else {
|
||||
return Err(format!("invalid precision in format '{s}'"));
|
||||
return Err(get_message_with_args(
|
||||
"numfmt-error-invalid-precision",
|
||||
HashMap::from([("format".to_string(), s.to_string())]),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some('f') = iter.peek() {
|
||||
iter.next();
|
||||
} else {
|
||||
return Err(format!(
|
||||
"invalid format '{s}', directive must be %[0]['][-][N][.][N]f"
|
||||
return Err(get_message_with_args(
|
||||
"numfmt-error-invalid-format-directive",
|
||||
HashMap::from([("format".to_string(), s.to_string())]),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -235,7 +254,10 @@ impl FromStr for FormatOptions {
|
|||
}
|
||||
iter.next();
|
||||
} else {
|
||||
return Err(format!("format '{s}' has too many % directives"));
|
||||
return Err(get_message_with_args(
|
||||
"numfmt-error-format-too-many-percent",
|
||||
HashMap::from([("format".to_string(), s.to_string())]),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,7 +274,10 @@ impl FromStr for InvalidModes {
|
|||
"fail" => Ok(Self::Fail),
|
||||
"warn" => Ok(Self::Warn),
|
||||
"ignore" => Ok(Self::Ignore),
|
||||
unknown => Err(format!("Unknown invalid mode: {unknown}")),
|
||||
unknown => Err(get_message_with_args(
|
||||
"numfmt-error-unknown-invalid-mode",
|
||||
HashMap::from([("mode".to_string(), unknown.to_string())]),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue