Require set fallback := true
to enable recipe fallback (#1368)
This commit is contained in:
parent
ca614ad117
commit
28be873dfc
@ -62,6 +62,7 @@ export : 'export' assignment
|
||||
setting : 'set' 'dotenv-load' boolean?
|
||||
| 'set' 'ignore-comments' boolean?
|
||||
| 'set' 'export' boolean?
|
||||
| 'set' 'fallback' boolean?
|
||||
| 'set' 'positional-arguments' boolean?
|
||||
| 'set' 'allow-duplicate-recipes' boolean?
|
||||
| 'set' 'windows-powershell' boolean?
|
||||
|
@ -646,6 +646,7 @@ foo:
|
||||
| `allow-duplicate-recipes` | boolean | False | Allow recipes appearing later in a `justfile` to override earlier recipes with the same name. |
|
||||
| `dotenv-load` | boolean | False | Load a `.env` file, if present. |
|
||||
| `export` | boolean | False | Export all variables as environment variables. |
|
||||
| `fallback` | boolean | False | Search `justfile` in parent directory if the first recipe on the command line is not found. |
|
||||
| `ignore-comments` | boolean | False | Ignore recipe lines beginning with `#`. |
|
||||
| `positional-arguments` | boolean | False | Pass positional arguments. |
|
||||
| `shell` | `[COMMAND, ARGS…]` | - | Set the command used to invoke recipes and evaluate backticks. |
|
||||
@ -2063,8 +2064,10 @@ The `--dump` command can be used with `--dump-format json` to print a JSON repre
|
||||
|
||||
### Falling back to parent `justfile`s
|
||||
|
||||
If a recipe is not found, `just` will look for `justfile`s in the parent
|
||||
directory and up, until it reaches the root directory.
|
||||
If a recipe is not found in a `justfile` and the `fallback` setting is set,
|
||||
`just` will look for `justfile`s in the parent directory and up, until it
|
||||
reaches the root directory. `just` will stop after it reaches a `justfile` in
|
||||
which the `fallback` setting is `false` or unset.
|
||||
|
||||
This feature is currently unstable, and so must be enabled with the
|
||||
`--unstable` flag.
|
||||
@ -2072,6 +2075,7 @@ This feature is currently unstable, and so must be enabled with the
|
||||
As an example, suppose the current directory contains this `justfile`:
|
||||
|
||||
```make
|
||||
set fallback
|
||||
foo:
|
||||
echo foo
|
||||
```
|
||||
|
@ -53,6 +53,9 @@ impl<'src> Analyzer<'src> {
|
||||
Setting::Export(export) => {
|
||||
settings.export = export;
|
||||
}
|
||||
Setting::Fallback(fallback) => {
|
||||
settings.fallback = fallback;
|
||||
}
|
||||
Setting::IgnoreComments(ignore_comments) => {
|
||||
settings.ignore_comments = ignore_comments;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ pub(crate) enum Keyword {
|
||||
DotenvLoad,
|
||||
Else,
|
||||
Export,
|
||||
Fallback,
|
||||
False,
|
||||
If,
|
||||
IgnoreComments,
|
||||
|
@ -227,6 +227,7 @@ impl<'src> Node<'src> for Set<'src> {
|
||||
Setting::AllowDuplicateRecipes(value)
|
||||
| Setting::DotenvLoad(value)
|
||||
| Setting::Export(value)
|
||||
| Setting::Fallback(value)
|
||||
| Setting::PositionalArguments(value)
|
||||
| Setting::WindowsPowerShell(value)
|
||||
| Setting::IgnoreComments(value) => {
|
||||
|
@ -761,8 +761,9 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
Some(Setting::AllowDuplicateRecipes(self.parse_set_bool()?))
|
||||
}
|
||||
Keyword::DotenvLoad => Some(Setting::DotenvLoad(self.parse_set_bool()?)),
|
||||
Keyword::IgnoreComments => Some(Setting::IgnoreComments(self.parse_set_bool()?)),
|
||||
Keyword::Export => Some(Setting::Export(self.parse_set_bool()?)),
|
||||
Keyword::Fallback => Some(Setting::Fallback(self.parse_set_bool()?)),
|
||||
Keyword::IgnoreComments => Some(Setting::IgnoreComments(self.parse_set_bool()?)),
|
||||
Keyword::PositionalArguments => Some(Setting::PositionalArguments(self.parse_set_bool()?)),
|
||||
Keyword::WindowsPowershell => Some(Setting::WindowsPowerShell(self.parse_set_bool()?)),
|
||||
_ => None,
|
||||
|
@ -4,8 +4,9 @@ use super::*;
|
||||
pub(crate) enum Setting<'src> {
|
||||
AllowDuplicateRecipes(bool),
|
||||
DotenvLoad(bool),
|
||||
IgnoreComments(bool),
|
||||
Export(bool),
|
||||
Fallback(bool),
|
||||
IgnoreComments(bool),
|
||||
PositionalArguments(bool),
|
||||
Shell(Shell<'src>),
|
||||
WindowsPowerShell(bool),
|
||||
@ -17,8 +18,9 @@ impl<'src> Display for Setting<'src> {
|
||||
match self {
|
||||
Setting::AllowDuplicateRecipes(value)
|
||||
| Setting::DotenvLoad(value)
|
||||
| Setting::IgnoreComments(value)
|
||||
| Setting::Export(value)
|
||||
| Setting::Fallback(value)
|
||||
| Setting::IgnoreComments(value)
|
||||
| Setting::PositionalArguments(value)
|
||||
| Setting::WindowsPowerShell(value) => write!(f, "{}", value),
|
||||
Setting::Shell(shell) | Setting::WindowsShell(shell) => write!(f, "{}", shell),
|
||||
|
@ -10,6 +10,7 @@ pub(crate) struct Settings<'src> {
|
||||
pub(crate) allow_duplicate_recipes: bool,
|
||||
pub(crate) dotenv_load: Option<bool>,
|
||||
pub(crate) export: bool,
|
||||
pub(crate) fallback: bool,
|
||||
pub(crate) ignore_comments: bool,
|
||||
pub(crate) positional_arguments: bool,
|
||||
pub(crate) shell: Option<Shell<'src>>,
|
||||
|
@ -135,7 +135,7 @@ impl Subcommand {
|
||||
};
|
||||
|
||||
match Self::run_inner(config, loader, arguments, overrides, &search) {
|
||||
Err(err @ Error::UnknownRecipes { .. }) => {
|
||||
Err((err @ Error::UnknownRecipes { .. }, true)) => {
|
||||
match search.justfile.parent().unwrap().parent() {
|
||||
Some(parent) => {
|
||||
unknown_recipes_errors.get_or_insert(err);
|
||||
@ -144,7 +144,7 @@ impl Subcommand {
|
||||
None => return Err(err),
|
||||
}
|
||||
}
|
||||
result => return result,
|
||||
result => return result.map_err(|(err, _fallback)| err),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -155,6 +155,7 @@ impl Subcommand {
|
||||
overrides,
|
||||
&Search::find(&config.search_config, &config.invocation_directory)?,
|
||||
)
|
||||
.map_err(|(err, _fallback)| err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,9 +165,12 @@ impl Subcommand {
|
||||
arguments: &[String],
|
||||
overrides: &BTreeMap<String, String>,
|
||||
search: &Search,
|
||||
) -> Result<(), Error<'src>> {
|
||||
let (_src, _ast, justfile) = Self::compile(config, loader, search)?;
|
||||
justfile.run(config, search, overrides, arguments)
|
||||
) -> Result<(), (Error<'src>, bool)> {
|
||||
let (_src, _ast, justfile) =
|
||||
Self::compile(config, loader, search).map_err(|err| (err, false))?;
|
||||
justfile
|
||||
.run(config, search, overrides, arguments)
|
||||
.map_err(|err| (err, justfile.settings.fallback))
|
||||
}
|
||||
|
||||
fn compile<'src>(
|
||||
|
@ -6,6 +6,40 @@ fn runs_recipe_in_parent_if_not_found_in_current() {
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
baz:
|
||||
echo subdir
|
||||
"
|
||||
}
|
||||
})
|
||||
.justfile(
|
||||
"
|
||||
foo:
|
||||
echo root
|
||||
",
|
||||
)
|
||||
.args(&["--unstable", "foo"])
|
||||
.current_dir("bar")
|
||||
.stderr(format!(
|
||||
"
|
||||
Trying ..{}justfile
|
||||
echo root
|
||||
",
|
||||
MAIN_SEPARATOR
|
||||
))
|
||||
.stdout("root\n")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setting_accepts_value() {
|
||||
Test::new()
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
justfile: "
|
||||
set fallback := true
|
||||
|
||||
baz:
|
||||
echo subdir
|
||||
"
|
||||
@ -36,6 +70,8 @@ fn print_error_from_parent_if_recipe_not_found_in_current() {
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
baz:
|
||||
echo subdir
|
||||
"
|
||||
@ -64,6 +100,8 @@ fn requires_unstable() {
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
baz:
|
||||
echo subdir
|
||||
"
|
||||
@ -83,7 +121,7 @@ fn requires_unstable() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_with_provided_search_directory() {
|
||||
fn requires_setting() {
|
||||
Test::new()
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
@ -99,6 +137,34 @@ fn works_with_provided_search_directory() {
|
||||
echo root
|
||||
",
|
||||
)
|
||||
.args(&["--unstable", "foo"])
|
||||
.current_dir("bar")
|
||||
.status(EXIT_FAILURE)
|
||||
.stderr("error: Justfile does not contain recipe `foo`.\n")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn works_with_provided_search_directory() {
|
||||
Test::new()
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
baz:
|
||||
echo subdir
|
||||
"
|
||||
}
|
||||
})
|
||||
.justfile(
|
||||
"
|
||||
set fallback
|
||||
|
||||
foo:
|
||||
echo root
|
||||
",
|
||||
)
|
||||
.args(&["--unstable", "./foo"])
|
||||
.stdout("root\n")
|
||||
.stderr(format!(
|
||||
@ -118,6 +184,8 @@ fn doesnt_work_with_justfile() {
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
baz:
|
||||
echo subdir
|
||||
"
|
||||
@ -125,6 +193,8 @@ fn doesnt_work_with_justfile() {
|
||||
})
|
||||
.justfile(
|
||||
"
|
||||
set fallback
|
||||
|
||||
foo:
|
||||
echo root
|
||||
",
|
||||
@ -142,6 +212,8 @@ fn doesnt_work_with_justfile_and_working_directory() {
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
baz:
|
||||
echo subdir
|
||||
"
|
||||
@ -149,6 +221,8 @@ fn doesnt_work_with_justfile_and_working_directory() {
|
||||
})
|
||||
.justfile(
|
||||
"
|
||||
set fallback
|
||||
|
||||
foo:
|
||||
echo root
|
||||
",
|
||||
@ -173,6 +247,8 @@ fn prints_correct_error_message_when_recipe_not_found() {
|
||||
.tree(tree! {
|
||||
bar: {
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
bar:
|
||||
echo subdir
|
||||
"
|
||||
@ -196,3 +272,82 @@ fn prints_correct_error_message_when_recipe_not_found() {
|
||||
))
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_levels_of_fallback_work() {
|
||||
Test::new()
|
||||
.tree(tree! {
|
||||
a: {
|
||||
b: {
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
foo:
|
||||
echo subdir
|
||||
"
|
||||
},
|
||||
justfile: "
|
||||
set fallback
|
||||
|
||||
bar:
|
||||
echo subdir
|
||||
"
|
||||
}
|
||||
})
|
||||
.justfile(
|
||||
"
|
||||
baz:
|
||||
echo root
|
||||
",
|
||||
)
|
||||
.args(&["--unstable", "baz"])
|
||||
.current_dir("a/b")
|
||||
.stdout("root\n")
|
||||
.stderr(format!(
|
||||
"
|
||||
Trying ..{}justfile
|
||||
Trying ..{}..{}justfile
|
||||
echo root
|
||||
",
|
||||
MAIN_SEPARATOR, MAIN_SEPARATOR, MAIN_SEPARATOR
|
||||
))
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stop_fallback_when_fallback_is_false() {
|
||||
Test::new()
|
||||
.tree(tree! {
|
||||
a: {
|
||||
b: {
|
||||
justfile: "
|
||||
set fallback
|
||||
foo:
|
||||
echo subdir
|
||||
"
|
||||
},
|
||||
justfile: "
|
||||
bar:
|
||||
echo subdir
|
||||
"
|
||||
}
|
||||
})
|
||||
.justfile(
|
||||
"
|
||||
baz:
|
||||
echo root
|
||||
",
|
||||
)
|
||||
.args(&["--unstable", "baz"])
|
||||
.current_dir("a/b")
|
||||
.stderr(format!(
|
||||
"
|
||||
Trying ..{}justfile
|
||||
error: Justfile does not contain recipe `baz`.
|
||||
Did you mean `bar`?
|
||||
",
|
||||
MAIN_SEPARATOR
|
||||
))
|
||||
.status(EXIT_FAILURE)
|
||||
.run();
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ fn alias() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"ignore_comments": false,
|
||||
@ -72,6 +73,7 @@ fn assignment() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -115,6 +117,7 @@ fn body() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -168,6 +171,7 @@ fn dependencies() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -258,6 +262,7 @@ fn dependency_argument() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -312,6 +317,7 @@ fn duplicate_recipes() {
|
||||
"allow_duplicate_recipes": true,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -348,6 +354,7 @@ fn doc_comment() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -372,6 +379,7 @@ fn empty_justfile() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -505,6 +513,7 @@ fn parameters() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -577,6 +586,7 @@ fn priors() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -613,6 +623,7 @@ fn private() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -649,6 +660,7 @@ fn quiet() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -676,6 +688,7 @@ fn settings() {
|
||||
"
|
||||
set dotenv-load
|
||||
set export
|
||||
set fallback
|
||||
set positional-arguments
|
||||
set ignore-comments
|
||||
set shell := ['a', 'b', 'c']
|
||||
@ -704,6 +717,7 @@ fn settings() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": true,
|
||||
"export": true,
|
||||
"fallback": true,
|
||||
"ignore_comments": true,
|
||||
"positional_arguments": true,
|
||||
"shell": {
|
||||
@ -746,6 +760,7 @@ fn shebang() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"ignore_comments": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
@ -782,6 +797,7 @@ fn simple() {
|
||||
"allow_duplicate_recipes": false,
|
||||
"dotenv_load": null,
|
||||
"export": false,
|
||||
"fallback": false,
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"ignore_comments": false,
|
||||
|
Loading…
Reference in New Issue
Block a user