Prefix parameters with $ to export to environment (#773)

If a parameter is prefixed with an `$`, it will be exported as an
environment variable.
This commit is contained in:
Casey Rodarmor 2021-03-25 18:35:24 -07:00 committed by GitHub
parent 122c351eba
commit 6f42c8b737
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 68 additions and 8 deletions

View File

@ -757,6 +757,14 @@ test:
cargo test cargo test
``` ```
Parameters prefixed with a `$` will be exported as environment variables:
```make
test $RUST_BACKTRACE="1":
# will print a stack trace if it crashes
cargo test
```
=== Recipe Parameters === Recipe Parameters
Recipes may have parameters. Here recipe `build` has a parameter called `target`: Recipes may have parameters. Here recipe `build` has a parameter called `target`:
@ -872,6 +880,13 @@ search QUERY:
lynx 'https://www.google.com/?q={{QUERY}}' lynx 'https://www.google.com/?q={{QUERY}}'
``` ```
Parameters prefixed with a `$` will be exported as environment variables:
```make
foo $bar:
echo $bar
```
=== Running recipes at the end of a recipe === Running recipes at the end of a recipe
Dependencies of a recipes always run before a recipe starts. That is to say, the dependee always runs before the depender. Dependencies of a recipes always run before a recipe starts. That is to say, the dependee always runs before the depender.

View File

@ -227,7 +227,7 @@ impl<'src, 'run> Evaluator<'src, 'run> {
rest = &rest[1..]; rest = &rest[1..];
value value
}; };
scope.bind(false, parameter.name, value); scope.bind(parameter.export, parameter.name, value);
} }
Ok(scope) Ok(scope)

View File

@ -464,6 +464,7 @@ impl<'src> Lexer<'src> {
match start { match start {
'!' => self.lex_bang(), '!' => self.lex_bang(),
'*' => self.lex_single(Asterisk), '*' => self.lex_single(Asterisk),
'$' => self.lex_single(Dollar),
'@' => self.lex_single(At), '@' => self.lex_single(At),
'[' => self.lex_delimiter(BracketL), '[' => self.lex_delimiter(BracketL),
']' => self.lex_delimiter(BracketR), ']' => self.lex_delimiter(BracketR),
@ -912,6 +913,7 @@ mod tests {
Colon => ":", Colon => ":",
ColonEquals => ":=", ColonEquals => ":=",
Comma => ",", Comma => ",",
Dollar => "$",
Eol => "\n", Eol => "\n",
Equals => "=", Equals => "=",
EqualsEquals => "==", EqualsEquals => "==",
@ -1048,6 +1050,12 @@ mod tests {
tokens: (BraceL, BraceL, BraceL, BraceR, BraceR, BraceR), tokens: (BraceL, BraceL, BraceL, BraceR, BraceR, BraceR),
} }
test! {
name: dollar,
text: "$",
tokens: (Dollar),
}
test! { test! {
name: export_concatination, name: export_concatination,
text: "export foo = 'foo' + 'bar'", text: "export foo = 'foo' + 'bar'",

View File

@ -9,6 +9,8 @@ pub(crate) struct Parameter<'src> {
pub(crate) kind: ParameterKind, pub(crate) kind: ParameterKind,
/// An optional default expression /// An optional default expression
pub(crate) default: Option<Expression<'src>>, pub(crate) default: Option<Expression<'src>>,
/// Export parameter as environment variable
pub(crate) export: bool,
} }
impl<'src> Display for Parameter<'src> { impl<'src> Display for Parameter<'src> {

View File

@ -568,7 +568,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
let mut positional = Vec::new(); let mut positional = Vec::new();
while self.next_is(Identifier) { while self.next_is(Identifier) || self.next_is(Dollar) {
positional.push(self.parse_parameter(ParameterKind::Singular)?); positional.push(self.parse_parameter(ParameterKind::Singular)?);
} }
@ -620,6 +620,8 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
/// Parse a recipe parameter /// Parse a recipe parameter
fn parse_parameter(&mut self, kind: ParameterKind) -> CompilationResult<'src, Parameter<'src>> { fn parse_parameter(&mut self, kind: ParameterKind) -> CompilationResult<'src, Parameter<'src>> {
let export = self.accepted(Dollar)?;
let name = self.parse_name()?; let name = self.parse_name()?;
let default = if self.accepted(Equals)? { let default = if self.accepted(Equals)? {
@ -632,6 +634,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
name, name,
kind, kind,
default, default,
export,
}) })
} }
@ -1643,7 +1646,10 @@ mod tests {
line: 0, line: 0,
column: 5, column: 5,
width: 1, width: 1,
kind: UnexpectedToken{expected: vec![Asterisk, Colon, Equals, Identifier, Plus], found: Eol}, kind: UnexpectedToken{
expected: vec![Asterisk, Colon, Dollar, Equals, Identifier, Plus],
found: Eol
},
} }
error! { error! {
@ -1728,7 +1734,7 @@ mod tests {
line: 0, line: 0,
column: 6, column: 6,
width: 1, width: 1,
kind: UnexpectedToken{expected: vec![Identifier], found: Colon}, kind: UnexpectedToken{expected: vec![Dollar, Identifier], found: Colon},
} }
error! { error! {
@ -1748,7 +1754,10 @@ mod tests {
line: 0, line: 0,
column: 8, column: 8,
width: 0, width: 0,
kind: UnexpectedToken{expected: vec![Asterisk, Colon, Equals, Identifier, Plus], found: Eof}, kind: UnexpectedToken {
expected: vec![Asterisk, Colon, Dollar, Equals, Identifier, Plus],
found: Eof
},
} }
error! { error! {

View File

@ -15,6 +15,7 @@ pub(crate) enum TokenKind {
Comma, Comma,
Comment, Comment,
Dedent, Dedent,
Dollar,
Eof, Eof,
Eol, Eol,
Equals, Equals,
@ -50,6 +51,7 @@ impl Display for TokenKind {
Comma => "','", Comma => "','",
Comment => "comment", Comment => "comment",
Dedent => "dedent", Dedent => "dedent",
Dollar => "'$'",
Eof => "end of file", Eof => "end of file",
Eol => "end of line", Eol => "end of line",
Equals => "'='", Equals => "'='",

View File

@ -13,6 +13,30 @@ wut:
stderr: "echo $FOO $BAR $ABC\n", stderr: "echo $FOO $BAR $ABC\n",
} }
test! {
name: parameter,
justfile: r#"
wut $FOO='a' BAR='b':
echo $FOO
echo {{BAR}}
if [ -n "${BAR+1}" ]; then echo defined; else echo undefined; fi
"#,
stdout: "a\nb\nundefined\n",
stderr: "echo $FOO\necho b\nif [ -n \"${BAR+1}\" ]; then echo defined; else echo undefined; fi\n",
}
test! {
name: parameter_not_visible_to_backtick,
justfile: r#"
wut $FOO BAR=`if [ -n "${FOO+1}" ]; then echo defined; else echo undefined; fi`:
echo $FOO
echo {{BAR}}
"#,
args: ("wut", "bar"),
stdout: "bar\nundefined\n",
stderr: "echo $FOO\necho undefined\n",
}
test! { test! {
name: override_variable, name: override_variable,
justfile: r#" justfile: r#"

View File

@ -1422,7 +1422,7 @@ test! {
justfile: "foo 'bar'", justfile: "foo 'bar'",
args: ("foo"), args: ("foo"),
stdout: "", stdout: "",
stderr: "error: Expected '*', ':', identifier, or '+', but found raw string stderr: "error: Expected '*', ':', '$', identifier, or '+', but found raw string
| |
1 | foo 'bar' 1 | foo 'bar'
| ^^^^^ | ^^^^^
@ -2050,12 +2050,12 @@ foo a=\t`echo blaaaaaah:
test! { test! {
name: unknown_start_of_token, name: unknown_start_of_token,
justfile: " justfile: "
assembly_source_files = $(wildcard src/arch/$(arch)/*.s) assembly_source_files = %(wildcard src/arch/$(arch)/*.s)
", ",
stderr: r#" stderr: r#"
error: Unknown start of token: error: Unknown start of token:
| |
2 | assembly_source_files = $(wildcard src/arch/$(arch)/*.s) 2 | assembly_source_files = %(wildcard src/arch/$(arch)/*.s)
| ^ | ^
"#, "#,
status: EXIT_FAILURE, status: EXIT_FAILURE,