mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
env: ignore flags after the command or -- argument
This commit is contained in:
parent
d68e288602
commit
814e82ea4e
2 changed files with 120 additions and 22 deletions
87
src/uu/env/src/env.rs
vendored
87
src/uu/env/src/env.rs
vendored
|
@ -78,6 +78,18 @@ const ABOUT: &str = help_about!("env.md");
|
||||||
const USAGE: &str = help_usage!("env.md");
|
const USAGE: &str = help_usage!("env.md");
|
||||||
const AFTER_HELP: &str = help_section!("after help", "env.md");
|
const AFTER_HELP: &str = help_section!("after help", "env.md");
|
||||||
|
|
||||||
|
mod options {
|
||||||
|
pub const IGNORE_ENVIRONMENT: &str = "ignore-environment";
|
||||||
|
pub const CHDIR: &str = "chdir";
|
||||||
|
pub const NULL: &str = "null";
|
||||||
|
pub const FILE: &str = "file";
|
||||||
|
pub const UNSET: &str = "unset";
|
||||||
|
pub const DEBUG: &str = "debug";
|
||||||
|
pub const SPLIT_STRING: &str = "split-string";
|
||||||
|
pub const ARGV0: &str = "argv0";
|
||||||
|
pub const IGNORE_SIGNAL: &str = "ignore-signal";
|
||||||
|
}
|
||||||
|
|
||||||
const ERROR_MSG_S_SHEBANG: &str = "use -[v]S to pass options in shebang lines";
|
const ERROR_MSG_S_SHEBANG: &str = "use -[v]S to pass options in shebang lines";
|
||||||
|
|
||||||
struct Options<'a> {
|
struct Options<'a> {
|
||||||
|
@ -216,16 +228,16 @@ pub fn uu_app() -> Command {
|
||||||
.infer_long_args(true)
|
.infer_long_args(true)
|
||||||
.trailing_var_arg(true)
|
.trailing_var_arg(true)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("ignore-environment")
|
Arg::new(options::IGNORE_ENVIRONMENT)
|
||||||
.short('i')
|
.short('i')
|
||||||
.long("ignore-environment")
|
.long(options::IGNORE_ENVIRONMENT)
|
||||||
.help("start with an empty environment")
|
.help("start with an empty environment")
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("chdir")
|
Arg::new(options::CHDIR)
|
||||||
.short('C') // GNU env compatibility
|
.short('C') // GNU env compatibility
|
||||||
.long("chdir")
|
.long(options::CHDIR)
|
||||||
.number_of_values(1)
|
.number_of_values(1)
|
||||||
.value_name("DIR")
|
.value_name("DIR")
|
||||||
.value_parser(ValueParser::os_string())
|
.value_parser(ValueParser::os_string())
|
||||||
|
@ -233,9 +245,9 @@ pub fn uu_app() -> Command {
|
||||||
.help("change working directory to DIR"),
|
.help("change working directory to DIR"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("null")
|
Arg::new(options::NULL)
|
||||||
.short('0')
|
.short('0')
|
||||||
.long("null")
|
.long(options::NULL)
|
||||||
.help(
|
.help(
|
||||||
"end each output line with a 0 byte rather than a newline (only \
|
"end each output line with a 0 byte rather than a newline (only \
|
||||||
valid when printing the environment)",
|
valid when printing the environment)",
|
||||||
|
@ -243,9 +255,9 @@ pub fn uu_app() -> Command {
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("file")
|
Arg::new(options::FILE)
|
||||||
.short('f')
|
.short('f')
|
||||||
.long("file")
|
.long(options::FILE)
|
||||||
.value_name("PATH")
|
.value_name("PATH")
|
||||||
.value_hint(clap::ValueHint::FilePath)
|
.value_hint(clap::ValueHint::FilePath)
|
||||||
.value_parser(ValueParser::os_string())
|
.value_parser(ValueParser::os_string())
|
||||||
|
@ -256,34 +268,34 @@ pub fn uu_app() -> Command {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("unset")
|
Arg::new(options::UNSET)
|
||||||
.short('u')
|
.short('u')
|
||||||
.long("unset")
|
.long(options::UNSET)
|
||||||
.value_name("NAME")
|
.value_name("NAME")
|
||||||
.action(ArgAction::Append)
|
.action(ArgAction::Append)
|
||||||
.value_parser(ValueParser::os_string())
|
.value_parser(ValueParser::os_string())
|
||||||
.help("remove variable from the environment"),
|
.help("remove variable from the environment"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("debug")
|
Arg::new(options::DEBUG)
|
||||||
.short('v')
|
.short('v')
|
||||||
.long("debug")
|
.long(options::DEBUG)
|
||||||
.action(ArgAction::Count)
|
.action(ArgAction::Count)
|
||||||
.help("print verbose information for each processing step"),
|
.help("print verbose information for each processing step"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("split-string") // split string handling is implemented directly, not using CLAP. But this entry here is needed for the help information output.
|
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.
|
||||||
.short('S')
|
.short('S')
|
||||||
.long("split-string")
|
.long(options::SPLIT_STRING)
|
||||||
.value_name("S")
|
.value_name("S")
|
||||||
.action(ArgAction::Set)
|
.action(ArgAction::Set)
|
||||||
.value_parser(ValueParser::os_string())
|
.value_parser(ValueParser::os_string())
|
||||||
.help("process and split S into separate arguments; used to pass multiple arguments on shebang lines")
|
.help("process and split S into separate arguments; used to pass multiple arguments on shebang lines")
|
||||||
).arg(
|
).arg(
|
||||||
Arg::new("argv0")
|
Arg::new(options::ARGV0)
|
||||||
.overrides_with("argv0")
|
.overrides_with(options::ARGV0)
|
||||||
.short('a')
|
.short('a')
|
||||||
.long("argv0")
|
.long(options::ARGV0)
|
||||||
.value_name("a")
|
.value_name("a")
|
||||||
.action(ArgAction::Set)
|
.action(ArgAction::Set)
|
||||||
.value_parser(ValueParser::os_string())
|
.value_parser(ValueParser::os_string())
|
||||||
|
@ -296,8 +308,8 @@ pub fn uu_app() -> Command {
|
||||||
.value_parser(ValueParser::os_string())
|
.value_parser(ValueParser::os_string())
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("ignore-signal")
|
Arg::new(options::IGNORE_SIGNAL)
|
||||||
.long("ignore-signal")
|
.long(options::IGNORE_SIGNAL)
|
||||||
.value_name("SIG")
|
.value_name("SIG")
|
||||||
.action(ArgAction::Append)
|
.action(ArgAction::Append)
|
||||||
.value_parser(ValueParser::os_string())
|
.value_parser(ValueParser::os_string())
|
||||||
|
@ -387,7 +399,31 @@ impl EnvAppData {
|
||||||
original_args: &Vec<OsString>,
|
original_args: &Vec<OsString>,
|
||||||
) -> UResult<Vec<OsString>> {
|
) -> UResult<Vec<OsString>> {
|
||||||
let mut all_args: Vec<OsString> = Vec::new();
|
let mut all_args: Vec<OsString> = Vec::new();
|
||||||
for arg in original_args {
|
let mut process_flags = true;
|
||||||
|
let mut expecting_arg = false;
|
||||||
|
// Leave out split-string since it's a special case below
|
||||||
|
let flags_with_args = [
|
||||||
|
options::ARGV0,
|
||||||
|
options::CHDIR,
|
||||||
|
options::FILE,
|
||||||
|
options::IGNORE_SIGNAL,
|
||||||
|
options::UNSET,
|
||||||
|
];
|
||||||
|
let short_flags_with_args = ['a', 'C', 'f', 'u'];
|
||||||
|
for (n, arg) in original_args.iter().enumerate() {
|
||||||
|
let arg_str = arg.to_string_lossy();
|
||||||
|
// Stop processing env flags once we reach the command or -- argument
|
||||||
|
if 0 < n
|
||||||
|
&& !expecting_arg
|
||||||
|
&& (arg == "--" || !(arg_str.starts_with('-') || arg_str.contains('=')))
|
||||||
|
{
|
||||||
|
process_flags = false;
|
||||||
|
}
|
||||||
|
if !process_flags {
|
||||||
|
all_args.push(arg.clone());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
expecting_arg = false;
|
||||||
match arg {
|
match arg {
|
||||||
b if check_and_handle_string_args(b, "--split-string", &mut all_args, None)? => {
|
b if check_and_handle_string_args(b, "--split-string", &mut all_args, None)? => {
|
||||||
self.had_string_argument = true;
|
self.had_string_argument = true;
|
||||||
|
@ -411,8 +447,15 @@ impl EnvAppData {
|
||||||
self.had_string_argument = true;
|
self.had_string_argument = true;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let arg_str = arg.to_string_lossy();
|
if let Some(flag) = arg_str.strip_prefix("--") {
|
||||||
|
if flags_with_args.contains(&flag) {
|
||||||
|
expecting_arg = true;
|
||||||
|
}
|
||||||
|
} else if let Some(flag) = arg_str.strip_prefix("-") {
|
||||||
|
for c in flag.chars() {
|
||||||
|
expecting_arg = short_flags_with_args.contains(&c);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Short unset option (-u) is not allowed to contain '='
|
// Short unset option (-u) is not allowed to contain '='
|
||||||
if arg_str.contains('=')
|
if arg_str.contains('=')
|
||||||
&& arg_str.starts_with("-u")
|
&& arg_str.starts_with("-u")
|
||||||
|
|
|
@ -66,6 +66,61 @@ fn test_invalid_arg() {
|
||||||
new_ucmd!().arg("--definitely-invalid").fails_with_code(125);
|
new_ucmd!().arg("--definitely-invalid").fails_with_code(125);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
fn test_flags_after_command() {
|
||||||
|
new_ucmd!()
|
||||||
|
// This would cause an error if -u=v were processed because it's malformed
|
||||||
|
.args(&["echo", "-u=v"])
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_is("-u=v\n");
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
// Ensure the string isn't split
|
||||||
|
// cSpell:disable
|
||||||
|
.args(&["printf", "%s-%s", "-Sfoo bar"])
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_is("-Sfoo bar-");
|
||||||
|
// cSpell:enable
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
// Ensure -- is recognized
|
||||||
|
.args(&["-i", "--", "-u=v"])
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_is("-u=v\n");
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
// Recognize echo as the command after a flag that takes a value
|
||||||
|
.args(&["-C", "..", "echo", "-u=v"])
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_is("-u=v\n");
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
// Recognize echo as the command after a flag that takes an inline value
|
||||||
|
.args(&["-C..", "echo", "-u=v"])
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_is("-u=v\n");
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
// Recognize echo as the command after a flag that takes a value after another flag
|
||||||
|
.args(&["-iC", "..", "echo", "-u=v"])
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_is("-u=v\n");
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
// Similar to the last two combined
|
||||||
|
.args(&["-iC..", "echo", "-u=v"])
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_is("-u=v\n");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_env_help() {
|
fn test_env_help() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue