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,
|
raw: &str,
|
||||||
token: &Token<'a>,
|
token: &Token<'a>,
|
||||||
) -> RunResult<'a, String> {
|
) -> 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);
|
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;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
pub(crate) const DEFAULT_SHELL: &str = "sh";
|
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";
|
pub(crate) const INIT_JUSTFILE: &str = "default:\n\techo 'Hello, world!'\n";
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -15,6 +16,8 @@ pub(crate) struct Config {
|
|||||||
pub(crate) quiet: bool,
|
pub(crate) quiet: bool,
|
||||||
pub(crate) search_config: SearchConfig,
|
pub(crate) search_config: SearchConfig,
|
||||||
pub(crate) shell: String,
|
pub(crate) shell: String,
|
||||||
|
pub(crate) shell_args: Vec<String>,
|
||||||
|
pub(crate) shell_present: bool,
|
||||||
pub(crate) subcommand: Subcommand,
|
pub(crate) subcommand: Subcommand,
|
||||||
pub(crate) verbosity: Verbosity,
|
pub(crate) verbosity: Verbosity,
|
||||||
}
|
}
|
||||||
@ -34,14 +37,16 @@ mod cmd {
|
|||||||
|
|
||||||
mod arg {
|
mod arg {
|
||||||
pub(crate) const ARGUMENTS: &str = "ARGUMENTS";
|
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 COLOR: &str = "COLOR";
|
||||||
pub(crate) const DRY_RUN: &str = "DRY-RUN";
|
pub(crate) const DRY_RUN: &str = "DRY-RUN";
|
||||||
pub(crate) const HIGHLIGHT: &str = "HIGHLIGHT";
|
pub(crate) const HIGHLIGHT: &str = "HIGHLIGHT";
|
||||||
pub(crate) const NO_HIGHLIGHT: &str = "NO-HIGHLIGHT";
|
|
||||||
pub(crate) const JUSTFILE: &str = "JUSTFILE";
|
pub(crate) const JUSTFILE: &str = "JUSTFILE";
|
||||||
|
pub(crate) const NO_HIGHLIGHT: &str = "NO-HIGHLIGHT";
|
||||||
pub(crate) const QUIET: &str = "QUIET";
|
pub(crate) const QUIET: &str = "QUIET";
|
||||||
pub(crate) const SET: &str = "SET";
|
pub(crate) const SET: &str = "SET";
|
||||||
pub(crate) const SHELL: &str = "SHELL";
|
pub(crate) const SHELL: &str = "SHELL";
|
||||||
|
pub(crate) const SHELL_ARG: &str = "SHELL-ARG";
|
||||||
pub(crate) const VERBOSE: &str = "VERBOSE";
|
pub(crate) const VERBOSE: &str = "VERBOSE";
|
||||||
pub(crate) const WORKING_DIRECTORY: &str = "WORKING-DIRECTORY";
|
pub(crate) const WORKING_DIRECTORY: &str = "WORKING-DIRECTORY";
|
||||||
|
|
||||||
@ -114,6 +119,23 @@ impl Config {
|
|||||||
.default_value(DEFAULT_SHELL)
|
.default_value(DEFAULT_SHELL)
|
||||||
.help("Invoke <SHELL> to run recipes"),
|
.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(
|
||||||
Arg::with_name(arg::VERBOSE)
|
Arg::with_name(arg::VERBOSE)
|
||||||
.short("v")
|
.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 {
|
Ok(Config {
|
||||||
dry_run: matches.is_present(arg::DRY_RUN),
|
dry_run: matches.is_present(arg::DRY_RUN),
|
||||||
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
|
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
|
||||||
quiet: matches.is_present(arg::QUIET),
|
quiet: matches.is_present(arg::QUIET),
|
||||||
shell: matches.value_of(arg::SHELL).unwrap().to_owned(),
|
shell: matches.value_of(arg::SHELL).unwrap().to_owned(),
|
||||||
search_config,
|
color,
|
||||||
invocation_directory,
|
invocation_directory,
|
||||||
|
search_config,
|
||||||
|
shell_args,
|
||||||
|
shell_present,
|
||||||
subcommand,
|
subcommand,
|
||||||
verbosity,
|
verbosity,
|
||||||
color,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,6 +633,7 @@ USAGE:
|
|||||||
just [FLAGS] [OPTIONS] [--] [ARGUMENTS]...
|
just [FLAGS] [OPTIONS] [--] [ARGUMENTS]...
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
|
--clear-shell-args Clear shell arguments
|
||||||
--dry-run Print what just would do without doing it
|
--dry-run Print what just would do without doing it
|
||||||
--dump Print entire justfile
|
--dump Print entire justfile
|
||||||
-e, --edit \
|
-e, --edit \
|
||||||
@ -614,6 +654,8 @@ OPTIONS:
|
|||||||
-f, --justfile <JUSTFILE> Use <JUSTFILE> as justfile.
|
-f, --justfile <JUSTFILE> Use <JUSTFILE> as justfile.
|
||||||
--set <VARIABLE> <VALUE> Override <VARIABLE> with <VALUE>
|
--set <VARIABLE> <VALUE> Override <VARIABLE> with <VALUE>
|
||||||
--shell <SHELL> Invoke <SHELL> to run recipes [default: sh]
|
--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>
|
-s, --show <RECIPE> Show information about <RECIPE>
|
||||||
-d, --working-directory <WORKING-DIRECTORY>
|
-d, --working-directory <WORKING-DIRECTORY>
|
||||||
Use <WORKING-DIRECTORY> as working directory. --justfile must also be set
|
Use <WORKING-DIRECTORY> as working directory. --justfile must also be set
|
||||||
@ -641,6 +683,8 @@ ARGS:
|
|||||||
$(quiet: $quiet:expr,)?
|
$(quiet: $quiet:expr,)?
|
||||||
$(search_config: $search_config:expr,)?
|
$(search_config: $search_config:expr,)?
|
||||||
$(shell: $shell:expr,)?
|
$(shell: $shell:expr,)?
|
||||||
|
$(shell_args: $shell_args:expr,)?
|
||||||
|
$(shell_present: $shell_present:expr,)?
|
||||||
$(subcommand: $subcommand:expr,)?
|
$(subcommand: $subcommand:expr,)?
|
||||||
$(verbosity: $verbosity:expr,)?
|
$(verbosity: $verbosity:expr,)?
|
||||||
} => {
|
} => {
|
||||||
@ -658,6 +702,8 @@ ARGS:
|
|||||||
$(quiet: $quiet,)?
|
$(quiet: $quiet,)?
|
||||||
$(search_config: $search_config,)?
|
$(search_config: $search_config,)?
|
||||||
$(shell: $shell.to_string(),)?
|
$(shell: $shell.to_string(),)?
|
||||||
|
$(shell_args: $shell_args,)?
|
||||||
|
$(shell_present: $shell_present,)?
|
||||||
$(subcommand: $subcommand,)?
|
$(subcommand: $subcommand,)?
|
||||||
$(verbosity: $verbosity,)?
|
$(verbosity: $verbosity,)?
|
||||||
..testing::config(&[])
|
..testing::config(&[])
|
||||||
@ -895,12 +941,15 @@ ARGS:
|
|||||||
name: shell_default,
|
name: shell_default,
|
||||||
args: [],
|
args: [],
|
||||||
shell: "sh",
|
shell: "sh",
|
||||||
|
shell_args: vec!["-cu".to_owned()],
|
||||||
|
shell_present: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: shell_set,
|
name: shell_set,
|
||||||
args: ["--shell", "tclsh"],
|
args: ["--shell", "tclsh"],
|
||||||
shell: "tclsh",
|
shell: "tclsh",
|
||||||
|
shell_present: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
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! {
|
test! {
|
||||||
name: search_config_default,
|
name: search_config_default,
|
||||||
args: [],
|
args: [],
|
||||||
|
@ -275,7 +275,7 @@ impl<'a, D> Recipe<'a, D> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cmd = context.settings.shell_command(&config.shell);
|
let mut cmd = context.settings.shell_command(config);
|
||||||
|
|
||||||
cmd.current_dir(context.working_directory);
|
cmd.current_dir(context.working_directory);
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ impl<'src> Settings<'src> {
|
|||||||
Settings { shell: None }
|
Settings { shell: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn shell_command(&self, default_shell: &str) -> Command {
|
pub(crate) fn shell_command(&self, config: &Config) -> Command {
|
||||||
if let Some(shell) = &self.shell {
|
if let (Some(shell), false) = (&self.shell, config.shell_present) {
|
||||||
let mut cmd = Command::new(shell.command.cooked.as_ref());
|
let mut cmd = Command::new(shell.command.cooked.as_ref());
|
||||||
|
|
||||||
for argument in &shell.arguments {
|
for argument in &shell.arguments {
|
||||||
@ -20,9 +20,9 @@ impl<'src> Settings<'src> {
|
|||||||
|
|
||||||
cmd
|
cmd
|
||||||
} else {
|
} else {
|
||||||
let mut cmd = Command::new(default_shell);
|
let mut cmd = Command::new(&config.shell);
|
||||||
|
|
||||||
cmd.arg("-cu");
|
cmd.args(&config.shell_args);
|
||||||
|
|
||||||
cmd
|
cmd
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ macro_rules! test {
|
|||||||
$(stdout: $stdout:expr,)?
|
$(stdout: $stdout:expr,)?
|
||||||
$(stderr: $stderr:expr,)?
|
$(stderr: $stderr:expr,)?
|
||||||
$(status: $status:expr,)?
|
$(status: $status:expr,)?
|
||||||
|
$(shell: $shell:expr,)?
|
||||||
) => {
|
) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
@ -30,6 +31,7 @@ macro_rules! test {
|
|||||||
$(stdout: $stdout,)?
|
$(stdout: $stdout,)?
|
||||||
$(stderr: $stderr,)?
|
$(stderr: $stderr,)?
|
||||||
$(status: $status,)?
|
$(status: $status,)?
|
||||||
|
$(shell: $shell,)?
|
||||||
..Test::default()
|
..Test::default()
|
||||||
}.run();
|
}.run();
|
||||||
}
|
}
|
||||||
@ -43,6 +45,7 @@ struct Test<'a> {
|
|||||||
stdout: &'a str,
|
stdout: &'a str,
|
||||||
stderr: &'a str,
|
stderr: &'a str,
|
||||||
status: i32,
|
status: i32,
|
||||||
|
shell: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for Test<'a> {
|
impl<'a> Default for Test<'a> {
|
||||||
@ -54,6 +57,7 @@ impl<'a> Default for Test<'a> {
|
|||||||
stdout: "",
|
stdout: "",
|
||||||
stderr: "",
|
stderr: "",
|
||||||
status: EXIT_SUCCESS,
|
status: EXIT_SUCCESS,
|
||||||
|
shell: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,10 +78,15 @@ impl<'a> Test<'a> {
|
|||||||
dotenv_path.push(".env");
|
dotenv_path.push(".env");
|
||||||
fs::write(dotenv_path, "DOTENV_KEY=dotenv-value").unwrap();
|
fs::write(dotenv_path, "DOTENV_KEY=dotenv-value").unwrap();
|
||||||
|
|
||||||
let mut child = Command::new(&executable_path("just"))
|
let mut command = Command::new(&executable_path("just"));
|
||||||
.current_dir(tmp.path())
|
|
||||||
.args(&["--shell", "bash"])
|
if self.shell {
|
||||||
|
command.args(&["--shell", "bash"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut child = command
|
||||||
.args(self.args)
|
.args(self.args)
|
||||||
|
.current_dir(tmp.path())
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
@ -350,22 +359,6 @@ _y:
|
|||||||
stdout: "a b c d\n",
|
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! {
|
test! {
|
||||||
name: select,
|
name: select,
|
||||||
justfile: "b:
|
justfile: "b:
|
||||||
@ -2211,3 +2204,60 @@ test! {
|
|||||||
echo default
|
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