Add the --command
subcommand (#824)
This commit is contained in:
parent
4cb82e0c1f
commit
50cd24d37b
@ -1111,7 +1111,7 @@ echo:
|
||||
The interpreter path `/bin/sh` will be translated to a Windows-style path using
|
||||
`cygpath` before being executed.
|
||||
|
||||
If the interpreter path does not contain a `/` it will be executed without being translated. This is useful if `cygpath` is not available, or you wish to use a Windows style path to the interpreter.
|
||||
If the interpreter path does not contain a `/` it will be executed without being translated. This is useful if `cygpath` is not available, or you wish to pass a Windows style path to the interpreter.
|
||||
|
||||
=== Setting Variables in a Recipe
|
||||
|
||||
|
@ -20,7 +20,7 @@ _just() {
|
||||
|
||||
case "${cmd}" in
|
||||
just)
|
||||
opts=" -q -u -v -e -l -h -V -f -d -s --dry-run --highlight --no-dotenv --no-highlight --quiet --clear-shell-args --unsorted --verbose --choose --dump --edit --evaluate --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --completions --show <ARGUMENTS>... "
|
||||
opts=" -q -u -v -e -l -h -V -f -d -c -s --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --verbose --choose --dump --edit --evaluate --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show <ARGUMENTS>... "
|
||||
if [[ ${cur} == -* ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
@ -77,6 +77,14 @@ _just() {
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--command)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-c)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--completions)
|
||||
COMPREPLY=($(compgen -W "zsh bash fish powershell elvish" -- "${cur}"))
|
||||
return 0
|
||||
|
@ -25,6 +25,8 @@ edit:completion:arg-completer[just] = [@words]{
|
||||
cand --shell-arg 'Invoke shell with <SHELL-ARG> as an argument'
|
||||
cand -d 'Use <WORKING-DIRECTORY> as working directory. --justfile must also be set'
|
||||
cand --working-directory 'Use <WORKING-DIRECTORY> as working directory. --justfile must also be set'
|
||||
cand -c 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set'
|
||||
cand --command 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set'
|
||||
cand --completions 'Print shell completion script for <SHELL>'
|
||||
cand -s 'Show information about <RECIPE>'
|
||||
cand --show 'Show information about <RECIPE>'
|
||||
@ -34,6 +36,7 @@ edit:completion:arg-completer[just] = [@words]{
|
||||
cand --no-highlight 'Don''t highlight echoed recipe lines in bold'
|
||||
cand -q 'Suppress all output'
|
||||
cand --quiet 'Suppress all output'
|
||||
cand --shell-command 'Invoke <COMMAND> with the shell used to run recipe lines and backticks'
|
||||
cand --clear-shell-args 'Clear shell arguments'
|
||||
cand -u 'Return list and summary entries in source order'
|
||||
cand --unsorted 'Return list and summary entries in source order'
|
||||
|
@ -18,6 +18,7 @@ complete -c just -n "__fish_use_subcommand" -l set -d 'Override <VARIABLE> with
|
||||
complete -c just -n "__fish_use_subcommand" -l shell -d 'Invoke <SHELL> to run recipes'
|
||||
complete -c just -n "__fish_use_subcommand" -l shell-arg -d 'Invoke shell with <SHELL-ARG> as an argument'
|
||||
complete -c just -n "__fish_use_subcommand" -s d -l working-directory -d 'Use <WORKING-DIRECTORY> as working directory. --justfile must also be set'
|
||||
complete -c just -n "__fish_use_subcommand" -s c -l command -d 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set'
|
||||
complete -c just -n "__fish_use_subcommand" -l completions -d 'Print shell completion script for <SHELL>' -r -f -a "zsh bash fish powershell elvish"
|
||||
complete -c just -n "__fish_use_subcommand" -s s -l show -d 'Show information about <RECIPE>'
|
||||
complete -c just -n "__fish_use_subcommand" -l dry-run -d 'Print what just would do without doing it'
|
||||
@ -25,6 +26,7 @@ complete -c just -n "__fish_use_subcommand" -l highlight -d 'Highlight echoed re
|
||||
complete -c just -n "__fish_use_subcommand" -l no-dotenv -d 'Don\'t load `.env` file'
|
||||
complete -c just -n "__fish_use_subcommand" -l no-highlight -d 'Don\'t highlight echoed recipe lines in bold'
|
||||
complete -c just -n "__fish_use_subcommand" -s q -l quiet -d 'Suppress all output'
|
||||
complete -c just -n "__fish_use_subcommand" -l shell-command -d 'Invoke <COMMAND> with the shell used to run recipe lines and backticks'
|
||||
complete -c just -n "__fish_use_subcommand" -l clear-shell-args -d 'Clear shell arguments'
|
||||
complete -c just -n "__fish_use_subcommand" -s u -l unsorted -d 'Return list and summary entries in source order'
|
||||
complete -c just -n "__fish_use_subcommand" -s v -l verbose -d 'Use verbose output'
|
||||
|
@ -30,6 +30,8 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
|
||||
[CompletionResult]::new('--shell-arg', 'shell-arg', [CompletionResultType]::ParameterName, 'Invoke shell with <SHELL-ARG> as an argument')
|
||||
[CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Use <WORKING-DIRECTORY> as working directory. --justfile must also be set')
|
||||
[CompletionResult]::new('--working-directory', 'working-directory', [CompletionResultType]::ParameterName, 'Use <WORKING-DIRECTORY> as working directory. --justfile must also be set')
|
||||
[CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set')
|
||||
[CompletionResult]::new('--command', 'command', [CompletionResultType]::ParameterName, 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set')
|
||||
[CompletionResult]::new('--completions', 'completions', [CompletionResultType]::ParameterName, 'Print shell completion script for <SHELL>')
|
||||
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Show information about <RECIPE>')
|
||||
[CompletionResult]::new('--show', 'show', [CompletionResultType]::ParameterName, 'Show information about <RECIPE>')
|
||||
@ -39,6 +41,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
|
||||
[CompletionResult]::new('--no-highlight', 'no-highlight', [CompletionResultType]::ParameterName, 'Don''t highlight echoed recipe lines in bold')
|
||||
[CompletionResult]::new('-q', 'q', [CompletionResultType]::ParameterName, 'Suppress all output')
|
||||
[CompletionResult]::new('--quiet', 'quiet', [CompletionResultType]::ParameterName, 'Suppress all output')
|
||||
[CompletionResult]::new('--shell-command', 'shell-command', [CompletionResultType]::ParameterName, 'Invoke <COMMAND> with the shell used to run recipe lines and backticks')
|
||||
[CompletionResult]::new('--clear-shell-args', 'clear-shell-args', [CompletionResultType]::ParameterName, 'Clear shell arguments')
|
||||
[CompletionResult]::new('-u', 'u', [CompletionResultType]::ParameterName, 'Return list and summary entries in source order')
|
||||
[CompletionResult]::new('--unsorted', 'unsorted', [CompletionResultType]::ParameterName, 'Return list and summary entries in source order')
|
||||
|
@ -26,6 +26,8 @@ _just() {
|
||||
'*--shell-arg=[Invoke shell with <SHELL-ARG> as an argument]' \
|
||||
'-d+[Use <WORKING-DIRECTORY> as working directory. --justfile must also be set]' \
|
||||
'--working-directory=[Use <WORKING-DIRECTORY> as working directory. --justfile must also be set]' \
|
||||
'-c+[Run an arbitrary command with the working directory, `.env`, overrides, and exports set]' \
|
||||
'--command=[Run an arbitrary command with the working directory, `.env`, overrides, and exports set]' \
|
||||
'--completions=[Print shell completion script for <SHELL>]: :(zsh bash fish powershell elvish)' \
|
||||
'-s+[Show information about <RECIPE>]: :_just_commands' \
|
||||
'--show=[Show information about <RECIPE>]: :_just_commands' \
|
||||
@ -35,6 +37,7 @@ _just() {
|
||||
'--no-highlight[Don'\''t highlight echoed recipe lines in bold]' \
|
||||
'(--dry-run)-q[Suppress all output]' \
|
||||
'(--dry-run)--quiet[Suppress all output]' \
|
||||
'--shell-command[Invoke <COMMAND> with the shell used to run recipe lines and backticks]' \
|
||||
'--clear-shell-args[Clear shell arguments]' \
|
||||
'-u[Return list and summary entries in source order]' \
|
||||
'--unsorted[Return list and summary entries in source order]' \
|
||||
|
@ -5,10 +5,10 @@ error_on_unformatted = true
|
||||
format_code_in_doc_comments = true
|
||||
format_macro_bodies = true
|
||||
format_strings = true
|
||||
imports_granularity = "Crate"
|
||||
match_arm_blocks = false
|
||||
match_block_trailing_comma = true
|
||||
max_width = 100
|
||||
merge_imports = true
|
||||
newline_style = "Unix"
|
||||
normalize_comments = true
|
||||
overflow_delimited_expr = true
|
||||
|
@ -3,7 +3,7 @@ pub(crate) use std::{
|
||||
cmp,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
env,
|
||||
ffi::OsString,
|
||||
ffi::{OsStr, OsString},
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
fs,
|
||||
io::{self, Cursor, Write},
|
||||
|
@ -26,6 +26,7 @@ pub(crate) struct Config {
|
||||
pub(crate) shell: String,
|
||||
pub(crate) shell_args: Vec<String>,
|
||||
pub(crate) shell_present: bool,
|
||||
pub(crate) shell_command: bool,
|
||||
pub(crate) subcommand: Subcommand,
|
||||
pub(crate) unsorted: bool,
|
||||
pub(crate) verbosity: Verbosity,
|
||||
@ -42,14 +43,16 @@ mod cmd {
|
||||
pub(crate) const SHOW: &str = "SHOW";
|
||||
pub(crate) const SUMMARY: &str = "SUMMARY";
|
||||
pub(crate) const VARIABLES: &str = "VARIABLES";
|
||||
pub(crate) const COMMAND: &str = "COMMAND";
|
||||
|
||||
pub(crate) const ALL: &[&str] = &[
|
||||
CHOOSE,
|
||||
COMMAND,
|
||||
COMPLETIONS,
|
||||
DUMP,
|
||||
EDIT,
|
||||
INIT,
|
||||
EVALUATE,
|
||||
INIT,
|
||||
LIST,
|
||||
SHOW,
|
||||
SUMMARY,
|
||||
@ -75,15 +78,16 @@ mod arg {
|
||||
pub(crate) const COLOR: &str = "COLOR";
|
||||
pub(crate) const DRY_RUN: &str = "DRY-RUN";
|
||||
pub(crate) const HIGHLIGHT: &str = "HIGHLIGHT";
|
||||
pub(crate) const JUSTFILE: &str = "JUSTFILE";
|
||||
pub(crate) const LIST_HEADING: &str = "LIST-HEADING";
|
||||
pub(crate) const LIST_PREFIX: &str = "LIST-PREFIX";
|
||||
pub(crate) const JUSTFILE: &str = "JUSTFILE";
|
||||
pub(crate) const NO_DOTENV: &str = "NO-DOTENV";
|
||||
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 SHELL_COMMAND: &str = "SHELL-COMMAND";
|
||||
pub(crate) const UNSORTED: &str = "UNSORTED";
|
||||
pub(crate) const VERBOSE: &str = "VERBOSE";
|
||||
pub(crate) const WORKING_DIRECTORY: &str = "WORKING-DIRECTORY";
|
||||
@ -193,6 +197,12 @@ impl Config {
|
||||
.overrides_with(arg::CLEAR_SHELL_ARGS)
|
||||
.help("Invoke shell with <SHELL-ARG> as an argument"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(arg::SHELL_COMMAND)
|
||||
.long("shell-command")
|
||||
.requires(cmd::COMMAND)
|
||||
.help("Invoke <COMMAND> with the shell used to run recipe lines and backticks"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(arg::CLEAR_SHELL_ARGS)
|
||||
.long("clear-shell-args")
|
||||
@ -220,12 +230,18 @@ impl Config {
|
||||
.help("Use <WORKING-DIRECTORY> as working directory. --justfile must also be set")
|
||||
.requires(arg::JUSTFILE),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(arg::ARGUMENTS)
|
||||
.multiple(true)
|
||||
.help("Overrides and recipe(s) to run, defaulting to the first recipe in the justfile"),
|
||||
)
|
||||
.arg(Arg::with_name(cmd::CHOOSE).long("choose").help(CHOOSE_HELP))
|
||||
.arg(
|
||||
Arg::with_name(cmd::COMMAND)
|
||||
.long("command")
|
||||
.short("c")
|
||||
.min_values(1)
|
||||
.allow_hyphen_values(true)
|
||||
.help(
|
||||
"Run an arbitrary command with the working directory, `.env`, overrides, and exports \
|
||||
set",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(cmd::COMPLETIONS)
|
||||
.long("completions")
|
||||
@ -279,7 +295,12 @@ impl Config {
|
||||
.long("variables")
|
||||
.help("List names of variables"),
|
||||
)
|
||||
.group(ArgGroup::with_name("SUBCOMMAND").args(cmd::ALL));
|
||||
.group(ArgGroup::with_name("SUBCOMMAND").args(cmd::ALL))
|
||||
.arg(
|
||||
Arg::with_name(arg::ARGUMENTS)
|
||||
.multiple(true)
|
||||
.help("Overrides and recipe(s) to run, defaulting to the first recipe in the justfile"),
|
||||
);
|
||||
|
||||
if cfg!(feature = "help4help2man") {
|
||||
app.version(env!("CARGO_PKG_VERSION")).about(concat!(
|
||||
@ -401,6 +422,16 @@ impl Config {
|
||||
chooser: matches.value_of(arg::CHOOSER).map(str::to_owned),
|
||||
overrides,
|
||||
}
|
||||
} else if let Some(values) = matches.values_of_os(cmd::COMMAND) {
|
||||
let mut arguments = values
|
||||
.into_iter()
|
||||
.map(OsStr::to_owned)
|
||||
.collect::<Vec<OsString>>();
|
||||
Subcommand::Command {
|
||||
binary: arguments.remove(0),
|
||||
arguments,
|
||||
overrides,
|
||||
}
|
||||
} else if let Some(shell) = matches.value_of(cmd::COMPLETIONS) {
|
||||
Subcommand::Completions {
|
||||
shell: shell.to_owned(),
|
||||
@ -463,6 +494,7 @@ impl Config {
|
||||
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
|
||||
shell: matches.value_of(arg::SHELL).unwrap().to_owned(),
|
||||
load_dotenv: !matches.is_present(arg::NO_DOTENV),
|
||||
shell_command: matches.is_present(arg::SHELL_COMMAND),
|
||||
unsorted: matches.is_present(arg::UNSORTED),
|
||||
list_heading: matches
|
||||
.value_of(arg::LIST_HEADING)
|
||||
@ -522,6 +554,7 @@ impl Config {
|
||||
match &self.subcommand {
|
||||
Choose { overrides, chooser } =>
|
||||
self.choose(justfile, &search, overrides, chooser.as_deref())?,
|
||||
Command { overrides, .. } => self.run(justfile, &search, overrides, &[])?,
|
||||
Dump => Self::dump(justfile),
|
||||
Evaluate { overrides, .. } => self.run(justfile, &search, overrides, &[])?,
|
||||
List => self.list(justfile),
|
||||
@ -893,6 +926,8 @@ FLAGS:
|
||||
--no-dotenv Don't load `.env` file
|
||||
--no-highlight Don't highlight echoed recipe lines in bold
|
||||
-q, --quiet Suppress all output
|
||||
--shell-command Invoke <COMMAND> with the shell used to run recipe lines and \
|
||||
backticks
|
||||
--summary List names of available recipes
|
||||
-u, --unsorted Return list and summary entries in source order
|
||||
--variables List names of variables
|
||||
@ -903,6 +938,9 @@ OPTIONS:
|
||||
--color <COLOR>
|
||||
Print colorful output [default: auto] [possible values: auto, always, never]
|
||||
|
||||
-c, --command <COMMAND>
|
||||
Run an arbitrary command with the working directory, `.env`, overrides, and exports set
|
||||
|
||||
--completions <SHELL>
|
||||
Print shell completion script for <SHELL> [possible values: zsh, bash, fish, \
|
||||
powershell, elvish]
|
||||
|
@ -127,34 +127,70 @@ impl<'src> Justfile<'src> {
|
||||
)?
|
||||
};
|
||||
|
||||
if let Subcommand::Evaluate { variable, .. } = &config.subcommand {
|
||||
if let Some(variable) = variable {
|
||||
if let Some(value) = scope.value(variable) {
|
||||
print!("{}", value);
|
||||
match &config.subcommand {
|
||||
Subcommand::Command {
|
||||
binary, arguments, ..
|
||||
} => {
|
||||
let mut command = if config.shell_command {
|
||||
let mut command = self.settings.shell_command(&config);
|
||||
command.arg(binary);
|
||||
command
|
||||
} else {
|
||||
return Err(RuntimeError::EvalUnknownVariable {
|
||||
suggestion: self.suggest_variable(&variable),
|
||||
variable: variable.clone(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let mut width = 0;
|
||||
Command::new(binary)
|
||||
};
|
||||
|
||||
for name in scope.names() {
|
||||
width = cmp::max(name.len(), width);
|
||||
command.args(arguments);
|
||||
|
||||
command.current_dir(&search.working_directory);
|
||||
|
||||
let scope = scope.child();
|
||||
|
||||
command.export(&self.settings, &dotenv, &scope);
|
||||
|
||||
let status = InterruptHandler::guard(|| command.status()).map_err(|io_error| {
|
||||
RuntimeError::CommandInvocation {
|
||||
binary: binary.clone(),
|
||||
arguments: arguments.clone(),
|
||||
io_error,
|
||||
}
|
||||
})?;
|
||||
|
||||
if !status.success() {
|
||||
process::exit(status.code().unwrap_or(EXIT_FAILURE));
|
||||
};
|
||||
|
||||
return Ok(());
|
||||
},
|
||||
Subcommand::Evaluate { variable, .. } => {
|
||||
if let Some(variable) = variable {
|
||||
if let Some(value) = scope.value(variable) {
|
||||
print!("{}", value);
|
||||
} else {
|
||||
return Err(RuntimeError::EvalUnknownVariable {
|
||||
suggestion: self.suggest_variable(&variable),
|
||||
variable: variable.clone(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let mut width = 0;
|
||||
|
||||
for name in scope.names() {
|
||||
width = cmp::max(name.len(), width);
|
||||
}
|
||||
|
||||
for binding in scope.bindings() {
|
||||
println!(
|
||||
"{0:1$} := \"{2}\"",
|
||||
binding.name.lexeme(),
|
||||
width,
|
||||
binding.value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for binding in scope.bindings() {
|
||||
println!(
|
||||
"{0:1$} := \"{2}\"",
|
||||
binding.name.lexeme(),
|
||||
width,
|
||||
binding.value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
return Ok(());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let argvec: Vec<&str> = if !arguments.is_empty() {
|
||||
|
@ -18,6 +18,11 @@ pub(crate) enum RuntimeError<'src> {
|
||||
line_number: Option<usize>,
|
||||
code: i32,
|
||||
},
|
||||
CommandInvocation {
|
||||
binary: OsString,
|
||||
arguments: Vec<OsString>,
|
||||
io_error: io::Error,
|
||||
},
|
||||
Cygpath {
|
||||
recipe: &'src str,
|
||||
output_error: OutputError,
|
||||
@ -201,6 +206,22 @@ impl<'src> Display for RuntimeError<'src> {
|
||||
} else {
|
||||
write!(f, "Recipe `{}` failed with exit code {}", recipe, code)?;
|
||||
},
|
||||
CommandInvocation {
|
||||
binary,
|
||||
arguments,
|
||||
io_error,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"Failed to invoke {}: {}",
|
||||
iter::once(binary)
|
||||
.chain(arguments)
|
||||
.map(|value| Enclosure::tick(value.to_string_lossy()).to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(" "),
|
||||
io_error,
|
||||
)?;
|
||||
},
|
||||
Cygpath {
|
||||
recipe,
|
||||
output_error,
|
||||
|
@ -6,6 +6,11 @@ pub(crate) enum Subcommand {
|
||||
overrides: BTreeMap<String, String>,
|
||||
chooser: Option<String>,
|
||||
},
|
||||
Command {
|
||||
arguments: Vec<OsString>,
|
||||
binary: OsString,
|
||||
overrides: BTreeMap<String, String>,
|
||||
},
|
||||
Completions {
|
||||
shell: String,
|
||||
},
|
||||
|
134
tests/command.rs
Normal file
134
tests/command.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use crate::common::*;
|
||||
|
||||
test! {
|
||||
name: long,
|
||||
justfile: "
|
||||
x:
|
||||
echo XYZ
|
||||
",
|
||||
args: ("--command", "printf", "foo"),
|
||||
stdout: "foo",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: short,
|
||||
justfile: "
|
||||
x:
|
||||
echo XYZ
|
||||
",
|
||||
args: ("-c", "printf", "foo"),
|
||||
stdout: "foo",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: no_binary,
|
||||
justfile: "
|
||||
x:
|
||||
echo XYZ
|
||||
",
|
||||
args: ("--command"),
|
||||
stderr: &format!("
|
||||
error: The argument '--command <COMMAND>' requires a value but none was supplied
|
||||
|
||||
USAGE:
|
||||
just{} --color <COLOR> --shell <SHELL> --shell-arg <SHELL-ARG>... \
|
||||
<--choose|--command <COMMAND>|--completions <SHELL>|--dump|--edit|\
|
||||
--evaluate|--init|--list|--show <RECIPE>|--summary|--variables>
|
||||
|
||||
For more information try --help
|
||||
", EXE_SUFFIX),
|
||||
status: EXIT_FAILURE,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: env_is_loaded,
|
||||
justfile: "
|
||||
x:
|
||||
echo XYZ
|
||||
",
|
||||
args: ("--command", "sh", "-c", "printf $DOTENV_KEY"),
|
||||
stdout: "dotenv-value",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: exports_are_available,
|
||||
justfile: "
|
||||
export FOO := 'bar'
|
||||
|
||||
x:
|
||||
echo XYZ
|
||||
",
|
||||
args: ("--command", "sh", "-c", "printf $FOO"),
|
||||
stdout: "bar",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: set_overrides_work,
|
||||
justfile: "
|
||||
export FOO := 'bar'
|
||||
|
||||
x:
|
||||
echo XYZ
|
||||
",
|
||||
args: ("--set", "FOO", "baz", "--command", "sh", "-c", "printf $FOO"),
|
||||
stdout: "baz",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: run_in_shell,
|
||||
justfile: "
|
||||
set shell := ['printf']
|
||||
",
|
||||
args: ("--shell-command", "--command", "bar baz"),
|
||||
stdout: "bar baz",
|
||||
shell: false,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: exit_status,
|
||||
justfile: "
|
||||
x:
|
||||
echo XYZ
|
||||
",
|
||||
args: ("--command", "false"),
|
||||
status: EXIT_FAILURE,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn working_directory_is_correct() {
|
||||
let tmp = tempdir();
|
||||
|
||||
fs::write(tmp.path().join("justfile"), "").unwrap();
|
||||
fs::write(tmp.path().join("bar"), "baz").unwrap();
|
||||
fs::create_dir(tmp.path().join("foo")).unwrap();
|
||||
|
||||
let output = Command::new(&executable_path("just"))
|
||||
.args(&["--command", "cat", "bar"])
|
||||
.current_dir(tmp.path().join("foo"))
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(str::from_utf8(&output.stderr).unwrap(), "");
|
||||
|
||||
assert!(output.status.success());
|
||||
|
||||
assert_eq!(str::from_utf8(&output.stdout).unwrap(), "baz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_not_found() {
|
||||
let tmp = tempdir();
|
||||
|
||||
fs::write(tmp.path().join("justfile"), "").unwrap();
|
||||
|
||||
let output = Command::new(&executable_path("just"))
|
||||
.args(&["--command", "asdfasdfasdfasdfadfsadsfadsf", "bar"])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
assert!(str::from_utf8(&output.stderr)
|
||||
.unwrap()
|
||||
.starts_with("error: Failed to invoke `asdfasdfasdfasdfadfsadsfadsf` `bar`:"));
|
||||
|
||||
assert!(!output.status.success());
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
pub(crate) use std::{
|
||||
collections::BTreeMap,
|
||||
env, fs,
|
||||
env::{self, consts::EXE_SUFFIX},
|
||||
fs,
|
||||
io::Write,
|
||||
iter,
|
||||
path::Path,
|
||||
|
@ -1,6 +1,7 @@
|
||||
#[cfg(unix)]
|
||||
mod unix {
|
||||
use executable_path::executable_path;
|
||||
use just::unindent;
|
||||
use std::{
|
||||
fs,
|
||||
process::Command,
|
||||
@ -14,16 +15,17 @@ mod unix {
|
||||
}
|
||||
}
|
||||
|
||||
fn interrupt_test(justfile: &str) {
|
||||
fn interrupt_test(arguments: &[&str], justfile: &str) {
|
||||
let tmp = tempdir();
|
||||
let mut justfile_path = tmp.path().to_path_buf();
|
||||
justfile_path.push("justfile");
|
||||
fs::write(justfile_path, justfile).unwrap();
|
||||
fs::write(justfile_path, unindent(justfile)).unwrap();
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
let mut child = Command::new(&executable_path("just"))
|
||||
.current_dir(&tmp)
|
||||
.args(arguments)
|
||||
.spawn()
|
||||
.expect("just invocation failed");
|
||||
|
||||
@ -50,11 +52,12 @@ mod unix {
|
||||
#[ignore]
|
||||
fn interrupt_shebang() {
|
||||
interrupt_test(
|
||||
&[],
|
||||
"
|
||||
default:
|
||||
#!/usr/bin/env sh
|
||||
sleep 1
|
||||
",
|
||||
default:
|
||||
#!/usr/bin/env sh
|
||||
sleep 1
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
@ -62,10 +65,11 @@ default:
|
||||
#[ignore]
|
||||
fn interrupt_line() {
|
||||
interrupt_test(
|
||||
&[],
|
||||
"
|
||||
default:
|
||||
@sleep 1
|
||||
",
|
||||
default:
|
||||
@sleep 1
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
@ -73,12 +77,19 @@ default:
|
||||
#[ignore]
|
||||
fn interrupt_backtick() {
|
||||
interrupt_test(
|
||||
&[],
|
||||
"
|
||||
foo := `sleep 1`
|
||||
foo := `sleep 1`
|
||||
|
||||
default:
|
||||
@echo {{foo}}
|
||||
",
|
||||
default:
|
||||
@echo {{foo}}
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn interrupt_command() {
|
||||
interrupt_test(&["--command", "sleep", "1"], "");
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ mod test;
|
||||
mod common;
|
||||
|
||||
mod choose;
|
||||
mod command;
|
||||
mod completions;
|
||||
mod conditional;
|
||||
mod delimiters;
|
||||
|
Loading…
Reference in New Issue
Block a user