Lift limitations on recipes that take parameters (#137)
Previously, only one recipe with parameters could be passed on the command line. This was to avoid confusion in case the number of parameters a recipe took changed, and wound up using as an argument was was once a recipe. However, I don't think this is actually particularly confusing in practice, and could be a slightly annoying limitation. Now, any number of recipes with parameters may be given on the command line. Fixes #70
This commit is contained in:
parent
af543d7258
commit
c6256333ed
@ -239,7 +239,7 @@ build target:
|
||||
cd {{target}} && make
|
||||
```
|
||||
|
||||
Recipes with parameters have limitations. Other recipes may not depend on them, and only one recipe with parameters may be given on the command line.
|
||||
Other recipes may not depend on a recipe with parameters.
|
||||
|
||||
To pass arguments, put them after the recipe name:
|
||||
|
||||
|
@ -911,7 +911,7 @@ foo A B:
|
||||
",
|
||||
255,
|
||||
"",
|
||||
"error: Recipe `foo` got 3 arguments but only takes 2\n",
|
||||
"error: Justfile does not contain recipe `THREE`.\n",
|
||||
);
|
||||
}
|
||||
|
||||
@ -939,7 +939,7 @@ foo A B='B':
|
||||
",
|
||||
255,
|
||||
"",
|
||||
"error: Recipe `foo` got 3 arguments but takes at most 2\n",
|
||||
"error: Justfile does not contain recipe `THREE`.\n",
|
||||
);
|
||||
}
|
||||
|
||||
@ -1537,3 +1537,23 @@ a x y +z:
|
||||
"error: Recipe `a` got 2 arguments but takes at least 3\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn argument_grouping() {
|
||||
integration_test(
|
||||
&["BAR", "0", "FOO", "1", "2", "BAZ", "3", "4", "5"],
|
||||
"
|
||||
FOO A B='blarg':
|
||||
echo foo: {{A}} {{B}}
|
||||
|
||||
BAR X:
|
||||
echo bar: {{X}}
|
||||
|
||||
BAZ +Z:
|
||||
echo baz: {{Z}}
|
||||
",
|
||||
0,
|
||||
"bar: 0\nfoo: 1 2\nbaz: 3 4 5\n",
|
||||
"echo bar: 0\necho foo: 1 2\necho baz: 3 4 5\n",
|
||||
);
|
||||
}
|
||||
|
43
src/lib.rs
43
src/lib.rs
@ -1218,37 +1218,34 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut ran = empty();
|
||||
let mut missing = vec![];
|
||||
let mut grouped = vec![];
|
||||
let mut rest = arguments;
|
||||
|
||||
for (i, argument) in arguments.iter().enumerate() {
|
||||
while let Some((argument, mut tail)) = rest.split_first() {
|
||||
if let Some(recipe) = self.recipes.get(argument) {
|
||||
if !recipe.parameters.is_empty() {
|
||||
if i != 0 {
|
||||
return Err(RunError::NonLeadingRecipeWithParameters{recipe: recipe.name});
|
||||
}
|
||||
let rest = &arguments[1..];
|
||||
if recipe.parameters.is_empty() {
|
||||
grouped.push((recipe, &tail[0..0]));
|
||||
} else {
|
||||
let argument_range = recipe.argument_range();
|
||||
if !contains(&argument_range, rest.len()) {
|
||||
let argument_count = cmp::min(tail.len(), argument_range.end - 1);
|
||||
if !contains(&argument_range, argument_count) {
|
||||
return Err(RunError::ArgumentCountMismatch {
|
||||
recipe: recipe.name,
|
||||
found: rest.len(),
|
||||
found: tail.len(),
|
||||
min: argument_range.start,
|
||||
max: argument_range.end - 1,
|
||||
});
|
||||
}
|
||||
return self.run_recipe(recipe, rest, &scope, &mut ran, options);
|
||||
grouped.push((recipe, &tail[0..argument_count]));
|
||||
tail = &tail[argument_count..];
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
missing.push(*argument);
|
||||
}
|
||||
rest = tail;
|
||||
}
|
||||
|
||||
let mut missing = vec![];
|
||||
for recipe in arguments {
|
||||
if !self.recipes.contains_key(recipe) {
|
||||
missing.push(*recipe);
|
||||
}
|
||||
}
|
||||
if !missing.is_empty() {
|
||||
let suggestion = if missing.len() == 1 {
|
||||
self.suggest(missing.first().unwrap())
|
||||
@ -1257,9 +1254,12 @@ impl<'a, 'b> Justfile<'a> where 'a: 'b {
|
||||
};
|
||||
return Err(RunError::UnknownRecipes{recipes: missing, suggestion: suggestion});
|
||||
}
|
||||
for recipe in arguments.iter().map(|name| &self.recipes[name]) {
|
||||
self.run_recipe(recipe, &[], &scope, &mut ran, options)?;
|
||||
|
||||
let mut ran = empty();
|
||||
for (recipe, arguments) in grouped {
|
||||
self.run_recipe(recipe, arguments, &scope, &mut ran, options)?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1312,7 +1312,6 @@ enum RunError<'a> {
|
||||
Code{recipe: &'a str, line_number: Option<usize>, code: i32},
|
||||
InternalError{message: String},
|
||||
IoError{recipe: &'a str, io_error: io::Error},
|
||||
NonLeadingRecipeWithParameters{recipe: &'a str},
|
||||
Signal{recipe: &'a str, line_number: Option<usize>, signal: i32},
|
||||
TmpdirIoError{recipe: &'a str, io_error: io::Error},
|
||||
UnknownFailure{recipe: &'a str, line_number: Option<usize>},
|
||||
@ -1347,10 +1346,6 @@ impl<'a> Display for RunError<'a> {
|
||||
maybe_s(overrides.len()),
|
||||
And(&overrides.iter().map(Tick).collect::<Vec<_>>()))?;
|
||||
},
|
||||
NonLeadingRecipeWithParameters{recipe} => {
|
||||
write!(f, "Recipe `{}` takes arguments and so must be the first and only recipe \
|
||||
specified on the command line", recipe)?;
|
||||
},
|
||||
ArgumentCountMismatch{recipe, found, min, max} => {
|
||||
if min == max {
|
||||
let expected = min;
|
||||
|
Loading…
Reference in New Issue
Block a user