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
|
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:
|
To pass arguments, put them after the recipe name:
|
||||||
|
|
||||||
|
@ -911,7 +911,7 @@ foo A B:
|
|||||||
",
|
",
|
||||||
255,
|
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,
|
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",
|
"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(());
|
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 let Some(recipe) = self.recipes.get(argument) {
|
||||||
if !recipe.parameters.is_empty() {
|
if recipe.parameters.is_empty() {
|
||||||
if i != 0 {
|
grouped.push((recipe, &tail[0..0]));
|
||||||
return Err(RunError::NonLeadingRecipeWithParameters{recipe: recipe.name});
|
} else {
|
||||||
}
|
|
||||||
let rest = &arguments[1..];
|
|
||||||
let argument_range = recipe.argument_range();
|
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 {
|
return Err(RunError::ArgumentCountMismatch {
|
||||||
recipe: recipe.name,
|
recipe: recipe.name,
|
||||||
found: rest.len(),
|
found: tail.len(),
|
||||||
min: argument_range.start,
|
min: argument_range.start,
|
||||||
max: argument_range.end - 1,
|
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 {
|
} 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() {
|
if !missing.is_empty() {
|
||||||
let suggestion = if missing.len() == 1 {
|
let suggestion = if missing.len() == 1 {
|
||||||
self.suggest(missing.first().unwrap())
|
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});
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1312,7 +1312,6 @@ enum RunError<'a> {
|
|||||||
Code{recipe: &'a str, line_number: Option<usize>, code: i32},
|
Code{recipe: &'a str, line_number: Option<usize>, code: i32},
|
||||||
InternalError{message: String},
|
InternalError{message: String},
|
||||||
IoError{recipe: &'a str, io_error: io::Error},
|
IoError{recipe: &'a str, io_error: io::Error},
|
||||||
NonLeadingRecipeWithParameters{recipe: &'a str},
|
|
||||||
Signal{recipe: &'a str, line_number: Option<usize>, signal: i32},
|
Signal{recipe: &'a str, line_number: Option<usize>, signal: i32},
|
||||||
TmpdirIoError{recipe: &'a str, io_error: io::Error},
|
TmpdirIoError{recipe: &'a str, io_error: io::Error},
|
||||||
UnknownFailure{recipe: &'a str, line_number: Option<usize>},
|
UnknownFailure{recipe: &'a str, line_number: Option<usize>},
|
||||||
@ -1347,10 +1346,6 @@ impl<'a> Display for RunError<'a> {
|
|||||||
maybe_s(overrides.len()),
|
maybe_s(overrides.len()),
|
||||||
And(&overrides.iter().map(Tick).collect::<Vec<_>>()))?;
|
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} => {
|
ArgumentCountMismatch{recipe, found, min, max} => {
|
||||||
if min == max {
|
if min == max {
|
||||||
let expected = min;
|
let expected = min;
|
||||||
|
Loading…
Reference in New Issue
Block a user