Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement parallel job execution #1562

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
89 changes: 89 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ atty = "0.2.0"
camino = "1.0.4"
clap = { version = "2.33.0", features = ["wrap_help"] }
ctrlc = { version = "3.1.1", features = ["termination"] }
crossbeam = "0.8.2"
derivative = "2.0.0"
dotenvy = "0.15"
edit-distance = "2.0.0"
Expand Down
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,7 @@ Recipes may be annotated with attributes that change their behavior.
| `[macos]`<sup>1.8.0</sup> | Enable recipe on MacOS. |
| `[no-cd]`<sup>1.9.0</sup> | Don't change directory before executing recipe. |
| `[no-exit-message]`<sup>1.7.0</sup> | Don't print an error message if recipe fails. |
| `[parallel]`<sup>master</sup> | See [Parallel execution](#parallel-execution). |
| `[private]`<sup>1.10.0</sup> | See [Private Recipes](#private-recipes). |
| `[unix]`<sup>1.8.0</sup> | Enable recipe on Unixes. (Includes MacOS). |
| `[windows]`<sup>1.8.0</sup> | Enable recipe on Windows. |
Expand Down Expand Up @@ -2143,6 +2144,32 @@ Available recipes:

This is useful for helper recipes which are only meant to be used as dependencies of other recipes.

### Parallel execution

`just` has two separate ways to enable parallel execution of tasks.

Run the given recipes on the command line in parallel:

```sh
$ just --parallel recipe_1 recipe_2 recipe_3
[...]
```

And using the `[parallel]` attribute, task dependencies are allowed to run in
parallel:

```just
recipe_1:
sleep 1

recipe_2:
sleep 2

[parallel]
foo: recipe_1 recipe_2
echo hello
```

### Quiet Recipes

A recipe name may be prefixed with `@` to invert the meaning of `@` before each line:
Expand Down
2 changes: 1 addition & 1 deletion completions/just.bash
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ _just() {

case "${cmd}" in
just)
opts=" -n -q -u -v -e -l -h -V -f -d -c -s --check --yes --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --unstable --verbose --changelog --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --command-color --dump-format --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show --dotenv-filename --dotenv-path <ARGUMENTS>... "
opts=" -n -p -q -u -v -e -l -h -V -f -d -c -s --check --yes --dry-run --highlight --no-dotenv --no-highlight --parallel --quiet --shell-command --clear-shell-args --unsorted --unstable --verbose --changelog --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --command-color --dump-format --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show --dotenv-filename --dotenv-path <ARGUMENTS>... "
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
Expand Down
2 changes: 2 additions & 0 deletions completions/just.elvish
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ edit:completion:arg-completer[just] = [@words]{
cand --highlight 'Highlight echoed recipe lines in bold'
cand --no-dotenv 'Don''t load `.env` file'
cand --no-highlight 'Don''t highlight echoed recipe lines in bold'
cand -p 'run given tasks in parallel'
cand --parallel 'run given tasks in parallel'
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'
Expand Down
1 change: 1 addition & 0 deletions completions/just.fish
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ complete -c just -n "__fish_use_subcommand" -s n -l dry-run -d 'Print what just
complete -c just -n "__fish_use_subcommand" -l highlight -d 'Highlight echoed recipe lines in bold'
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 p -l parallel -d 'run given tasks in parallel'
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'
Expand Down
2 changes: 2 additions & 0 deletions completions/just.powershell
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
[CompletionResult]::new('--highlight', 'highlight', [CompletionResultType]::ParameterName, 'Highlight echoed recipe lines in bold')
[CompletionResult]::new('--no-dotenv', 'no-dotenv', [CompletionResultType]::ParameterName, 'Don''t load `.env` file')
[CompletionResult]::new('--no-highlight', 'no-highlight', [CompletionResultType]::ParameterName, 'Don''t highlight echoed recipe lines in bold')
[CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'run given tasks in parallel')
[CompletionResult]::new('--parallel', 'parallel', [CompletionResultType]::ParameterName, 'run given tasks in parallel')
[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')
Expand Down
2 changes: 2 additions & 0 deletions completions/just.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ _just() {
'--highlight[Highlight echoed recipe lines in bold]' \
'--no-dotenv[Don'\''t load `.env` file]' \
'--no-highlight[Don'\''t highlight echoed recipe lines in bold]' \
'-p[run given tasks in parallel]' \
'--parallel[run given tasks in parallel]' \
'(-n --dry-run)-q[Suppress all output]' \
'(-n --dry-run)--quiet[Suppress all output]' \
'--shell-command[Invoke <COMMAND> with the shell used to run recipe lines and backticks]' \
Expand Down
1 change: 0 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,3 @@ pwd:
# Local Variables:
# mode: makefile
# End:
# vim: set ft=make :
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to remove this?

5 changes: 3 additions & 2 deletions src/alias.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use super::*;
use std::sync::Arc;

/// An alias, e.g. `name := target`
#[derive(Debug, PartialEq, Clone, Serialize)]
pub(crate) struct Alias<'src, T = Rc<Recipe<'src>>> {
pub(crate) struct Alias<'src, T = Arc<Recipe<'src>>> {
pub(crate) attributes: BTreeSet<Attribute>,
pub(crate) name: Name<'src>,
#[serde(
Expand All @@ -17,7 +18,7 @@ impl<'src> Alias<'src, Name<'src>> {
self.name.line
}

pub(crate) fn resolve(self, target: Rc<Recipe<'src>>) -> Alias<'src> {
pub(crate) fn resolve(self, target: Arc<Recipe<'src>>) -> Alias<'src> {
assert_eq!(self.target.lexeme(), target.name.lexeme());

Alias {
Expand Down
9 changes: 5 additions & 4 deletions src/analyzer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::sync::Arc;
use {super::*, CompileErrorKind::*};

#[derive(Default)]
Expand Down Expand Up @@ -87,11 +88,11 @@ impl<'src> Analyzer<'src> {
first: recipes
.values()
.fold(None, |accumulator, next| match accumulator {
None => Some(Rc::clone(next)),
None => Some(Arc::clone(next)),
Some(previous) => Some(if previous.line_number() < next.line_number() {
previous
} else {
Rc::clone(next)
Arc::clone(next)
}),
}),
aliases,
Expand Down Expand Up @@ -190,7 +191,7 @@ impl<'src> Analyzer<'src> {
}

fn resolve_alias(
recipes: &Table<'src, Rc<Recipe<'src>>>,
recipes: &Table<'src, Arc<Recipe<'src>>>,
alias: Alias<'src, Name<'src>>,
) -> CompileResult<'src, Alias<'src>> {
let token = alias.name.token();
Expand All @@ -204,7 +205,7 @@ impl<'src> Analyzer<'src> {

// Make sure the target recipe exists
match recipes.get(alias.target.lexeme()) {
Some(target) => Ok(alias.resolve(Rc::clone(target))),
Some(target) => Ok(alias.resolve(Arc::clone(target))),
None => Err(token.error(UnknownAliasTarget {
alias: alias.name.lexeme(),
target: alias.target.lexeme(),
Expand Down
1 change: 1 addition & 0 deletions src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub(crate) enum Attribute {
NoCd,
NoExitMessage,
Private,
Parallel,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be sorted.

Unix,
Windows,
}
Expand Down
23 changes: 23 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub(crate) struct Config {
pub(crate) list_heading: String,
pub(crate) list_prefix: String,
pub(crate) load_dotenv: bool,
pub(crate) parallel: bool,
pub(crate) search_config: SearchConfig,
pub(crate) shell: Option<String>,
pub(crate) shell_args: Option<Vec<String>>,
Expand Down Expand Up @@ -98,6 +99,7 @@ mod arg {
pub(crate) const LIST_PREFIX: &str = "LIST-PREFIX";
pub(crate) const NO_DOTENV: &str = "NO-DOTENV";
pub(crate) const NO_HIGHLIGHT: &str = "NO-HIGHLIGHT";
pub(crate) const PARALLEL: &str = "PARALLEL";
pub(crate) const QUIET: &str = "QUIET";
pub(crate) const SET: &str = "SET";
pub(crate) const SHELL: &str = "SHELL";
Expand Down Expand Up @@ -225,6 +227,12 @@ impl Config {
.takes_value(true)
.help("Use <JUSTFILE> as justfile"),
)
.arg(
Arg::with_name(arg::PARALLEL)
.short("p")
.long("parallel")
.help("run given tasks in parallel")
)
.arg(
Arg::with_name(arg::QUIET)
.short("q")
Expand Down Expand Up @@ -630,6 +638,7 @@ impl Config {
dotenv_filename: matches.value_of(arg::DOTENV_FILENAME).map(str::to_owned),
dotenv_path: matches.value_of(arg::DOTENV_PATH).map(PathBuf::from),
dry_run: matches.is_present(arg::DRY_RUN),
parallel: matches.is_present(arg::PARALLEL),
dump_format: Self::dump_format_from_matches(matches)?,
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
invocation_directory,
Expand Down Expand Up @@ -685,6 +694,7 @@ mod tests {
args: [$($arg:expr),*],
$(color: $color:expr,)?
$(dry_run: $dry_run:expr,)?
$(parallel: $parallel:expr,)?
$(dump_format: $dump_format:expr,)?
$(highlight: $highlight:expr,)?
$(search_config: $search_config:expr,)?
Expand All @@ -704,6 +714,7 @@ mod tests {
let want = Config {
$(color: $color,)?
$(dry_run: $dry_run,)?
$(parallel: $parallel,)?
$(dump_format: $dump_format,)?
$(highlight: $highlight,)?
$(search_config: $search_config,)?
Expand Down Expand Up @@ -840,6 +851,18 @@ mod tests {
dry_run: true,
}

test! {
name: parallel_long,
args: ["--parallel"],
parallel: true,
}

test! {
name: parallel_short,
args: ["-p"],
parallel: true,
}

error! {
name: dry_run_quiet,
args: ["--dry-run", "--quiet"],
Expand Down
3 changes: 2 additions & 1 deletion src/dependency.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use super::*;
use std::sync::Arc;

#[derive(PartialEq, Debug, Serialize)]
pub(crate) struct Dependency<'src> {
pub(crate) arguments: Vec<Expression<'src>>,
#[serde(serialize_with = "keyed::serialize")]
pub(crate) recipe: Rc<Recipe<'src>>,
pub(crate) recipe: Arc<Recipe<'src>>,
}

impl<'src> Display for Dependency<'src> {
Expand Down
Loading
Loading