Add OS Configuration Attributes (#1387)
This commit is contained in:
parent
c834fb1e4e
commit
73777f7183
82
README.md
82
README.md
@ -1057,9 +1057,7 @@ Done!
|
|||||||
#### System Information
|
#### System Information
|
||||||
|
|
||||||
- `arch()` — Instruction set architecture. Possible values are: `"aarch64"`, `"arm"`, `"asmjs"`, `"hexagon"`, `"mips"`, `"msp430"`, `"powerpc"`, `"powerpc64"`, `"s390x"`, `"sparc"`, `"wasm32"`, `"x86"`, `"x86_64"`, and `"xcore"`.
|
- `arch()` — Instruction set architecture. Possible values are: `"aarch64"`, `"arm"`, `"asmjs"`, `"hexagon"`, `"mips"`, `"msp430"`, `"powerpc"`, `"powerpc64"`, `"s390x"`, `"sparc"`, `"wasm32"`, `"x86"`, `"x86_64"`, and `"xcore"`.
|
||||||
|
|
||||||
- `os()` — Operating system. Possible values are: `"android"`, `"bitrig"`, `"dragonfly"`, `"emscripten"`, `"freebsd"`, `"haiku"`, `"ios"`, `"linux"`, `"macos"`, `"netbsd"`, `"openbsd"`, `"solaris"`, and `"windows"`.
|
- `os()` — Operating system. Possible values are: `"android"`, `"bitrig"`, `"dragonfly"`, `"emscripten"`, `"freebsd"`, `"haiku"`, `"ios"`, `"linux"`, `"macos"`, `"netbsd"`, `"openbsd"`, `"solaris"`, and `"windows"`.
|
||||||
|
|
||||||
- `os_family()` — Operating system family; possible values are: `"unix"` and `"windows"`.
|
- `os_family()` — Operating system family; possible values are: `"unix"` and `"windows"`.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
@ -1143,67 +1141,47 @@ The executable is at: /bin/just
|
|||||||
|
|
||||||
#### String Manipulation
|
#### String Manipulation
|
||||||
|
|
||||||
- `capitalize(s)`<sup>1.7.0</sup> - Convert first character of `s` to uppercase and the rest to lowercase.
|
|
||||||
|
|
||||||
- `kebabcase(s)`<sup>1.7.0</sup> - Convert `s` to `kebab-case`.
|
|
||||||
|
|
||||||
- `lowercamelcase(s)`<sup>1.7.0</sup> - Convert `s` to `lowerCamelCase`.
|
|
||||||
|
|
||||||
- `lowercase(s)` - Convert `s` to lowercase.
|
|
||||||
|
|
||||||
- `quote(s)` - Replace all single quotes with `'\''` and prepend and append single quotes to `s`. This is sufficient to escape special characters for many shells, including most Bourne shell descendants.
|
- `quote(s)` - Replace all single quotes with `'\''` and prepend and append single quotes to `s`. This is sufficient to escape special characters for many shells, including most Bourne shell descendants.
|
||||||
|
|
||||||
- `replace(s, from, to)` - Replace all occurrences of `from` in `s` to `to`.
|
- `replace(s, from, to)` - Replace all occurrences of `from` in `s` to `to`.
|
||||||
|
|
||||||
- `shoutykebabcase(s)`<sup>1.7.0</sup> - Convert `s` to `SHOUTY-KEBAB-CASE`.
|
|
||||||
|
|
||||||
- `shoutysnakecase(s)`<sup>1.7.0</sup> - Convert `s` to `SHOUTY_SNAKE_CASE`.
|
|
||||||
|
|
||||||
- `snakecase(s)`<sup>1.7.0</sup> - Convert `s` to `snake_case`.
|
|
||||||
|
|
||||||
- `titlecase(s)`<sup>1.7.0</sup> - Convert `s` to `Title Case`.
|
|
||||||
|
|
||||||
- `trim(s)` - Remove leading and trailing whitespace from `s`.
|
- `trim(s)` - Remove leading and trailing whitespace from `s`.
|
||||||
|
|
||||||
- `trim_end(s)` - Remove trailing whitespace from `s`.
|
- `trim_end(s)` - Remove trailing whitespace from `s`.
|
||||||
|
|
||||||
- `trim_end_match(s, pat)` - Remove suffix of `s` matching `pat`.
|
- `trim_end_match(s, pat)` - Remove suffix of `s` matching `pat`.
|
||||||
|
|
||||||
- `trim_end_matches(s, pat)` - Repeatedly remove suffixes of `s` matching `pat`.
|
- `trim_end_matches(s, pat)` - Repeatedly remove suffixes of `s` matching `pat`.
|
||||||
|
|
||||||
- `trim_start(s)` - Remove leading whitespace from `s`.
|
- `trim_start(s)` - Remove leading whitespace from `s`.
|
||||||
|
|
||||||
- `trim_start_match(s, pat)` - Remove prefix of `s` matching `pat`.
|
- `trim_start_match(s, pat)` - Remove prefix of `s` matching `pat`.
|
||||||
|
|
||||||
- `trim_start_matches(s, pat)` - Repeatedly remove prefixes of `s` matching `pat`.
|
- `trim_start_matches(s, pat)` - Repeatedly remove prefixes of `s` matching `pat`.
|
||||||
|
|
||||||
|
#### Case Conversion
|
||||||
|
|
||||||
|
- `capitalize(s)`<sup>1.7.0</sup> - Convert first character of `s` to uppercase and the rest to lowercase.
|
||||||
|
- `kebabcase(s)`<sup>1.7.0</sup> - Convert `s` to `kebab-case`.
|
||||||
|
- `lowercamelcase(s)`<sup>1.7.0</sup> - Convert `s` to `lowerCamelCase`.
|
||||||
|
- `lowercase(s)` - Convert `s` to lowercase.
|
||||||
|
- `shoutykebabcase(s)`<sup>1.7.0</sup> - Convert `s` to `SHOUTY-KEBAB-CASE`.
|
||||||
|
- `shoutysnakecase(s)`<sup>1.7.0</sup> - Convert `s` to `SHOUTY_SNAKE_CASE`.
|
||||||
|
- `snakecase(s)`<sup>1.7.0</sup> - Convert `s` to `snake_case`.
|
||||||
|
- `titlecase(s)`<sup>1.7.0</sup> - Convert `s` to `Title Case`.
|
||||||
|
- `uppercamelcase(s)`<sup>1.7.0</sup> - Convert `s` to `UpperCamelCase`.
|
||||||
- `uppercase(s)` - Convert `s` to uppercase.
|
- `uppercase(s)` - Convert `s` to uppercase.
|
||||||
|
|
||||||
- `uppercamelcase(s)`<sup>1.7.0</sup> - Convert `s` to `UpperCamelCase`.
|
|
||||||
|
|
||||||
#### Path Manipulation
|
#### Path Manipulation
|
||||||
|
|
||||||
##### Fallible
|
##### Fallible
|
||||||
|
|
||||||
- `absolute_path(path)` - Absolute path to relative `path` in the working directory. `absolute_path("./bar.txt")` in directory `/foo` is `/foo/bar.txt`.
|
- `absolute_path(path)` - Absolute path to relative `path` in the working directory. `absolute_path("./bar.txt")` in directory `/foo` is `/foo/bar.txt`.
|
||||||
|
|
||||||
- `extension(path)` - Extension of `path`. `extension("/foo/bar.txt")` is `txt`.
|
- `extension(path)` - Extension of `path`. `extension("/foo/bar.txt")` is `txt`.
|
||||||
|
|
||||||
- `file_name(path)` - File name of `path` with any leading directory components removed. `file_name("/foo/bar.txt")` is `bar.txt`.
|
- `file_name(path)` - File name of `path` with any leading directory components removed. `file_name("/foo/bar.txt")` is `bar.txt`.
|
||||||
|
|
||||||
- `file_stem(path)` - File name of `path` without extension. `file_stem("/foo/bar.txt")` is `bar`.
|
- `file_stem(path)` - File name of `path` without extension. `file_stem("/foo/bar.txt")` is `bar`.
|
||||||
|
|
||||||
- `parent_directory(path)` - Parent directory of `path`. `parent_directory("/foo/bar.txt")` is `/foo`.
|
- `parent_directory(path)` - Parent directory of `path`. `parent_directory("/foo/bar.txt")` is `/foo`.
|
||||||
|
|
||||||
- `without_extension(path)` - `path` without extension. `without_extension("/foo/bar.txt")` is `/foo/bar`.
|
- `without_extension(path)` - `path` without extension. `without_extension("/foo/bar.txt")` is `/foo/bar`.
|
||||||
|
|
||||||
These functions can fail, for example if a path does not have an extension, which will halt execution.
|
These functions can fail, for example if a path does not have an extension, which will halt execution.
|
||||||
|
|
||||||
##### Infallible
|
##### Infallible
|
||||||
|
|
||||||
- `join(a, b…)` - *This function uses `/` on Unix and `\` on Windows, which can be lead to unwanted behavior. The `/` operator, e.g., `a / b`, which always uses `/`, should be considered as a replacement unless `\`s are specifically desired on Windows.* Join path `a` with path `b`. `join("foo/bar", "baz")` is `foo/bar/baz`. Accepts two or more arguments.
|
|
||||||
|
|
||||||
- `clean(path)` - Simplify `path` by removing extra path separators, intermediate `.` components, and `..` where possible. `clean("foo//bar")` is `foo/bar`, `clean("foo/..")` is `.`, `clean("foo/./bar")` is `foo/bar`.
|
- `clean(path)` - Simplify `path` by removing extra path separators, intermediate `.` components, and `..` where possible. `clean("foo//bar")` is `foo/bar`, `clean("foo/..")` is `.`, `clean("foo/./bar")` is `foo/bar`.
|
||||||
|
- `join(a, b…)` - *This function uses `/` on Unix and `\` on Windows, which can be lead to unwanted behavior. The `/` operator, e.g., `a / b`, which always uses `/`, should be considered as a replacement unless `\`s are specifically desired on Windows.* Join path `a` with path `b`. `join("foo/bar", "baz")` is `foo/bar/baz`. Accepts two or more arguments.
|
||||||
|
|
||||||
#### Filesystem Access
|
#### Filesystem Access
|
||||||
|
|
||||||
@ -1219,6 +1197,42 @@ These functions can fail, for example if a path does not have an extension, whic
|
|||||||
- `sha256_file(path)` - Return the SHA-256 hash of the file at `path` as a hexadecimal string.
|
- `sha256_file(path)` - Return the SHA-256 hash of the file at `path` as a hexadecimal string.
|
||||||
- `uuid()` - Return a randomly generated UUID.
|
- `uuid()` - Return a randomly generated UUID.
|
||||||
|
|
||||||
|
### Recipe Attributes
|
||||||
|
|
||||||
|
Recipes may be annotated with attributes that change their behavior.
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| ------------------- | ------------------------------------------------- |
|
||||||
|
| `[no-exit-message]` | Don't print an error message when a recipe fails. |
|
||||||
|
| `[linux]` | Enable recipe on Linux. |
|
||||||
|
| `[macos]` | Enable recipe on MacOS. |
|
||||||
|
| `[unix]` | Enable recipe on Unixes. |
|
||||||
|
| `[windows]` | Enable recipe on Windows. |
|
||||||
|
|
||||||
|
#### Enabling and Disabling Recipes
|
||||||
|
|
||||||
|
The `[linux]`, `[macos]`, `[unix]`, and `[windows]` attributes are
|
||||||
|
configuration attributes. By default, recipes are always enabled. A recipe with
|
||||||
|
one or more configuration attributes will only be enabled when one or more of
|
||||||
|
those configurations is active.
|
||||||
|
|
||||||
|
This can be used to write `justfile`s that behave differently depending on
|
||||||
|
which operating system they run on. The `run` recipe in this `justfile` will
|
||||||
|
compile and run `main.c`, using a different C compiler and using the correct
|
||||||
|
output binary name for that compiler depending on the operating system:
|
||||||
|
|
||||||
|
```make
|
||||||
|
[unix]
|
||||||
|
run:
|
||||||
|
cc main.c
|
||||||
|
./a.out
|
||||||
|
|
||||||
|
[windows]
|
||||||
|
run:
|
||||||
|
cl main.c
|
||||||
|
main.exe
|
||||||
|
```
|
||||||
|
|
||||||
### Command Evaluation Using Backticks
|
### Command Evaluation Using Backticks
|
||||||
|
|
||||||
Backticks can be used to store the result of commands:
|
Backticks can be used to store the result of commands:
|
||||||
|
@ -30,8 +30,10 @@ impl<'src> Analyzer<'src> {
|
|||||||
}
|
}
|
||||||
Item::Comment(_) => (),
|
Item::Comment(_) => (),
|
||||||
Item::Recipe(recipe) => {
|
Item::Recipe(recipe) => {
|
||||||
Self::analyze_recipe(&recipe)?;
|
if recipe.enabled() {
|
||||||
recipes.push(recipe);
|
Self::analyze_recipe(&recipe)?;
|
||||||
|
recipes.push(recipe);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Item::Set(set) => {
|
Item::Set(set) => {
|
||||||
self.analyze_set(&set)?;
|
self.analyze_set(&set)?;
|
||||||
|
@ -1,13 +1,34 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(EnumString)]
|
#[derive(
|
||||||
#[strum(serialize_all = "kebab_case")]
|
EnumString, PartialEq, Debug, Copy, Clone, Serialize, Ord, PartialOrd, Eq, IntoStaticStr,
|
||||||
|
)]
|
||||||
|
#[strum(serialize_all = "kebab-case")]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub(crate) enum Attribute {
|
pub(crate) enum Attribute {
|
||||||
|
Linux,
|
||||||
|
Macos,
|
||||||
NoExitMessage,
|
NoExitMessage,
|
||||||
|
Unix,
|
||||||
|
Windows,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attribute {
|
impl Attribute {
|
||||||
pub(crate) fn from_name(name: Name) -> Option<Attribute> {
|
pub(crate) fn from_name(name: Name) -> Option<Attribute> {
|
||||||
name.lexeme().parse().ok()
|
name.lexeme().parse().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_str(self) -> &'static str {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_str() {
|
||||||
|
assert_eq!(Attribute::NoExitMessage.to_str(), "no-exit-message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,15 @@ impl Display for CompileError<'_> {
|
|||||||
self.token.line.ordinal(),
|
self.token.line.ordinal(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
DuplicateAttribute { attribute, first } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Recipe attribute `{}` first used on line {} is duplicated on line {}",
|
||||||
|
attribute,
|
||||||
|
first.ordinal(),
|
||||||
|
self.token.line.ordinal(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
DuplicateParameter { recipe, parameter } => {
|
DuplicateParameter { recipe, parameter } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
@ -25,6 +25,10 @@ pub(crate) enum CompileErrorKind<'src> {
|
|||||||
alias: &'src str,
|
alias: &'src str,
|
||||||
first: usize,
|
first: usize,
|
||||||
},
|
},
|
||||||
|
DuplicateAttribute {
|
||||||
|
attribute: &'src str,
|
||||||
|
first: usize,
|
||||||
|
},
|
||||||
DuplicateParameter {
|
DuplicateParameter {
|
||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
parameter: &'src str,
|
parameter: &'src str,
|
||||||
|
@ -35,7 +35,7 @@ pub(crate) enum Error<'src> {
|
|||||||
recipe: &'src str,
|
recipe: &'src str,
|
||||||
line_number: Option<usize>,
|
line_number: Option<usize>,
|
||||||
code: i32,
|
code: i32,
|
||||||
suppress_message: bool,
|
print_message: bool,
|
||||||
},
|
},
|
||||||
CommandInvoke {
|
CommandInvoke {
|
||||||
binary: OsString,
|
binary: OsString,
|
||||||
@ -169,11 +169,11 @@ impl<'src> Error<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn suppress_message(&self) -> bool {
|
pub(crate) fn print_message(&self) -> bool {
|
||||||
matches!(
|
!matches!(
|
||||||
self,
|
self,
|
||||||
Error::Code {
|
Error::Code {
|
||||||
suppress_message: true,
|
print_message: false,
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -472,13 +472,13 @@ mod tests {
|
|||||||
recipe,
|
recipe,
|
||||||
line_number,
|
line_number,
|
||||||
code,
|
code,
|
||||||
suppress_message,
|
print_message,
|
||||||
},
|
},
|
||||||
check: {
|
check: {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(code, 200);
|
assert_eq!(code, 200);
|
||||||
assert_eq!(line_number, None);
|
assert_eq!(line_number, None);
|
||||||
assert!(!suppress_message);
|
assert!(print_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,13 +493,13 @@ mod tests {
|
|||||||
recipe,
|
recipe,
|
||||||
line_number,
|
line_number,
|
||||||
code,
|
code,
|
||||||
suppress_message,
|
print_message,
|
||||||
},
|
},
|
||||||
check: {
|
check: {
|
||||||
assert_eq!(recipe, "fail");
|
assert_eq!(recipe, "fail");
|
||||||
assert_eq!(code, 100);
|
assert_eq!(code, 100);
|
||||||
assert_eq!(line_number, Some(2));
|
assert_eq!(line_number, Some(2));
|
||||||
assert!(!suppress_message);
|
assert!(print_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,13 +514,13 @@ mod tests {
|
|||||||
recipe,
|
recipe,
|
||||||
line_number,
|
line_number,
|
||||||
code,
|
code,
|
||||||
suppress_message,
|
print_message,
|
||||||
},
|
},
|
||||||
check: {
|
check: {
|
||||||
assert_eq!(recipe, "a");
|
assert_eq!(recipe, "a");
|
||||||
assert_eq!(code, 150);
|
assert_eq!(code, 150);
|
||||||
assert_eq!(line_number, Some(2));
|
assert_eq!(line_number, Some(2));
|
||||||
assert!(!suppress_message);
|
assert!(print_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,13 +672,13 @@ mod tests {
|
|||||||
error: Code {
|
error: Code {
|
||||||
recipe,
|
recipe,
|
||||||
line_number,
|
line_number,
|
||||||
suppress_message,
|
print_message,
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
check: {
|
check: {
|
||||||
assert_eq!(recipe, "wut");
|
assert_eq!(recipe, "wut");
|
||||||
assert_eq!(line_number, Some(7));
|
assert_eq!(line_number, Some(7));
|
||||||
assert!(!suppress_message);
|
assert!(print_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,20 +345,25 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
items.push(Item::Assignment(self.parse_assignment(false)?));
|
items.push(Item::Assignment(self.parse_assignment(false)?));
|
||||||
} else {
|
} else {
|
||||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||||
items.push(Item::Recipe(self.parse_recipe(doc, false, false)?));
|
items.push(Item::Recipe(self.parse_recipe(
|
||||||
|
doc,
|
||||||
|
false,
|
||||||
|
BTreeSet::new(),
|
||||||
|
)?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if self.accepted(At)? {
|
} else if self.accepted(At)? {
|
||||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||||
items.push(Item::Recipe(self.parse_recipe(doc, true, false)?));
|
items.push(Item::Recipe(self.parse_recipe(
|
||||||
} else if self.accepted(BracketL)? {
|
doc,
|
||||||
let Attribute::NoExitMessage = self.parse_attribute_name()?;
|
true,
|
||||||
self.expect(BracketR)?;
|
BTreeSet::new(),
|
||||||
self.expect_eol()?;
|
)?));
|
||||||
|
} else if let Some(attributes) = self.parse_attributes()? {
|
||||||
let quiet = self.accepted(At)?;
|
let quiet = self.accepted(At)?;
|
||||||
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
|
||||||
items.push(Item::Recipe(self.parse_recipe(doc, quiet, true)?));
|
items.push(Item::Recipe(self.parse_recipe(doc, quiet, attributes)?));
|
||||||
} else {
|
} else {
|
||||||
return Err(self.unexpected_token()?);
|
return Err(self.unexpected_token()?);
|
||||||
}
|
}
|
||||||
@ -602,7 +607,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
doc: Option<&'src str>,
|
doc: Option<&'src str>,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
suppress_exit_error_messages: bool,
|
attributes: BTreeSet<Attribute>,
|
||||||
) -> CompileResult<'src, UnresolvedRecipe<'src>> {
|
) -> CompileResult<'src, UnresolvedRecipe<'src>> {
|
||||||
let name = self.parse_name()?;
|
let name = self.parse_name()?;
|
||||||
|
|
||||||
@ -666,7 +671,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
parameters: positional.into_iter().chain(variadic).collect(),
|
parameters: positional.into_iter().chain(variadic).collect(),
|
||||||
private: name.lexeme().starts_with('_'),
|
private: name.lexeme().starts_with('_'),
|
||||||
shebang: body.first().map_or(false, Line::is_shebang),
|
shebang: body.first().map_or(false, Line::is_shebang),
|
||||||
suppress_exit_error_messages,
|
attributes,
|
||||||
priors,
|
priors,
|
||||||
body,
|
body,
|
||||||
dependencies,
|
dependencies,
|
||||||
@ -831,14 +836,33 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
Ok(Shell { arguments, command })
|
Ok(Shell { arguments, command })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a recipe attribute name
|
/// Parse recipe attributes
|
||||||
fn parse_attribute_name(&mut self) -> CompileResult<'src, Attribute> {
|
fn parse_attributes(&mut self) -> CompileResult<'src, Option<BTreeSet<Attribute>>> {
|
||||||
let name = self.parse_name()?;
|
let mut attributes = BTreeMap::new();
|
||||||
Attribute::from_name(name).ok_or_else(|| {
|
|
||||||
name.error(CompileErrorKind::UnknownAttribute {
|
while self.accepted(BracketL)? {
|
||||||
attribute: name.lexeme(),
|
let name = self.parse_name()?;
|
||||||
})
|
let attribute = Attribute::from_name(name).ok_or_else(|| {
|
||||||
})
|
name.error(CompileErrorKind::UnknownAttribute {
|
||||||
|
attribute: name.lexeme(),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
if let Some(line) = attributes.get(&attribute) {
|
||||||
|
return Err(name.error(CompileErrorKind::DuplicateAttribute {
|
||||||
|
attribute: name.lexeme(),
|
||||||
|
first: *line,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
attributes.insert(attribute, name.line);
|
||||||
|
self.expect(BracketR)?;
|
||||||
|
self.expect_eol()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if attributes.is_empty() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(attributes.into_keys().collect()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ fn error_from_signal(recipe: &str, line_number: Option<usize>, exit_status: Exit
|
|||||||
/// A recipe, e.g. `foo: bar baz`
|
/// A recipe, e.g. `foo: bar baz`
|
||||||
#[derive(PartialEq, Debug, Clone, Serialize)]
|
#[derive(PartialEq, Debug, Clone, Serialize)]
|
||||||
pub(crate) struct Recipe<'src, D = Dependency<'src>> {
|
pub(crate) struct Recipe<'src, D = Dependency<'src>> {
|
||||||
|
pub(crate) attributes: BTreeSet<Attribute>,
|
||||||
pub(crate) body: Vec<Line<'src>>,
|
pub(crate) body: Vec<Line<'src>>,
|
||||||
pub(crate) dependencies: Vec<D>,
|
pub(crate) dependencies: Vec<D>,
|
||||||
pub(crate) doc: Option<&'src str>,
|
pub(crate) doc: Option<&'src str>,
|
||||||
@ -30,7 +31,6 @@ pub(crate) struct Recipe<'src, D = Dependency<'src>> {
|
|||||||
pub(crate) private: bool,
|
pub(crate) private: bool,
|
||||||
pub(crate) quiet: bool,
|
pub(crate) quiet: bool,
|
||||||
pub(crate) shebang: bool,
|
pub(crate) shebang: bool,
|
||||||
pub(crate) suppress_exit_error_messages: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src, D> Recipe<'src, D> {
|
impl<'src, D> Recipe<'src, D> {
|
||||||
@ -66,6 +66,24 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
!self.private
|
!self.private
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enabled(&self) -> bool {
|
||||||
|
let windows = self.attributes.contains(&Attribute::Windows);
|
||||||
|
let linux = self.attributes.contains(&Attribute::Linux);
|
||||||
|
let macos = self.attributes.contains(&Attribute::Macos);
|
||||||
|
let unix = self.attributes.contains(&Attribute::Unix);
|
||||||
|
|
||||||
|
(!windows && !linux && !macos && !unix)
|
||||||
|
|| (cfg!(target_os = "windows") && windows)
|
||||||
|
|| (cfg!(target_os = "linux") && (linux || unix))
|
||||||
|
|| (cfg!(target_os = "macos") && (macos || unix))
|
||||||
|
|| (cfg!(windows) && windows)
|
||||||
|
|| (cfg!(unix) && unix)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_exit_message(&self) -> bool {
|
||||||
|
!self.attributes.contains(&Attribute::NoExitMessage)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn run<'run>(
|
pub(crate) fn run<'run>(
|
||||||
&self,
|
&self,
|
||||||
context: &RecipeContext<'src, 'run>,
|
context: &RecipeContext<'src, 'run>,
|
||||||
@ -192,12 +210,11 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
Ok(exit_status) => {
|
Ok(exit_status) => {
|
||||||
if let Some(code) = exit_status.code() {
|
if let Some(code) = exit_status.code() {
|
||||||
if code != 0 && !infallible_command {
|
if code != 0 && !infallible_command {
|
||||||
let suppress_message = self.suppress_exit_error_messages;
|
|
||||||
return Err(Error::Code {
|
return Err(Error::Code {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
line_number: Some(line_number),
|
line_number: Some(line_number),
|
||||||
code,
|
code,
|
||||||
suppress_message,
|
print_message: self.print_exit_message(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -327,12 +344,11 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
if code == 0 {
|
if code == 0 {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let suppress_message = self.suppress_exit_error_messages;
|
|
||||||
Err(Error::Code {
|
Err(Error::Code {
|
||||||
recipe: self.name(),
|
recipe: self.name(),
|
||||||
line_number: None,
|
line_number: None,
|
||||||
code,
|
code,
|
||||||
suppress_message,
|
print_message: self.print_exit_message(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -353,6 +369,10 @@ impl<'src, D: Display> ColorDisplay for Recipe<'src, D> {
|
|||||||
writeln!(f, "# {}", doc)?;
|
writeln!(f, "# {}", doc)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for attribute in &self.attributes {
|
||||||
|
writeln!(f, "[{}]", attribute.to_str())?;
|
||||||
|
}
|
||||||
|
|
||||||
if self.quiet {
|
if self.quiet {
|
||||||
write!(f, "@{}", self.name)?;
|
write!(f, "@{}", self.name)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -29,7 +29,7 @@ pub fn run() -> Result<(), i32> {
|
|||||||
config
|
config
|
||||||
.and_then(|config| config.run(&loader))
|
.and_then(|config| config.run(&loader))
|
||||||
.map_err(|error| {
|
.map_err(|error| {
|
||||||
if !verbosity.quiet() && !error.suppress_message() {
|
if !verbosity.quiet() && error.print_message() {
|
||||||
eprintln!("{}", error.color_display(color.stderr()));
|
eprintln!("{}", error.color_display(color.stderr()));
|
||||||
}
|
}
|
||||||
error.code().unwrap_or(EXIT_FAILURE)
|
error.code().unwrap_or(EXIT_FAILURE)
|
||||||
|
@ -53,7 +53,7 @@ impl<'src> UnresolvedRecipe<'src> {
|
|||||||
quiet: self.quiet,
|
quiet: self.quiet,
|
||||||
shebang: self.shebang,
|
shebang: self.shebang,
|
||||||
priors: self.priors,
|
priors: self.priors,
|
||||||
suppress_exit_error_messages: self.suppress_exit_error_messages,
|
attributes: self.attributes,
|
||||||
dependencies,
|
dependencies,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
43
tests/attributes.rs
Normal file
43
tests/attributes.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all() {
|
||||||
|
Test::new()
|
||||||
|
.justfile(
|
||||||
|
"
|
||||||
|
[macos]
|
||||||
|
[windows]
|
||||||
|
[linux]
|
||||||
|
[unix]
|
||||||
|
[no-exit-message]
|
||||||
|
foo:
|
||||||
|
exit 1
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.stderr("exit 1\n")
|
||||||
|
.status(1)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn duplicate_attributes_are_disallowed() {
|
||||||
|
Test::new()
|
||||||
|
.justfile(
|
||||||
|
"
|
||||||
|
[no-exit-message]
|
||||||
|
[no-exit-message]
|
||||||
|
foo:
|
||||||
|
echo bar
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.stderr(
|
||||||
|
"
|
||||||
|
error: Recipe attribute `no-exit-message` first used on line 1 is duplicated on line 2
|
||||||
|
|
|
||||||
|
2 | [no-exit-message]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.status(1)
|
||||||
|
.run();
|
||||||
|
}
|
@ -27,6 +27,7 @@ fn alias() {
|
|||||||
"assignments": {},
|
"assignments": {},
|
||||||
"recipes": {
|
"recipes": {
|
||||||
"foo": {
|
"foo": {
|
||||||
|
"attributes": [],
|
||||||
"body": [],
|
"body": [],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"doc": null,
|
"doc": null,
|
||||||
@ -36,7 +37,6 @@ fn alias() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -102,6 +102,7 @@ fn body() {
|
|||||||
"first": "foo",
|
"first": "foo",
|
||||||
"recipes": {
|
"recipes": {
|
||||||
"foo": {
|
"foo": {
|
||||||
|
"attributes": [],
|
||||||
"body": [
|
"body": [
|
||||||
["bar"],
|
["bar"],
|
||||||
["abc", ["xyz"], "def"],
|
["abc", ["xyz"], "def"],
|
||||||
@ -114,7 +115,6 @@ fn body() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -147,6 +147,7 @@ fn dependencies() {
|
|||||||
"first": "foo",
|
"first": "foo",
|
||||||
"recipes": {
|
"recipes": {
|
||||||
"bar": {
|
"bar": {
|
||||||
|
"attributes": [],
|
||||||
"doc": null,
|
"doc": null,
|
||||||
"name": "bar",
|
"name": "bar",
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -159,7 +160,6 @@ fn dependencies() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
|
||||||
},
|
},
|
||||||
"foo": {
|
"foo": {
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -171,7 +171,7 @@ fn dependencies() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -246,7 +246,7 @@ fn dependency_argument() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
},
|
},
|
||||||
"foo": {
|
"foo": {
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -265,7 +265,7 @@ fn dependency_argument() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -322,7 +322,7 @@ fn duplicate_recipes() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -361,7 +361,7 @@ fn doc_comment() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -424,6 +424,7 @@ fn parameters() {
|
|||||||
"assignments": {},
|
"assignments": {},
|
||||||
"recipes": {
|
"recipes": {
|
||||||
"a": {
|
"a": {
|
||||||
|
"attributes": [],
|
||||||
"body": [],
|
"body": [],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"doc": null,
|
"doc": null,
|
||||||
@ -433,7 +434,6 @@ fn parameters() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
|
||||||
},
|
},
|
||||||
"b": {
|
"b": {
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -452,7 +452,7 @@ fn parameters() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
},
|
},
|
||||||
"c": {
|
"c": {
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -471,7 +471,7 @@ fn parameters() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
},
|
},
|
||||||
"d": {
|
"d": {
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -490,7 +490,7 @@ fn parameters() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
},
|
},
|
||||||
"e": {
|
"e": {
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -509,7 +509,7 @@ fn parameters() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
},
|
},
|
||||||
"f": {
|
"f": {
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -528,7 +528,7 @@ fn parameters() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -571,7 +571,7 @@ fn priors() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
},
|
},
|
||||||
"b": {
|
"b": {
|
||||||
"body": [],
|
"body": [],
|
||||||
@ -590,7 +590,7 @@ fn priors() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
"priors": 1,
|
"priors": 1,
|
||||||
},
|
},
|
||||||
@ -603,7 +603,7 @@ fn priors() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
"parameters": [],
|
"parameters": [],
|
||||||
"priors": 0,
|
"priors": 0,
|
||||||
},
|
},
|
||||||
@ -644,7 +644,7 @@ fn private() {
|
|||||||
"private": true,
|
"private": true,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -683,7 +683,7 @@ fn quiet() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": true,
|
"quiet": true,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -741,7 +741,7 @@ fn settings() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": true,
|
"shebang": true,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -786,7 +786,7 @@ fn shebang() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": true,
|
"shebang": true,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -825,7 +825,7 @@ fn simple() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": false,
|
"attributes": [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -858,6 +858,7 @@ fn attribute() {
|
|||||||
"first": "foo",
|
"first": "foo",
|
||||||
"recipes": {
|
"recipes": {
|
||||||
"foo": {
|
"foo": {
|
||||||
|
"attributes": ["no-exit-message"],
|
||||||
"body": [],
|
"body": [],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"doc": null,
|
"doc": null,
|
||||||
@ -867,7 +868,6 @@ fn attribute() {
|
|||||||
"private": false,
|
"private": false,
|
||||||
"quiet": false,
|
"quiet": false,
|
||||||
"shebang": false,
|
"shebang": false,
|
||||||
"suppress_exit_error_messages": true,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
@ -33,6 +33,7 @@ mod test;
|
|||||||
mod allow_duplicate_recipes;
|
mod allow_duplicate_recipes;
|
||||||
mod assert_stdout;
|
mod assert_stdout;
|
||||||
mod assert_success;
|
mod assert_success;
|
||||||
|
mod attributes;
|
||||||
mod byte_order_mark;
|
mod byte_order_mark;
|
||||||
mod changelog;
|
mod changelog;
|
||||||
mod choose;
|
mod choose;
|
||||||
@ -60,6 +61,7 @@ mod line_prefixes;
|
|||||||
mod misc;
|
mod misc;
|
||||||
mod multibyte_char;
|
mod multibyte_char;
|
||||||
mod no_exit_message;
|
mod no_exit_message;
|
||||||
|
mod os_attributes;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod positional_arguments;
|
mod positional_arguments;
|
||||||
mod quiet;
|
mod quiet;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use libc::EXIT_FAILURE;
|
use super::*;
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: recipe_exit_message_suppressed,
|
name: recipe_exit_message_suppressed,
|
||||||
@ -86,7 +86,7 @@ hello:
|
|||||||
@exit 100
|
@exit 100
|
||||||
"#,
|
"#,
|
||||||
stderr: r#"
|
stderr: r#"
|
||||||
error: Expected '@' or identifier, but found comment
|
error: Expected '@', '[', or identifier, but found comment
|
||||||
|
|
|
|
||||||
2 | # This is a doc comment
|
2 | # This is a doc comment
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -103,7 +103,7 @@ test! {
|
|||||||
hello:
|
hello:
|
||||||
@exit 100
|
@exit 100
|
||||||
"#,
|
"#,
|
||||||
stderr: "error: Expected '@' or identifier, but found end of line\n |\n2 | \n | ^\n",
|
stderr: "error: Expected '@', '[', or identifier, but found end of line\n |\n2 | \n | ^\n",
|
||||||
status: EXIT_FAILURE,
|
status: EXIT_FAILURE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
tests/os_attributes.rs
Normal file
103
tests/os_attributes.rs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn os_family() {
|
||||||
|
Test::new()
|
||||||
|
.justfile(
|
||||||
|
"
|
||||||
|
[unix]
|
||||||
|
foo:
|
||||||
|
echo bar
|
||||||
|
|
||||||
|
[windows]
|
||||||
|
foo:
|
||||||
|
echo baz
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.stdout(if cfg!(unix) {
|
||||||
|
"bar\n"
|
||||||
|
} else if cfg!(windows) {
|
||||||
|
"baz\n"
|
||||||
|
} else {
|
||||||
|
panic!("unexpected os family")
|
||||||
|
})
|
||||||
|
.stderr(if cfg!(unix) {
|
||||||
|
"echo bar\n"
|
||||||
|
} else if cfg!(windows) {
|
||||||
|
"echo baz\n"
|
||||||
|
} else {
|
||||||
|
panic!("unexpected os family")
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn os() {
|
||||||
|
Test::new()
|
||||||
|
.justfile(
|
||||||
|
"
|
||||||
|
[macos]
|
||||||
|
foo:
|
||||||
|
echo bar
|
||||||
|
|
||||||
|
[windows]
|
||||||
|
foo:
|
||||||
|
echo baz
|
||||||
|
|
||||||
|
[linux]
|
||||||
|
foo:
|
||||||
|
echo quxx
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.stdout(if cfg!(target_os = "macos") {
|
||||||
|
"bar\n"
|
||||||
|
} else if cfg!(windows) {
|
||||||
|
"baz\n"
|
||||||
|
} else if cfg!(target_os = "linux") {
|
||||||
|
"quxx\n"
|
||||||
|
} else {
|
||||||
|
panic!("unexpected os family")
|
||||||
|
})
|
||||||
|
.stderr(if cfg!(target_os = "macos") {
|
||||||
|
"echo bar\n"
|
||||||
|
} else if cfg!(windows) {
|
||||||
|
"echo baz\n"
|
||||||
|
} else if cfg!(target_os = "linux") {
|
||||||
|
"echo quxx\n"
|
||||||
|
} else {
|
||||||
|
panic!("unexpected os family")
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all() {
|
||||||
|
Test::new()
|
||||||
|
.justfile(
|
||||||
|
"
|
||||||
|
[macos]
|
||||||
|
[windows]
|
||||||
|
[linux]
|
||||||
|
[unix]
|
||||||
|
foo:
|
||||||
|
echo bar
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.stdout("bar\n")
|
||||||
|
.stderr("echo bar\n")
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn none() {
|
||||||
|
Test::new()
|
||||||
|
.justfile(
|
||||||
|
"
|
||||||
|
foo:
|
||||||
|
echo bar
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.stdout("bar\n")
|
||||||
|
.stderr("echo bar\n")
|
||||||
|
.run();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user