Skip to content

Commit 8cf3dea

Browse files
committed
Fix argument parsing for volta run to properly handle flags
Clap's parsing for variable-length argument lists has precedence rules for what happens when a potential vararg overlaps with a known flag value (see https://docs.rs/clap/latest/clap/struct.Arg.html#method.allow_hyphen_values): 1. If we are already in a list of variable args, the args take precedence and any potential flags are ignored (flags are treated as part of the vararg) 2. If we are _not_ already in a list of variable args, then known flags take precedence and are parsed as such, rather than starting the vararg list As a result of this precedence, with `volta run` set up to have `args` be separate from `command`, we could run into parsing issues with commands that have flags that overlap with Volta's. For example: ``` volta run node -h ``` When parsing this, Clap would see `node` as the `command`, and then it would parse `-h` as _Volta's_ `-h` (help) flag and print Volta's help. This is because the variable-length `args` hadn't started yet (we hadn't run into any unknown positional arguments), so Clap treated `-h` as a known flag with higher precedence. This is exactly the opposite of what we actually want for `volta run` Instead, what we want is that everything after the `command` argument should be treated as part of the arguments to the command; regardless of whether the flag overlaps with Volta's flags. To achieve that, we combine `command` and `args` into a _single_ vararg, so that by virtue of having a command in the first place, the vararg has started parsing and Clap will treat any flags as more argument values, rather than as flags.
1 parent bd1b4ce commit 8cf3dea

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

src/command/run.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ pub(crate) struct Run {
4444
#[arg(long = "env", value_name = "NAME=value", num_args = 1)]
4545
envs: Vec<String>,
4646

47-
/// The command to run
48-
command: OsString,
49-
50-
/// Arguments to pass to the command
51-
#[arg(allow_hyphen_values = true, trailing_var_arg = true)]
52-
args: Vec<OsString>,
47+
/// The command to run, along with any arguments
48+
#[arg(
49+
allow_hyphen_values = true,
50+
trailing_var_arg = true,
51+
value_name = "COMMAND",
52+
required = true
53+
)]
54+
command_and_args: Vec<OsString>,
5355
}
5456

5557
impl Command for Run {
@@ -59,7 +61,13 @@ impl Command for Run {
5961
let envs = self.parse_envs();
6062
let platform = self.parse_platform(session)?;
6163

62-
match execute_tool(&self.command, &self.args, &envs, platform, session).into_result() {
64+
// Safety: At least one value is required for `command_and_args`, so there must be at
65+
// least one value in the list. If no value is provided, Clap will show a "required
66+
// argument missing" message and this function won't be called.
67+
let command = &self.command_and_args[0];
68+
let args = &self.command_and_args[1..];
69+
70+
match execute_tool(command, args, &envs, platform, session).into_result() {
6371
Ok(()) => {
6472
session.add_event_end(ActivityKind::Run, ExitCode::Success);
6573
Ok(ExitCode::Success)

0 commit comments

Comments
 (0)