Ignore additional search path arguments (#1528)
- Revert #1475 - Add a test that arguments with different path prefixes are allowed
This commit is contained in:
parent
6ab6588549
commit
1a5f07c672
12
README.md
12
README.md
@ -2174,18 +2174,6 @@ $ (cd foo && just a b)
|
|||||||
|
|
||||||
And will both invoke recipes `a` and `b` in `foo/justfile`.
|
And will both invoke recipes `a` and `b` in `foo/justfile`.
|
||||||
|
|
||||||
For consistency, it possible to use path prefixes for all recipes:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ just foo/a foo/b
|
|
||||||
```
|
|
||||||
|
|
||||||
But they must match:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ just foo/a bar/b
|
|
||||||
error: Conflicting path arguments: `foo/` and `bar/`
|
|
||||||
```
|
|
||||||
### Include Directives
|
### Include Directives
|
||||||
|
|
||||||
The `!include` directive, currently unstable, can be used to include the
|
The `!include` directive, currently unstable, can be used to include the
|
||||||
|
@ -434,7 +434,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let positional = Positional::from_values(matches.values_of(arg::ARGUMENTS))?;
|
let positional = Positional::from_values(matches.values_of(arg::ARGUMENTS));
|
||||||
|
|
||||||
for (name, value) in positional.overrides {
|
for (name, value) in positional.overrides {
|
||||||
overrides.insert(name.clone(), value.clone());
|
overrides.insert(name.clone(), value.clone());
|
||||||
|
@ -11,8 +11,6 @@ pub(crate) enum ConfigError {
|
|||||||
message
|
message
|
||||||
))]
|
))]
|
||||||
Internal { message: String },
|
Internal { message: String },
|
||||||
#[snafu(display("Conflicting path arguments: `{}` and `{}`", seen, conflicting))]
|
|
||||||
ConflictingSearchDirArgs { seen: String, conflicting: String },
|
|
||||||
#[snafu(display(
|
#[snafu(display(
|
||||||
"Path-prefixed recipes may not be used with `--working-directory` or `--justfile`."
|
"Path-prefixed recipes may not be used with `--working-directory` or `--justfile`."
|
||||||
))]
|
))]
|
||||||
|
@ -36,75 +36,41 @@ pub struct Positional {
|
|||||||
pub arguments: Vec<String>,
|
pub arguments: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum ProcessingStep {
|
|
||||||
Overrides,
|
|
||||||
SearchDir,
|
|
||||||
Arguments,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Positional {
|
impl Positional {
|
||||||
pub(crate) fn from_values<'values>(
|
pub fn from_values<'values>(values: Option<impl IntoIterator<Item = &'values str>>) -> Self {
|
||||||
values: Option<impl IntoIterator<Item = &'values str>>,
|
|
||||||
) -> Result<Self, ConfigError> {
|
|
||||||
let mut overrides = Vec::new();
|
let mut overrides = Vec::new();
|
||||||
let mut search_directory = None;
|
let mut search_directory = None;
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
let mut processing_step = ProcessingStep::Overrides;
|
|
||||||
|
|
||||||
if let Some(values) = values {
|
if let Some(values) = values {
|
||||||
let mut values = values.into_iter().peekable();
|
for value in values {
|
||||||
while let Some(value) = values.peek() {
|
if search_directory.is_none() && arguments.is_empty() {
|
||||||
let value = *value;
|
if let Some(o) = Self::override_from_value(value) {
|
||||||
match processing_step {
|
overrides.push(o);
|
||||||
ProcessingStep::Overrides => {
|
} else if value == "." || value == ".." {
|
||||||
if let Some(o) = Self::override_from_value(value) {
|
search_directory = Some(value.to_owned());
|
||||||
overrides.push(o);
|
} else if let Some(i) = value.rfind('/') {
|
||||||
values.next();
|
let (dir, tail) = value.split_at(i + 1);
|
||||||
} else {
|
|
||||||
processing_step = ProcessingStep::SearchDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ProcessingStep::SearchDir => {
|
|
||||||
if value == "." || value == ".." {
|
|
||||||
search_directory = Some(value.to_owned());
|
|
||||||
values.next();
|
|
||||||
} else if let Some(i) = value.rfind('/') {
|
|
||||||
let (dir, tail) = value.split_at(i + 1);
|
|
||||||
|
|
||||||
if let Some(ref seen) = search_directory {
|
search_directory = Some(dir.to_owned());
|
||||||
if seen != dir {
|
|
||||||
return Err(ConfigError::ConflictingSearchDirArgs {
|
|
||||||
seen: seen.clone(),
|
|
||||||
conflicting: dir.into(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
search_directory = Some(dir.to_owned());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !tail.is_empty() {
|
if !tail.is_empty() {
|
||||||
arguments.push(tail.to_owned());
|
arguments.push(tail.to_owned());
|
||||||
}
|
|
||||||
values.next();
|
|
||||||
} else {
|
|
||||||
processing_step = ProcessingStep::Arguments;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
ProcessingStep::Arguments => {
|
|
||||||
arguments.push(value.to_owned());
|
arguments.push(value.to_owned());
|
||||||
values.next();
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
arguments.push(value.to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Self {
|
||||||
overrides,
|
overrides,
|
||||||
search_directory,
|
search_directory,
|
||||||
arguments,
|
arguments,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an override from a value of the form `NAME=.*`.
|
/// Parse an override from a value of the form `NAME=.*`.
|
||||||
@ -141,7 +107,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
assert_eq! (
|
assert_eq! (
|
||||||
Positional::from_values(Some($vals.iter().cloned())).unwrap(),
|
Positional::from_values(Some($vals.iter().cloned())),
|
||||||
Positional {
|
Positional {
|
||||||
overrides: $overrides
|
overrides: $overrides
|
||||||
.iter()
|
.iter()
|
||||||
@ -259,35 +225,4 @@ mod tests {
|
|||||||
search_directory: None,
|
search_directory: None,
|
||||||
arguments: ["a", "a=b"],
|
arguments: ["a", "a=b"],
|
||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
|
||||||
name: search_dir_and_recipe_only,
|
|
||||||
values: ["some/path/recipe_a"],
|
|
||||||
overrides: [],
|
|
||||||
search_directory: Some("some/path/"),
|
|
||||||
arguments: ["recipe_a"],
|
|
||||||
}
|
|
||||||
|
|
||||||
test! {
|
|
||||||
name: multiple_same_valued_search_directories,
|
|
||||||
values: ["some/path/recipe_a", "some/path/recipe_b"],
|
|
||||||
overrides: [],
|
|
||||||
search_directory: Some("some/path/"),
|
|
||||||
arguments: ["recipe_a", "recipe_b"],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn invalid_multiple_search_paths() {
|
|
||||||
let err = Positional::from_values(Some(
|
|
||||||
[
|
|
||||||
"some/path/recipe_a",
|
|
||||||
"some/path/recipe_b",
|
|
||||||
"other/path/recipe_c",
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.copied(),
|
|
||||||
))
|
|
||||||
.unwrap_err();
|
|
||||||
assert_matches!(err, ConfigError::ConflictingSearchDirArgs { seen, conflicting } if seen == "some/path/" && conflicting == "other/path/");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,77 +1,9 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn same_path_argument() {
|
fn argument_with_different_path_prefix_is_allowed() {
|
||||||
let justfile_contents = unindent(
|
Test::new()
|
||||||
r#"
|
.justfile("foo bar:")
|
||||||
recipe_a:
|
.args(["./foo", "../bar"])
|
||||||
echo "A"
|
.run();
|
||||||
|
|
||||||
recipe_b:
|
|
||||||
echo "B"
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let tmp = temptree! {
|
|
||||||
subdir: {
|
|
||||||
justfile: justfile_contents
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for arg_list in [
|
|
||||||
["subdir/recipe_a", "recipe_b"],
|
|
||||||
["subdir/recipe_a", "subdir/recipe_b"],
|
|
||||||
] {
|
|
||||||
let mut command = Command::new(executable_path("just"));
|
|
||||||
command.current_dir(tmp.path());
|
|
||||||
|
|
||||||
for arg in arg_list {
|
|
||||||
command.arg(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = command.output().unwrap();
|
|
||||||
|
|
||||||
let stdout = String::from_utf8(output.stdout).unwrap();
|
|
||||||
|
|
||||||
assert!(output.status.success());
|
|
||||||
assert_eq!(stdout, "A\nB\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn different_path_arguments() {
|
|
||||||
let justfile_contents1 = unindent(
|
|
||||||
r#"
|
|
||||||
recipe_a:
|
|
||||||
echo "A"
|
|
||||||
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let justfile_contents2 = unindent(
|
|
||||||
r#"
|
|
||||||
recipe_b:
|
|
||||||
echo "B"
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
let tmp = temptree! {
|
|
||||||
subdir: {
|
|
||||||
justfile: justfile_contents1
|
|
||||||
},
|
|
||||||
subdir2: {
|
|
||||||
justfile: justfile_contents2
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let output = Command::new(executable_path("just"))
|
|
||||||
.current_dir(tmp.path())
|
|
||||||
.arg("subdir/recipe_a")
|
|
||||||
.arg("subdir2/recipe_b")
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let stderr = String::from_utf8(output.stderr).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
stderr,
|
|
||||||
"error: Conflicting path arguments: `subdir/` and `subdir2/`\n"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user