Skip to content

Commit 64f308a

Browse files
authored
Merge pull request #8245 from sylvestre/l10n-chmod-2
l10n: port chmod for translation + add french
2 parents 2b5dfe6 + d8ba6c0 commit 64f308a

File tree

5 files changed

+112
-50
lines changed

5 files changed

+112
-50
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/chmod/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ path = "src/chmod.rs"
2020
[dependencies]
2121
clap = { workspace = true }
2222
libc = { workspace = true }
23+
thiserror = { workspace = true }
2324
uucore = { workspace = true, features = ["entries", "fs", "mode", "perms"] }
2425

2526
[[bin]]

src/uu/chmod/locales/en-US.ftl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,28 @@ chmod-usage = chmod [OPTION]... MODE[,MODE]... FILE...
44
chmod [OPTION]... OCTAL-MODE FILE...
55
chmod [OPTION]... --reference=RFILE FILE...
66
chmod-after-help = Each MODE is of the form [ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+.
7+
chmod-error-cannot-stat = cannot stat attributes of {$file}
8+
chmod-error-dangling-symlink = cannot operate on dangling symlink {$file}
9+
chmod-error-no-such-file = cannot access {$file}: No such file or directory
10+
chmod-error-preserve-root = it is dangerous to operate recursively on {$file}
11+
chmod: use --no-preserve-root to override this failsafe
12+
chmod-error-permission-denied = {$file}: Permission denied
13+
chmod-error-new-permissions = {$file}: new permissions are {$actual}, not {$expected}
14+
chmod-error-missing-operand = missing operand
15+
16+
# Help messages
17+
chmod-help-print-help = Print help information.
18+
chmod-help-changes = like verbose but report only when a change is made
19+
chmod-help-quiet = suppress most error messages
20+
chmod-help-verbose = output a diagnostic for every file processed
21+
chmod-help-no-preserve-root = do not treat '/' specially (the default)
22+
chmod-help-preserve-root = fail to operate recursively on '/'
23+
chmod-help-recursive = change files and directories recursively
24+
chmod-help-reference = use RFILE's mode instead of MODE values
25+
26+
# Verbose messages
27+
chmod-verbose-failed-dangling = failed to change mode of {$file} from 0000 (---------) to 1500 (r-x-----T)
28+
chmod-verbose-neither-changed = neither symbolic link {$file} nor referent has been changed
29+
chmod-verbose-mode-retained = mode of {$file} retained as {$mode_octal} ({$mode_display})
30+
chmod-verbose-failed-change = failed to change mode of file {$file} from {$old_mode} ({$old_mode_display}) to {$new_mode} ({$new_mode_display})
31+
chmod-verbose-mode-changed = mode of {$file} changed from {$old_mode} ({$old_mode_display}) to {$new_mode} ({$new_mode_display})

src/uu/chmod/locales/fr-FR.ftl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
chmod-about = Changer le mode de chaque FICHIER vers MODE.
2+
Avec --reference, changer le mode de chaque FICHIER vers celui de RFICHIER.
3+
chmod-usage = chmod [OPTION]... MODE[,MODE]... FICHIER...
4+
chmod [OPTION]... MODE-OCTAL FICHIER...
5+
chmod [OPTION]... --reference=RFICHIER FICHIER...
6+
chmod-after-help = Chaque MODE est de la forme [ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+.
7+
8+
# Messages d'aide
9+
chmod-help-print-help = Afficher les informations d'aide.
10+
chmod-help-changes = comme verbeux mais rapporter seulement lors d'un changement
11+
chmod-help-quiet = supprimer la plupart des messages d'erreur
12+
chmod-help-verbose = afficher un diagnostic pour chaque fichier traité
13+
chmod-help-no-preserve-root = ne pas traiter '/' spécialement (par défaut)
14+
chmod-help-preserve-root = échouer à opérer récursivement sur '/'
15+
chmod-help-recursive = changer les fichiers et répertoires récursivement
16+
chmod-help-reference = utiliser le mode de RFICHIER au lieu des valeurs de MODE
17+
18+
# Messages d'erreur
19+
chmod-error-cannot-stat = impossible d'obtenir les attributs de {$file}
20+
chmod-error-dangling-symlink = impossible d'opérer sur le lien symbolique pendouillant {$file}
21+
chmod-error-no-such-file = impossible d'accéder à {$file} : Aucun fichier ou dossier de ce type
22+
chmod-error-preserve-root = il est dangereux d'opérer récursivement sur {$file}
23+
chmod: utiliser --no-preserve-root pour outrepasser cette protection
24+
chmod-error-permission-denied = {$file} : Permission refusée
25+
chmod-error-new-permissions = {$file} : les nouvelles permissions sont {$actual}, pas {$expected}
26+
chmod-error-missing-operand = opérande manquant
27+
28+
# Messages verbeux/de statut
29+
chmod-verbose-failed-dangling = échec du changement de mode de {$file} de 0000 (---------) vers 1500 (r-x-----T)
30+
chmod-verbose-neither-changed = ni le lien symbolique {$file} ni la référence n'ont été changés
31+
chmod-verbose-mode-retained = mode de {$file} conservé comme {$mode_octal} ({$mode_display})
32+
chmod-verbose-failed-change = échec du changement de mode du fichier {$file} de {$old_mode} ({$old_mode_display}) vers {$new_mode} ({$new_mode_display})
33+
chmod-verbose-mode-changed = mode de {$file} changé de {$old_mode} ({$old_mode_display}) vers {$new_mode} ({$new_mode_display})

src/uu/chmod/src/chmod.rs

Lines changed: 52 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,40 @@
66
// spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's
77

88
use clap::{Arg, ArgAction, Command};
9+
use std::collections::HashMap;
910
use std::ffi::OsString;
1011
use std::fs;
1112
use std::os::unix::fs::{MetadataExt, PermissionsExt};
1213
use std::path::Path;
14+
use thiserror::Error;
1315
use uucore::display::Quotable;
14-
use uucore::error::{ExitCode, UResult, USimpleError, UUsageError, set_exit_code};
16+
use uucore::error::{ExitCode, UError, UResult, USimpleError, UUsageError, set_exit_code};
1517
use uucore::fs::display_permissions_unix;
1618
use uucore::libc::mode_t;
1719
#[cfg(not(windows))]
1820
use uucore::mode;
1921
use uucore::perms::{TraverseSymlinks, configure_symlink_and_recursion};
2022
use uucore::{format_usage, show, show_error};
2123

22-
use uucore::locale::get_message;
24+
use uucore::locale::{get_message, get_message_with_args};
25+
26+
#[derive(Debug, Error)]
27+
enum ChmodError {
28+
#[error("{}", get_message_with_args("chmod-error-cannot-stat", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
29+
CannotStat(String),
30+
#[error("{}", get_message_with_args("chmod-error-dangling-symlink", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
31+
DanglingSymlink(String),
32+
#[error("{}", get_message_with_args("chmod-error-no-such-file", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
33+
NoSuchFile(String),
34+
#[error("{}", get_message_with_args("chmod-error-preserve-root", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
35+
PreserveRoot(String),
36+
#[error("{}", get_message_with_args("chmod-error-permission-denied", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
37+
PermissionDenied(String),
38+
#[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())])))]
39+
NewPermissions(String, String, String),
40+
}
41+
42+
impl UError for ChmodError {}
2343

2444
mod options {
2545
pub const HELP: &str = "help";
@@ -103,11 +123,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
103123
let fmode = match matches.get_one::<String>(options::REFERENCE) {
104124
Some(fref) => match fs::metadata(fref) {
105125
Ok(meta) => Some(meta.mode() & 0o7777),
106-
Err(err) => {
107-
return Err(USimpleError::new(
108-
1,
109-
format!("cannot stat attributes of {}: {err}", fref.quote()),
110-
));
126+
Err(_) => {
127+
return Err(ChmodError::CannotStat(fref.to_string()).into());
111128
}
112129
},
113130
None => None,
@@ -135,7 +152,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
135152
};
136153

137154
if files.is_empty() {
138-
return Err(UUsageError::new(1, "missing operand".to_string()));
155+
return Err(UUsageError::new(
156+
1,
157+
get_message("chmod-error-missing-operand"),
158+
));
139159
}
140160

141161
let (recursive, dereference, traverse_symlinks) =
@@ -168,55 +188,55 @@ pub fn uu_app() -> Command {
168188
.arg(
169189
Arg::new(options::HELP)
170190
.long(options::HELP)
171-
.help("Print help information.")
191+
.help(get_message("chmod-help-print-help"))
172192
.action(ArgAction::Help),
173193
)
174194
.arg(
175195
Arg::new(options::CHANGES)
176196
.long(options::CHANGES)
177197
.short('c')
178-
.help("like verbose but report only when a change is made")
198+
.help(get_message("chmod-help-changes"))
179199
.action(ArgAction::SetTrue),
180200
)
181201
.arg(
182202
Arg::new(options::QUIET)
183203
.long(options::QUIET)
184204
.visible_alias("silent")
185205
.short('f')
186-
.help("suppress most error messages")
206+
.help(get_message("chmod-help-quiet"))
187207
.action(ArgAction::SetTrue),
188208
)
189209
.arg(
190210
Arg::new(options::VERBOSE)
191211
.long(options::VERBOSE)
192212
.short('v')
193-
.help("output a diagnostic for every file processed")
213+
.help(get_message("chmod-help-verbose"))
194214
.action(ArgAction::SetTrue),
195215
)
196216
.arg(
197217
Arg::new(options::NO_PRESERVE_ROOT)
198218
.long(options::NO_PRESERVE_ROOT)
199-
.help("do not treat '/' specially (the default)")
219+
.help(get_message("chmod-help-no-preserve-root"))
200220
.action(ArgAction::SetTrue),
201221
)
202222
.arg(
203223
Arg::new(options::PRESERVE_ROOT)
204224
.long(options::PRESERVE_ROOT)
205-
.help("fail to operate recursively on '/'")
225+
.help(get_message("chmod-help-preserve-root"))
206226
.action(ArgAction::SetTrue),
207227
)
208228
.arg(
209229
Arg::new(options::RECURSIVE)
210230
.long(options::RECURSIVE)
211231
.short('R')
212-
.help("change files and directories recursively")
232+
.help(get_message("chmod-help-recursive"))
213233
.action(ArgAction::SetTrue),
214234
)
215235
.arg(
216236
Arg::new(options::REFERENCE)
217237
.long("reference")
218238
.value_hint(clap::ValueHint::FilePath)
219-
.help("use RFILE's mode instead of MODE values"),
239+
.help(get_message("chmod-help-reference")),
220240
)
221241
.arg(
222242
Arg::new(options::MODE).required_unless_present(options::REFERENCE),
@@ -265,27 +285,21 @@ impl Chmoder {
265285
}
266286

267287
if !self.quiet {
268-
show!(USimpleError::new(
269-
1,
270-
format!("cannot operate on dangling symlink {}", filename.quote()),
271-
));
288+
show!(ChmodError::DanglingSymlink(filename.to_string()));
272289
set_exit_code(1);
273290
}
274291

275292
if self.verbose {
276293
println!(
277-
"failed to change mode of {} from 0000 (---------) to 1500 (r-x-----T)",
278-
filename.quote()
294+
"{}",
295+
get_message_with_args(
296+
"chmod-verbose-failed-dangling",
297+
HashMap::from([("file".to_string(), filename.quote().to_string())])
298+
)
279299
);
280300
}
281301
} else if !self.quiet {
282-
show!(USimpleError::new(
283-
1,
284-
format!(
285-
"cannot access {}: No such file or directory",
286-
filename.quote()
287-
)
288-
));
302+
show!(ChmodError::NoSuchFile(filename.to_string()));
289303
}
290304
// GNU exits with exit code 1 even if -q or --quiet are passed
291305
// So we set the exit code, because it hasn't been set yet if `self.quiet` is true.
@@ -298,13 +312,7 @@ impl Chmoder {
298312
continue;
299313
}
300314
if self.recursive && self.preserve_root && filename == "/" {
301-
return Err(USimpleError::new(
302-
1,
303-
format!(
304-
"it is dangerous to operate recursively on {}\nchmod: use --no-preserve-root to override this failsafe",
305-
filename.quote()
306-
),
307-
));
315+
return Err(ChmodError::PreserveRoot(filename.to_string()).into());
308316
}
309317
if self.recursive {
310318
r = self.walk_dir(file);
@@ -368,12 +376,9 @@ impl Chmoder {
368376
} else if err.kind() == std::io::ErrorKind::PermissionDenied {
369377
// These two filenames would normally be conditionally
370378
// quoted, but GNU's tests expect them to always be quoted
371-
Err(USimpleError::new(
372-
1,
373-
format!("{}: Permission denied", file.quote()),
374-
))
379+
Err(ChmodError::PermissionDenied(file.to_string_lossy().to_string()).into())
375380
} else {
376-
Err(USimpleError::new(1, format!("{}: {err}", file.quote())))
381+
Err(ChmodError::CannotStat(file.to_string_lossy().to_string()).into())
377382
};
378383
}
379384
};
@@ -420,15 +425,12 @@ impl Chmoder {
420425
self.change_file(fperm, new_mode, file)?;
421426
// 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
422427
if (new_mode & !naively_expected_new_mode) != 0 {
423-
return Err(USimpleError::new(
424-
1,
425-
format!(
426-
"{}: new permissions are {}, not {}",
427-
file.maybe_quote(),
428-
display_permissions_unix(new_mode as mode_t, false),
429-
display_permissions_unix(naively_expected_new_mode as mode_t, false)
430-
),
431-
));
428+
return Err(ChmodError::NewPermissions(
429+
file.to_string_lossy().to_string(),
430+
display_permissions_unix(new_mode as mode_t, false),
431+
display_permissions_unix(naively_expected_new_mode as mode_t, false),
432+
)
433+
.into());
432434
}
433435
}
434436
}

0 commit comments

Comments
 (0)