Add flags to set and clear shell arguments (#551)
Add the `--shell-arg` and `--clear-shell-args` flags, which allow setting and clearing arguments to the shell from the command line. This allows full control over the shell from the command line. Additionally, any shell-related arguments on the command line override `set shell := [...]` in the Justfile, which I think will be the behavior that most people expect.
This commit is contained in:
parent
d2decbfdb8
commit
d0e813cd8b
@ -164,7 +164,7 @@ impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
||||
raw: &str,
|
||||
token: &Token<'a>,
|
||||
) -> RunResult<'a, String> {
|
||||
let mut cmd = self.settings.shell_command(&self.config.shell);
|
||||
let mut cmd = self.settings.shell_command(self.config);
|
||||
|
||||
cmd.arg(raw);
|
||||
|
||||
|
110
src/config.rs
110
src/config.rs
@ -4,6 +4,7 @@ use clap::{App, AppSettings, Arg, ArgGroup, ArgMatches};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
pub(crate) const DEFAULT_SHELL: &str = "sh";
|
||||
pub(crate) const DEFAULT_SHELL_ARG: &str = "-cu";
|
||||
pub(crate) const INIT_JUSTFILE: &str = "default:\n\techo 'Hello, world!'\n";
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@ -15,6 +16,8 @@ pub(crate) struct Config {
|
||||
pub(crate) quiet: bool,
|
||||
pub(crate) search_config: SearchConfig,
|
||||
pub(crate) shell: String,
|
||||
pub(crate) shell_args: Vec<String>,
|
||||
pub(crate) shell_present: bool,
|
||||
pub(crate) subcommand: Subcommand,
|
||||
pub(crate) verbosity: Verbosity,
|
||||
}
|
||||
@ -34,14 +37,16 @@ mod cmd {
|
||||
|
||||
mod arg {
|
||||
pub(crate) const ARGUMENTS: &str = "ARGUMENTS";
|
||||
pub(crate) const CLEAR_SHELL_ARGS: &str = "CLEAR-SHELL-ARGS";
|
||||
pub(crate) const COLOR: &str = "COLOR";
|
||||
pub(crate) const DRY_RUN: &str = "DRY-RUN";
|
||||
pub(crate) const HIGHLIGHT: &str = "HIGHLIGHT";
|
||||
pub(crate) const NO_HIGHLIGHT: &str = "NO-HIGHLIGHT";
|
||||
pub(crate) const JUSTFILE: &str = "JUSTFILE";
|
||||
pub(crate) const NO_HIGHLIGHT: &str = "NO-HIGHLIGHT";
|
||||
pub(crate) const QUIET: &str = "QUIET";
|
||||
pub(crate) const SET: &str = "SET";
|
||||
pub(crate) const SHELL: &str = "SHELL";
|
||||
pub(crate) const SHELL_ARG: &str = "SHELL-ARG";
|
||||
pub(crate) const VERBOSE: &str = "VERBOSE";
|
||||
pub(crate) const WORKING_DIRECTORY: &str = "WORKING-DIRECTORY";
|
||||
|
||||
@ -114,6 +119,23 @@ impl Config {
|
||||
.default_value(DEFAULT_SHELL)
|
||||
.help("Invoke <SHELL> to run recipes"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(arg::SHELL_ARG)
|
||||
.long("shell-arg")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.number_of_values(1)
|
||||
.default_value(DEFAULT_SHELL_ARG)
|
||||
.allow_hyphen_values(true)
|
||||
.overrides_with(arg::CLEAR_SHELL_ARGS)
|
||||
.help("Invoke shell with <SHELL-ARG> as an argument"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(arg::CLEAR_SHELL_ARGS)
|
||||
.long("clear-shell-args")
|
||||
.overrides_with(arg::SHELL_ARG)
|
||||
.help("Clear shell arguments"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(arg::VERBOSE)
|
||||
.short("v")
|
||||
@ -318,16 +340,33 @@ impl Config {
|
||||
}
|
||||
};
|
||||
|
||||
let shell_args = if matches.is_present(arg::CLEAR_SHELL_ARGS) {
|
||||
Vec::new()
|
||||
} else {
|
||||
matches
|
||||
.values_of(arg::SHELL_ARG)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(str::to_owned)
|
||||
.collect()
|
||||
};
|
||||
|
||||
let shell_present = matches.occurrences_of(arg::CLEAR_SHELL_ARGS) > 0
|
||||
|| matches.occurrences_of(arg::SHELL) > 0
|
||||
|| matches.occurrences_of(arg::SHELL_ARG) > 0;
|
||||
|
||||
Ok(Config {
|
||||
dry_run: matches.is_present(arg::DRY_RUN),
|
||||
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
|
||||
quiet: matches.is_present(arg::QUIET),
|
||||
shell: matches.value_of(arg::SHELL).unwrap().to_owned(),
|
||||
search_config,
|
||||
color,
|
||||
invocation_directory,
|
||||
search_config,
|
||||
shell_args,
|
||||
shell_present,
|
||||
subcommand,
|
||||
verbosity,
|
||||
color,
|
||||
})
|
||||
}
|
||||
|
||||
@ -594,6 +633,7 @@ USAGE:
|
||||
just [FLAGS] [OPTIONS] [--] [ARGUMENTS]...
|
||||
|
||||
FLAGS:
|
||||
--clear-shell-args Clear shell arguments
|
||||
--dry-run Print what just would do without doing it
|
||||
--dump Print entire justfile
|
||||
-e, --edit \
|
||||
@ -614,6 +654,8 @@ OPTIONS:
|
||||
-f, --justfile <JUSTFILE> Use <JUSTFILE> as justfile.
|
||||
--set <VARIABLE> <VALUE> Override <VARIABLE> with <VALUE>
|
||||
--shell <SHELL> Invoke <SHELL> to run recipes [default: sh]
|
||||
--shell-arg <SHELL-ARG>... \
|
||||
Invoke shell with <SHELL-ARG> as an argument [default: -cu]
|
||||
-s, --show <RECIPE> Show information about <RECIPE>
|
||||
-d, --working-directory <WORKING-DIRECTORY>
|
||||
Use <WORKING-DIRECTORY> as working directory. --justfile must also be set
|
||||
@ -641,6 +683,8 @@ ARGS:
|
||||
$(quiet: $quiet:expr,)?
|
||||
$(search_config: $search_config:expr,)?
|
||||
$(shell: $shell:expr,)?
|
||||
$(shell_args: $shell_args:expr,)?
|
||||
$(shell_present: $shell_present:expr,)?
|
||||
$(subcommand: $subcommand:expr,)?
|
||||
$(verbosity: $verbosity:expr,)?
|
||||
} => {
|
||||
@ -658,6 +702,8 @@ ARGS:
|
||||
$(quiet: $quiet,)?
|
||||
$(search_config: $search_config,)?
|
||||
$(shell: $shell.to_string(),)?
|
||||
$(shell_args: $shell_args,)?
|
||||
$(shell_present: $shell_present,)?
|
||||
$(subcommand: $subcommand,)?
|
||||
$(verbosity: $verbosity,)?
|
||||
..testing::config(&[])
|
||||
@ -895,12 +941,15 @@ ARGS:
|
||||
name: shell_default,
|
||||
args: [],
|
||||
shell: "sh",
|
||||
shell_args: vec!["-cu".to_owned()],
|
||||
shell_present: false,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_set,
|
||||
args: ["--shell", "tclsh"],
|
||||
shell: "tclsh",
|
||||
shell_present: true,
|
||||
}
|
||||
|
||||
test! {
|
||||
@ -1050,6 +1099,61 @@ ARGS:
|
||||
},
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args_default,
|
||||
args: [],
|
||||
shell_args: vec!["-cu".to_owned()],
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args_set_hyphen,
|
||||
args: ["--shell-arg", "--foo"],
|
||||
shell_args: vec!["--foo".to_owned()],
|
||||
shell_present: true,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args_set_word,
|
||||
args: ["--shell-arg", "foo"],
|
||||
shell_args: vec!["foo".to_owned()],
|
||||
shell_present: true,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args_set_multiple,
|
||||
args: ["--shell-arg", "foo", "--shell-arg", "bar"],
|
||||
shell_args: vec!["foo".to_owned(), "bar".to_owned()],
|
||||
shell_present: true,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args_clear,
|
||||
args: ["--clear-shell-args"],
|
||||
shell_args: vec![],
|
||||
shell_present: true,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args_clear_and_set,
|
||||
args: ["--clear-shell-args", "--shell-arg", "bar"],
|
||||
shell_args: vec!["bar".to_owned()],
|
||||
shell_present: true,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args_set_and_clear,
|
||||
args: ["--shell-arg", "bar", "--clear-shell-args"],
|
||||
shell_args: vec![],
|
||||
shell_present: true,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args_set_multiple_and_clear,
|
||||
args: ["--shell-arg", "bar", "--shell-arg", "baz", "--clear-shell-args"],
|
||||
shell_args: vec![],
|
||||
shell_present: true,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: search_config_default,
|
||||
args: [],
|
||||
|
@ -275,7 +275,7 @@ impl<'a, D> Recipe<'a, D> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut cmd = context.settings.shell_command(&config.shell);
|
||||
let mut cmd = context.settings.shell_command(config);
|
||||
|
||||
cmd.current_dir(context.working_directory);
|
||||
|
||||
|
@ -10,8 +10,8 @@ impl<'src> Settings<'src> {
|
||||
Settings { shell: None }
|
||||
}
|
||||
|
||||
pub(crate) fn shell_command(&self, default_shell: &str) -> Command {
|
||||
if let Some(shell) = &self.shell {
|
||||
pub(crate) fn shell_command(&self, config: &Config) -> Command {
|
||||
if let (Some(shell), false) = (&self.shell, config.shell_present) {
|
||||
let mut cmd = Command::new(shell.command.cooked.as_ref());
|
||||
|
||||
for argument in &shell.arguments {
|
||||
@ -20,9 +20,9 @@ impl<'src> Settings<'src> {
|
||||
|
||||
cmd
|
||||
} else {
|
||||
let mut cmd = Command::new(default_shell);
|
||||
let mut cmd = Command::new(&config.shell);
|
||||
|
||||
cmd.arg("-cu");
|
||||
cmd.args(&config.shell_args);
|
||||
|
||||
cmd
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ macro_rules! test {
|
||||
$(stdout: $stdout:expr,)?
|
||||
$(stderr: $stderr:expr,)?
|
||||
$(status: $status:expr,)?
|
||||
$(shell: $shell:expr,)?
|
||||
) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
@ -30,6 +31,7 @@ macro_rules! test {
|
||||
$(stdout: $stdout,)?
|
||||
$(stderr: $stderr,)?
|
||||
$(status: $status,)?
|
||||
$(shell: $shell,)?
|
||||
..Test::default()
|
||||
}.run();
|
||||
}
|
||||
@ -43,6 +45,7 @@ struct Test<'a> {
|
||||
stdout: &'a str,
|
||||
stderr: &'a str,
|
||||
status: i32,
|
||||
shell: bool,
|
||||
}
|
||||
|
||||
impl<'a> Default for Test<'a> {
|
||||
@ -54,6 +57,7 @@ impl<'a> Default for Test<'a> {
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
status: EXIT_SUCCESS,
|
||||
shell: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,10 +78,15 @@ impl<'a> Test<'a> {
|
||||
dotenv_path.push(".env");
|
||||
fs::write(dotenv_path, "DOTENV_KEY=dotenv-value").unwrap();
|
||||
|
||||
let mut child = Command::new(&executable_path("just"))
|
||||
.current_dir(tmp.path())
|
||||
.args(&["--shell", "bash"])
|
||||
let mut command = Command::new(&executable_path("just"));
|
||||
|
||||
if self.shell {
|
||||
command.args(&["--shell", "bash"]);
|
||||
}
|
||||
|
||||
let mut child = command
|
||||
.args(self.args)
|
||||
.current_dir(tmp.path())
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
@ -350,22 +359,6 @@ _y:
|
||||
stdout: "a b c d\n",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: set_shell,
|
||||
justfile: "
|
||||
set shell := ['echo', '-n']
|
||||
|
||||
x := `bar`
|
||||
|
||||
foo:
|
||||
echo {{x}}
|
||||
echo foo
|
||||
",
|
||||
args: (),
|
||||
stdout: "echo barecho foo",
|
||||
stderr: "echo bar\necho foo\n",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: select,
|
||||
justfile: "b:
|
||||
@ -2211,3 +2204,60 @@ test! {
|
||||
echo default
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_args,
|
||||
justfile: "
|
||||
default:
|
||||
echo A${foo}A
|
||||
",
|
||||
args: ("--shell-arg", "-c"),
|
||||
stdout: "AA\n",
|
||||
stderr: "echo A${foo}A\n",
|
||||
shell: false,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_override,
|
||||
justfile: "
|
||||
set shell := ['foo-bar-baz']
|
||||
|
||||
default:
|
||||
echo hello
|
||||
",
|
||||
args: ("--shell", "bash"),
|
||||
stdout: "hello\n",
|
||||
stderr: "echo hello\n",
|
||||
shell: false,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: shell_arg_override,
|
||||
justfile: "
|
||||
set shell := ['foo-bar-baz']
|
||||
|
||||
default:
|
||||
echo hello
|
||||
",
|
||||
args: ("--shell-arg", "-cu"),
|
||||
stdout: "hello\n",
|
||||
stderr: "echo hello\n",
|
||||
shell: false,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: set_shell,
|
||||
justfile: "
|
||||
set shell := ['echo', '-n']
|
||||
|
||||
x := `bar`
|
||||
|
||||
foo:
|
||||
echo {{x}}
|
||||
echo foo
|
||||
",
|
||||
args: (),
|
||||
stdout: "echo barecho foo",
|
||||
stderr: "echo bar\necho foo\n",
|
||||
shell: false,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user