From 625dec0be15b8fc884f43f69b8fc860d8b19e361 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 17 Jun 2025 21:50:11 +0200 Subject: [PATCH 1/2] l10n: port env for translation + add french --- src/uu/env/locales/en-US.ftl | 40 +++++++ src/uu/env/locales/fr-FR.ftl | 43 +++++++ src/uu/env/src/env.rs | 224 ++++++++++++++++++++++++----------- 3 files changed, 240 insertions(+), 67 deletions(-) create mode 100644 src/uu/env/locales/fr-FR.ftl diff --git a/src/uu/env/locales/en-US.ftl b/src/uu/env/locales/en-US.ftl index 4204cb2e4..dd7cf2176 100644 --- a/src/uu/env/locales/en-US.ftl +++ b/src/uu/env/locales/en-US.ftl @@ -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 } diff --git a/src/uu/env/locales/fr-FR.ftl b/src/uu/env/locales/fr-FR.ftl new file mode 100644 index 000000000..cb422a35a --- /dev/null +++ b/src/uu/env/locales/fr-FR.ftl @@ -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 } diff --git a/src/uu/env/src/env.rs b/src/uu/env/src/env.rs index 7bb877b72..df3aabf40 100644 --- a/src/uu/env/src/env.rs +++ b/src/uu/env/src/env.rs @@ -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 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 { 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> 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 { - 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> { { 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> { 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> { 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()), + ]), ), )); } From 576bd6f565a041569b12c5cdc7420aaef352cd23 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 17 Jun 2025 21:50:45 +0200 Subject: [PATCH 2/2] env: adjust to test after the improvement on the error message --- src/uu/env/src/env.rs | 9 ++++--- tests/by-util/test_env.rs | 32 +++++++++++------------ util/gnu-patches/tests_env_env-S.pl.patch | 30 +++++++++++++++------ 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/uu/env/src/env.rs b/src/uu/env/src/env.rs index df3aabf40..d5a7c8659 100644 --- a/src/uu/env/src/env.rs +++ b/src/uu/env/src/env.rs @@ -917,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() { @@ -951,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 @@ -964,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 @@ -982,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 diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index c52202ec2..a4319b71f 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -522,7 +522,7 @@ fn test_split_string_into_args_s_escaped_c_not_allowed() { let out = scene.ucmd().args(&[r#"-S"\c""#]).fails().stderr_move_str(); assert_eq!( out, - "env: '\\c' must not appear in double-quoted -S string\n" + "env: '\\c' must not appear in double-quoted -S string at position 2\n" ); } @@ -608,91 +608,91 @@ fn test_env_parsing_errors() { .arg("-S\\|echo hallo") // no quotes, invalid escape sequence | .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\|' in -S\n"); + .stderr_is("env: invalid sequence '\\|' in -S at position 1\n"); ts.ucmd() .arg("-S\\a") // no quotes, invalid escape sequence a .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\a' in -S\n"); + .stderr_is("env: invalid sequence '\\a' in -S at position 1\n"); ts.ucmd() .arg("-S\"\\a\"") // double quotes, invalid escape sequence a .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\a' in -S\n"); + .stderr_is("env: invalid sequence '\\a' in -S at position 2\n"); ts.ucmd() .arg(r#"-S"\a""#) // same as before, just using r#""# .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\a' in -S\n"); + .stderr_is("env: invalid sequence '\\a' in -S at position 2\n"); ts.ucmd() .arg("-S'\\a'") // single quotes, invalid escape sequence a .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\a' in -S\n"); + .stderr_is("env: invalid sequence '\\a' in -S at position 2\n"); ts.ucmd() .arg(r"-S\|\&\;") // no quotes, invalid escape sequence | .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\|' in -S\n"); + .stderr_is("env: invalid sequence '\\|' in -S at position 1\n"); ts.ucmd() .arg(r"-S\<\&\;") // no quotes, invalid escape sequence < .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\<' in -S\n"); + .stderr_is("env: invalid sequence '\\<' in -S at position 1\n"); ts.ucmd() .arg(r"-S\>\&\;") // no quotes, invalid escape sequence > .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\>' in -S\n"); + .stderr_is("env: invalid sequence '\\>' in -S at position 1\n"); ts.ucmd() .arg(r"-S\`\&\;") // no quotes, invalid escape sequence ` .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\`' in -S\n"); + .stderr_is("env: invalid sequence '\\`' in -S at position 1\n"); ts.ucmd() .arg(r#"-S"\`\&\;""#) // double quotes, invalid escape sequence ` .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\`' in -S\n"); + .stderr_is("env: invalid sequence '\\`' in -S at position 2\n"); ts.ucmd() .arg(r"-S'\`\&\;'") // single quotes, invalid escape sequence ` .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\`' in -S\n"); + .stderr_is("env: invalid sequence '\\`' in -S at position 2\n"); ts.ucmd() .arg(r"-S\`") // ` escaped without quotes .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\`' in -S\n"); + .stderr_is("env: invalid sequence '\\`' in -S at position 1\n"); ts.ucmd() .arg(r#"-S"\`""#) // ` escaped in double quotes .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\`' in -S\n"); + .stderr_is("env: invalid sequence '\\`' in -S at position 2\n"); ts.ucmd() .arg(r"-S'\`'") // ` escaped in single quotes .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\`' in -S\n"); + .stderr_is("env: invalid sequence '\\`' in -S at position 2\n"); ts.ucmd() .args(&[r"-S\🦉"]) // ` escaped in single quotes .fails_with_code(125) .no_stdout() - .stderr_is("env: invalid sequence '\\\u{FFFD}' in -S\n"); // gnu doesn't show the owl. Instead a invalid unicode ? + .stderr_is("env: invalid sequence '\\\u{FFFD}' in -S at position 1\n"); // gnu doesn't show the owl. Instead a invalid unicode ? } #[test] diff --git a/util/gnu-patches/tests_env_env-S.pl.patch b/util/gnu-patches/tests_env_env-S.pl.patch index 1ea860fa0..b3c5d34d1 100644 --- a/util/gnu-patches/tests_env_env-S.pl.patch +++ b/util/gnu-patches/tests_env_env-S.pl.patch @@ -2,27 +2,41 @@ Index: gnu/tests/env/env-S.pl =================================================================== --- gnu.orig/tests/env/env-S.pl +++ gnu/tests/env/env-S.pl -@@ -212,27 +212,28 @@ my @Tests = - {ERR=>"$prog: no terminating quote in -S string\n"}], +@@ -200,36 +200,37 @@ my @Tests = + + # Test Error Conditions + ['err1', q[-S'"\\c"'], {EXIT=>125}, +- {ERR=>"$prog: '\\c' must not appear in double-quoted -S string\n"}], ++ {ERR=>"$prog: '\\c' must not appear in double-quoted -S string at position 2\n"}], + ['err2', q[-S'A=B\\'], {EXIT=>125}, +- {ERR=>"$prog: invalid backslash at end of string in -S\n"}], ++ {ERR=>"$prog: invalid backslash at end of string in -S at position 4 in context Unquoted\n"}], + ['err3', q[-S'"A=B\\"'], {EXIT=>125}, +- {ERR=>"$prog: no terminating quote in -S string\n"}], ++ {ERR=>"$prog: no terminating quote in -S string at position 6 for quote '\"'\n"}], + ['err4', q[-S"'A=B\\\\'"], {EXIT=>125}, +- {ERR=>"$prog: no terminating quote in -S string\n"}], ++ {ERR=>"$prog: no terminating quote in -S string at position 6 for quote '''\n"}], ['err5', q[-S'A=B\\q'], {EXIT=>125}, - {ERR=>"$prog: invalid sequence '\\q' in -S\n"}], +- {ERR=>"$prog: invalid sequence '\\q' in -S\n"}], - ['err6', q[-S'A=$B'], {EXIT=>125}, - {ERR=>"$prog: only \${VARNAME} expansion is supported, error at: \$B\n"}], ++ {ERR=>"$prog: invalid sequence '\\q' in -S at position 4\n"}], + ['err6', q[-S'A=$B echo hello'], {EXIT=>0}, + {OUT=>"hello"}], ['err7', q[-S'A=${B'], {EXIT=>125}, - {ERR=>"$prog: only \${VARNAME} expansion is supported, " . - "error at: \${B\n"}], -+ {ERR=>"$prog" . qq[: variable name issue (at 5): Missing closing brace\n]}], ++ {ERR=>"$prog" . qq[: variable name issue (at 5): Missing closing brace at position 5\n]}], ['err8', q[-S'A=${B%B}'], {EXIT=>125}, - {ERR=>"$prog: only \${VARNAME} expansion is supported, " . - "error at: \${B%B}\n"}], -+ {ERR=>"$prog" . qq[: variable name issue (at 5): Unexpected character: '%', expected a closing brace ('}') or colon (':')\n]}], ++ {ERR=>"$prog" . qq[: variable name issue (at 5): Unexpected character: '%', expected a closing brace ('}') or colon (':') at position 5\n]}], ['err9', q[-S'A=${9B}'], {EXIT=>125}, - {ERR=>"$prog: only \${VARNAME} expansion is supported, " . - "error at: \${9B}\n"}], -+ {ERR=>"$prog" . qq[: variable name issue (at 4): Unexpected character: '9', expected variable name must not start with 0..9\n]}], - ++ {ERR=>"$prog" . qq[: variable name issue (at 4): Unexpected character: '9', expected variable name must not start with 0..9 at position 4\n]}], + # Test incorrect shebang usage (extraneous whitespace). ['err_sp2', q['-v -S cat -n'], {EXIT=>125}, - {ERR=>"env: invalid option -- ' '\n" . @@ -42,6 +56,6 @@ Index: gnu/tests/env/env-S.pl + "Usage: $prog [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]\n\n" . + "For more information, try '--help'.\n" . + "$prog: use -[v]S to pass options in shebang lines\n"}], - + # Also diagnose incorrect shebang usage when failing to exec. # This typically happens with: