Deprecate = in assignments, aliases, and exports in favor of := (#413)

This commit is contained in:
Casey Rodarmor 2019-04-18 11:48:02 -07:00 committed by GitHub
parent 1c0dc284fe
commit 0ad5574ecc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 298 additions and 184 deletions

View File

@ -49,23 +49,23 @@ item : recipe
eol : NEWLINE eol : NEWLINE
| COMMENT NEWLINE | COMMENT NEWLINE
assignment : NAME '=' expression eol alias : 'alias' NAME ':=' NAME
alias : 'alias' NAME '=' NAME assignment : NAME ':=' expression eol
export : 'export' assignment export : 'export' assignment
expression : value '+' expression expression : value '+' expression
| value | value
value : NAME '(' arguments? ')' value : NAME '(' sequence? ')'
| STRING | STRING
| RAW_STRING | RAW_STRING
| BACKTICK | BACKTICK
| NAME | NAME
| '(' expression ')' | '(' expression ')'
arguments : expression ',' arguments sequence : expression ',' sequence
| expression ','? | expression ','?
recipe : '@'? NAME parameter* ('+' parameter)? ':' dependencies? body? recipe : '@'? NAME parameter* ('+' parameter)? ':' dependencies? body?

View File

@ -210,7 +210,7 @@ build test deploy lint
Aliases allow recipes to be invoked with alternative names: Aliases allow recipes to be invoked with alternative names:
```make ```make
alias b = build alias b := build
build: build:
echo 'Building!' echo 'Building!'
@ -249,9 +249,9 @@ Available recipes:
Variables, strings, concatenation, and substitution using `{{...}}` are supported: Variables, strings, concatenation, and substitution using `{{...}}` are supported:
```make ```make
version = "0.2.7" version := "0.2.7"
tardir = "awesomesauce-" + version tardir := "awesomesauce-" + version
tarball = tardir + ".tar.gz" tarball := tardir + ".tar.gz"
publish: publish:
rm -f {{tarball}} rm -f {{tarball}}
@ -285,29 +285,29 @@ braces:
Double-quoted strings support escape sequences: Double-quoted strings support escape sequences:
```make ```make
string-with-tab = "\t" string-with-tab := "\t"
string-with-newline = "\n" string-with-newline := "\n"
string-with-carriage-return = "\r" string-with-carriage-return := "\r"
string-with-double-quote = "\"" string-with-double-quote := "\""
string-with-slash = "\\" string-with-slash := "\\"
``` ```
```sh ```sh
$ just --evaluate $ just --evaluate
"tring-with-carriage-return = " "tring-with-carriage-return := "
string-with-double-quote = """ string-with-double-quote := """
string-with-newline = " string-with-newline := "
" "
string-with-slash = "\" string-with-slash := "\"
string-with-tab = " " string-with-tab := " "
``` ```
Single-quoted strings do not recognize escape sequences and may contain line breaks: Single-quoted strings do not recognize escape sequences and may contain line breaks:
```make ```make
escapes = '\t\n\r\"\\' escapes := '\t\n\r\"\\'
line-breaks = 'hello line-breaks := 'hello
this this
is is
a a
@ -318,9 +318,9 @@ string!
```sh ```sh
$ just --evaluate $ just --evaluate
escapes = "\t\n\r\"\\" escapes := "\t\n\r\"\\"
line-breaks = "hello line-breaks := "hello
this this
is is
a a
@ -410,7 +410,7 @@ Starting server with database localhost:6379 on port 1337...
Backticks can be used to store the result of commands: Backticks can be used to store the result of commands:
```make ```make
localhost = `dumpinterfaces | cut -d: -f2 | sed 's/\/.*//' | sed 's/ //g'` localhost := `dumpinterfaces | cut -d: -f2 | sed 's/\/.*//' | sed 's/ //g'`
serve: serve:
./serve {{localhost}} 8080 ./serve {{localhost}} 8080
@ -421,7 +421,7 @@ serve:
Variables can be overridden from the command line. Variables can be overridden from the command line.
```make ```make
os = "linux" os := "linux"
test: build test: build
./test --test {{os}} ./test --test {{os}}
@ -457,7 +457,7 @@ $ just --set os bsd
Assignments prefixed with the `export` keyword will be exported to recipes as environment variables: Assignments prefixed with the `export` keyword will be exported to recipes as environment variables:
```make ```make
export RUST_BACKTRACE = "1" export RUST_BACKTRACE := "1"
test: test:
# will print a stack trace if it crashes # will print a stack trace if it crashes
@ -487,7 +487,7 @@ cd my-awesome-project && make
Parameters may have default values: Parameters may have default values:
```make ```make
default = 'all' default := 'all'
test target tests=default: test target tests=default:
@echo 'Testing {{target}}:{{tests}}...' @echo 'Testing {{target}}:{{tests}}...'
@ -513,7 +513,7 @@ Testing server:unit...
Default values may be arbitrary expressions, but concatenations must be parenthesized: Default values may be arbitrary expressions, but concatenations must be parenthesized:
```make ```make
arch = "wasm" arch := "wasm"
test triple=(arch + "-unknown-unknown"): test triple=(arch + "-unknown-unknown"):
./test {{triple}} ./test {{triple}}

View File

@ -2,9 +2,9 @@
# ^ A shebang isn't required, but allows a justfile to be executed # ^ A shebang isn't required, but allows a justfile to be executed
# like a script, with `./justfile test`, for example. # like a script, with `./justfile test`, for example.
bt='0' bt = '0'
export RUST_BACKTRACE=bt export RUST_BACKTRACE = bt
alias t = test alias t = test

View File

@ -10,6 +10,6 @@ pub struct Alias<'a> {
impl<'a> Display for Alias<'a> { impl<'a> Display for Alias<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "alias {} = {}", self.name, self.target) write!(f, "alias {} := {}", self.name, self.target)
} }
} }

View File

@ -76,6 +76,10 @@ impl Color {
self.restyle(Style::new().fg(Red).bold()) self.restyle(Style::new().fg(Red).bold())
} }
pub fn warning(self) -> Color {
self.restyle(Style::new().fg(Yellow).bold())
}
pub fn banner(self) -> Color { pub fn banner(self) -> Color {
self.restyle(Style::new().fg(Cyan).bold()) self.restyle(Style::new().fg(Cyan).bold())
} }

View File

@ -6,6 +6,7 @@ pub struct Justfile<'a> {
pub assignments: BTreeMap<&'a str, Expression<'a>>, pub assignments: BTreeMap<&'a str, Expression<'a>>,
pub exports: BTreeSet<&'a str>, pub exports: BTreeSet<&'a str>,
pub aliases: BTreeMap<&'a str, Alias<'a>>, pub aliases: BTreeMap<&'a str, Alias<'a>>,
pub deprecated_equals: bool,
} }
impl<'a> Justfile<'a> where { impl<'a> Justfile<'a> where {
@ -80,7 +81,7 @@ impl<'a> Justfile<'a> where {
} }
for (name, value) in scope { for (name, value) in scope {
println!("{0:1$} = \"{2}\"", name, width, value); println!("{0:1$} := \"{2}\"", name, width, value);
} }
return Ok(()); return Ok(());
} }
@ -175,7 +176,7 @@ impl<'a> Display for Justfile<'a> {
if self.exports.contains(name) { if self.exports.contains(name) {
write!(f, "export ")?; write!(f, "export ")?;
} }
write!(f, "{} = {}", name, expression)?; write!(f, "{} := {}", name, expression)?;
items -= 1; items -= 1;
if items != 0 { if items != 0 {
write!(f, "\n\n")?; write!(f, "\n\n")?;

View File

@ -323,7 +323,7 @@ impl<'a> Lexer<'a> {
'@' => self.lex_single(At), '@' => self.lex_single(At),
'=' => self.lex_single(Equals), '=' => self.lex_single(Equals),
',' => self.lex_single(Comma), ',' => self.lex_single(Comma),
':' => self.lex_single(Colon), ':' => self.lex_colon(),
'(' => self.lex_single(ParenL), '(' => self.lex_single(ParenL),
')' => self.lex_single(ParenR), ')' => self.lex_single(ParenR),
'{' => self.lex_brace_l(), '{' => self.lex_brace_l(),
@ -442,6 +442,20 @@ impl<'a> Lexer<'a> {
Ok(()) Ok(())
} }
/// Lex a token starting with ':'
fn lex_colon(&mut self) -> CompilationResult<'a, ()> {
self.advance()?;
if let Some('=') = self.next {
self.advance()?;
self.token(ColonEquals);
} else {
self.token(Colon);
}
Ok(())
}
/// Lex a token starting with '{' /// Lex a token starting with '{'
fn lex_brace_l(&mut self) -> CompilationResult<'a, ()> { fn lex_brace_l(&mut self) -> CompilationResult<'a, ()> {
if !self.rest_starts_with("{{") { if !self.rest_starts_with("{{") {

View File

@ -12,6 +12,7 @@ pub struct Parser<'a> {
exports: BTreeSet<&'a str>, exports: BTreeSet<&'a str>,
aliases: BTreeMap<&'a str, Alias<'a>>, aliases: BTreeMap<&'a str, Alias<'a>>,
alias_tokens: BTreeMap<&'a str, Token<'a>>, alias_tokens: BTreeMap<&'a str, Token<'a>>,
deprecated_equals: bool,
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
@ -31,6 +32,7 @@ impl<'a> Parser<'a> {
exports: empty(), exports: empty(),
aliases: empty(), aliases: empty(),
alias_tokens: empty(), alias_tokens: empty(),
deprecated_equals: false,
text, text,
} }
} }
@ -152,10 +154,10 @@ impl<'a> Parser<'a> {
} }
if let Some(token) = self.expect(Colon) { if let Some(token) = self.expect(Colon) {
// if we haven't accepted any parameters, an equals // if we haven't accepted any parameters, a :=
// would have been fine as part of an assignment // would have been fine as part of an assignment
if parameters.is_empty() { if parameters.is_empty() {
return Err(self.unexpected_token(&token, &[Name, Plus, Colon, Equals])); return Err(self.unexpected_token(&token, &[Name, Plus, Colon, ColonEquals]));
} else { } else {
return Err(self.unexpected_token(&token, &[Name, Plus, Colon])); return Err(self.unexpected_token(&token, &[Name, Plus, Colon]));
} }
@ -420,6 +422,10 @@ impl<'a> Parser<'a> {
if token.lexeme() == "export" { if token.lexeme() == "export" {
let next = self.tokens.next().unwrap(); let next = self.tokens.next().unwrap();
if next.kind == Name && self.accepted(Equals) { if next.kind == Name && self.accepted(Equals) {
self.deprecated_equals = true;
self.assignment(next, true)?;
doc = None;
} else if next.kind == Name && self.accepted(ColonEquals) {
self.assignment(next, true)?; self.assignment(next, true)?;
doc = None; doc = None;
} else { } else {
@ -430,6 +436,10 @@ impl<'a> Parser<'a> {
} else if token.lexeme() == "alias" { } else if token.lexeme() == "alias" {
let next = self.tokens.next().unwrap(); let next = self.tokens.next().unwrap();
if next.kind == Name && self.accepted(Equals) { if next.kind == Name && self.accepted(Equals) {
self.deprecated_equals = true;
self.alias(next)?;
doc = None;
} else if next.kind == Name && self.accepted(ColonEquals) {
self.alias(next)?; self.alias(next)?;
doc = None; doc = None;
} else { } else {
@ -438,6 +448,10 @@ impl<'a> Parser<'a> {
doc = None; doc = None;
} }
} else if self.accepted(Equals) { } else if self.accepted(Equals) {
self.deprecated_equals = true;
self.assignment(token, false)?;
doc = None;
} else if self.accepted(ColonEquals) {
self.assignment(token, false)?; self.assignment(token, false)?;
doc = None; doc = None;
} else { } else {
@ -501,6 +515,7 @@ impl<'a> Parser<'a> {
assignments: self.assignments, assignments: self.assignments,
exports: self.exports, exports: self.exports,
aliases: self.aliases, aliases: self.aliases,
deprecated_equals: self.deprecated_equals,
}) })
} }
} }
@ -604,10 +619,10 @@ foo a='b\t':
summary_test! { summary_test! {
parse_export, parse_export,
r#" r#"
export a = "hello" export a := "hello"
"#, "#,
r#"export a = "hello""#, r#"export a := "hello""#,
} }
summary_test! { summary_test! {
@ -615,9 +630,9 @@ export a = "hello"
r#" r#"
foo: foo:
echo a echo a
alias f = foo alias f := foo
"#, "#,
r#"alias f = foo r#"alias f := foo
foo: foo:
echo a"# echo a"#
@ -626,11 +641,11 @@ foo:
summary_test! { summary_test! {
parse_alias_before_target, parse_alias_before_target,
r#" r#"
alias f = foo alias f := foo
foo: foo:
echo a echo a
"#, "#,
r#"alias f = foo r#"alias f := foo
foo: foo:
echo a"# echo a"#
@ -639,11 +654,11 @@ foo:
summary_test! { summary_test! {
parse_alias_with_comment, parse_alias_with_comment,
r#" r#"
alias f = foo #comment alias f := foo #comment
foo: foo:
echo a echo a
"#, "#,
r#"alias f = foo r#"alias f := foo
foo: foo:
echo a"# echo a"#
@ -655,9 +670,9 @@ foo:
x: x:
y: y:
z: z:
foo = \"xx\" foo := \"xx\"
bar = foo bar := foo
goodbye = \"y\" goodbye := \"y\"
hello a b c : x y z #hello hello a b c : x y z #hello
#! blah #! blah
#blarg #blarg
@ -666,11 +681,11 @@ hello a b c : x y z #hello
2 2
3 3
", ",
"bar = foo "bar := foo
foo = \"xx\" foo := \"xx\"
goodbye = \"y\" goodbye := \"y\"
hello a b c: x y z hello a b c: x y z
#! blah #! blah
@ -690,14 +705,14 @@ z:"
summary_test! { summary_test! {
parse_shebang, parse_shebang,
" "
practicum = 'hello' practicum := 'hello'
install: install:
\t#!/bin/sh \t#!/bin/sh
\tif [[ -f {{practicum}} ]]; then \tif [[ -f {{practicum}} ]]; then
\t\treturn \t\treturn
\tfi \tfi
", ",
"practicum = 'hello' "practicum := 'hello'
install: install:
#!/bin/sh #!/bin/sh
@ -714,27 +729,27 @@ install:
summary_test! { summary_test! {
parse_assignments, parse_assignments,
r#"a = "0" r#"a := "0"
c = a + b + a + b c := a + b + a + b
b = "1" b := "1"
"#, "#,
r#"a = "0" r#"a := "0"
b = "1" b := "1"
c = a + b + a + b"#, c := a + b + a + b"#,
} }
summary_test! { summary_test! {
parse_assignment_backticks, parse_assignment_backticks,
"a = `echo hello` "a := `echo hello`
c = a + b + a + b c := a + b + a + b
b = `echo goodbye`", b := `echo goodbye`",
"a = `echo hello` "a := `echo hello`
b = `echo goodbye` b := `echo goodbye`
c = a + b + a + b", c := a + b + a + b",
} }
summary_test! { summary_test! {
@ -753,14 +768,14 @@ c = a + b + a + b",
summary_test! { summary_test! {
string_quote_escape, string_quote_escape,
r#"a = "hello\"""#, r#"a := "hello\"""#,
r#"a = "hello\"""#, r#"a := "hello\"""#,
} }
summary_test! { summary_test! {
string_escapes, string_escapes,
r#"a = "\n\t\r\"\\""#, r#"a := "\n\t\r\"\\""#,
r#"a = "\n\t\r\"\\""#, r#"a := "\n\t\r\"\\""#,
} }
summary_test! { summary_test! {
@ -774,11 +789,11 @@ c = a + b + a + b",
summary_test! { summary_test! {
unary_functions, unary_functions,
" "
x = arch() x := arch()
a: a:
{{os()}} {{os_family()}}", {{os()}} {{os_family()}}",
"x = arch() "x := arch()
a: a:
{{os()}} {{os_family()}}", {{os()}} {{os_family()}}",
@ -787,11 +802,11 @@ a:
summary_test! { summary_test! {
env_functions, env_functions,
r#" r#"
x = env_var('foo',) x := env_var('foo',)
a: a:
{{env_var_or_default('foo' + 'bar', 'baz',)}} {{env_var(env_var("baz"))}}"#, {{env_var_or_default('foo' + 'bar', 'baz',)}} {{env_var(env_var("baz"))}}"#,
r#"x = env_var('foo') r#"x := env_var('foo')
a: a:
{{env_var_or_default('foo' + 'bar', 'baz')}} {{env_var(env_var("baz"))}}"#, {{env_var_or_default('foo' + 'bar', 'baz')}} {{env_var(env_var("baz"))}}"#,
@ -832,10 +847,10 @@ f x=(`echo hello` + "foo"):
summary_test! { summary_test! {
parameter_default_concatination_variable, parameter_default_concatination_variable,
r#" r#"
x = "10" x := "10"
f y=(`echo hello` + x) +z="foo": f y=(`echo hello` + x) +z="foo":
"#, "#,
r#"x = "10" r#"x := "10"
f y=(`echo hello` + x) +z="foo":"#, f y=(`echo hello` + x) +z="foo":"#,
} }
@ -843,24 +858,24 @@ f y=(`echo hello` + x) +z="foo":"#,
summary_test! { summary_test! {
parameter_default_multiple, parameter_default_multiple,
r#" r#"
x = "10" x := "10"
f y=(`echo hello` + x) +z=("foo" + "bar"): f y=(`echo hello` + x) +z=("foo" + "bar"):
"#, "#,
r#"x = "10" r#"x := "10"
f y=(`echo hello` + x) +z=("foo" + "bar"):"#, f y=(`echo hello` + x) +z=("foo" + "bar"):"#,
} }
summary_test! { summary_test! {
concatination_in_group, concatination_in_group,
"x = ('0' + '1')", "x := ('0' + '1')",
"x = ('0' + '1')", "x := ('0' + '1')",
} }
summary_test! { summary_test! {
string_in_group, string_in_group,
"x = ('0' )", "x := ('0' )",
"x = ('0')", "x := ('0')",
} }
#[rustfmt::skip] #[rustfmt::skip]

View File

@ -321,6 +321,24 @@ pub fn run() {
} }
}); });
if justfile.deprecated_equals {
let warning = color.warning().stderr();
let message = color.message().stderr();
eprintln!(
"{}",
warning.paint(
"warning: `=` in assignments, exports, and aliases is being phased out on favor of `:=`"
)
);
eprintln!(
"{}",
message
.paint("Please see this issue for more details: https://github.com/casey/just/issues/379")
);
}
if matches.is_present("SUMMARY") { if matches.is_present("SUMMARY") {
if justfile.count() == 0 { if justfile.count() == 0 {
eprintln!("Justfile contains no recipes."); eprintln!("Justfile contains no recipes.");

View File

@ -16,6 +16,7 @@ pub fn token_summary(tokens: &[Token]) -> String {
At => "@", At => "@",
Backtick => "`", Backtick => "`",
Colon => ":", Colon => ":",
ColonEquals => ":=",
Comma => ",", Comma => ",",
Comment => "#", Comment => "#",
Dedent => "<", Dedent => "<",

View File

@ -5,6 +5,7 @@ pub enum TokenKind {
At, At,
Backtick, Backtick,
Colon, Colon,
ColonEquals,
Comma, Comma,
Comment, Comment,
Dedent, Dedent,
@ -35,6 +36,7 @@ impl Display for TokenKind {
At => "'@'", At => "'@'",
Backtick => "backtick", Backtick => "backtick",
Colon => "':'", Colon => "':'",
ColonEquals => "':='",
Comma => "','", Comma => "','",
Comment => "comment", Comment => "comment",
Dedent => "dedent", Dedent => "dedent",

View File

@ -157,7 +157,7 @@ fn integration_test(
integration_test! { integration_test! {
name: alias_listing, name: alias_listing,
justfile: "foo:\n echo foo\nalias f = foo", justfile: "foo:\n echo foo\nalias f := foo",
args: ("--list"), args: ("--list"),
stdin: "", stdin: "",
stdout: "Available recipes: stdout: "Available recipes:
@ -170,7 +170,7 @@ integration_test! {
integration_test! { integration_test! {
name: alias_listing_multiple_aliases, name: alias_listing_multiple_aliases,
justfile: "foo:\n echo foo\nalias f = foo\nalias fo = foo", justfile: "foo:\n echo foo\nalias f := foo\nalias fo := foo",
args: ("--list"), args: ("--list"),
stdin: "", stdin: "",
stdout: "Available recipes: stdout: "Available recipes:
@ -184,7 +184,7 @@ integration_test! {
integration_test! { integration_test! {
name: alias_listing_parameters, name: alias_listing_parameters,
justfile: "foo PARAM='foo':\n echo {{PARAM}}\nalias f = foo", justfile: "foo PARAM='foo':\n echo {{PARAM}}\nalias f := foo",
args: ("--list"), args: ("--list"),
stdin: "", stdin: "",
stdout: "Available recipes: stdout: "Available recipes:
@ -197,7 +197,7 @@ integration_test! {
integration_test! { integration_test! {
name: alias_listing_private, name: alias_listing_private,
justfile: "foo PARAM='foo':\n echo {{PARAM}}\nalias _f = foo", justfile: "foo PARAM='foo':\n echo {{PARAM}}\nalias _f := foo",
args: ("--list"), args: ("--list"),
stdin: "", stdin: "",
stdout: "Available recipes: stdout: "Available recipes:
@ -209,7 +209,7 @@ integration_test! {
integration_test! { integration_test! {
name: alias, name: alias,
justfile: "foo:\n echo foo\nalias f = foo", justfile: "foo:\n echo foo\nalias f := foo",
args: ("f"), args: ("f"),
stdin: "", stdin: "",
stdout: "foo\n", stdout: "foo\n",
@ -219,7 +219,7 @@ integration_test! {
integration_test! { integration_test! {
name: alias_with_parameters, name: alias_with_parameters,
justfile: "foo value='foo':\n echo {{value}}\nalias f = foo", justfile: "foo value='foo':\n echo {{value}}\nalias f := foo",
args: ("f", "bar"), args: ("f", "bar"),
stdin: "", stdin: "",
stdout: "bar\n", stdout: "bar\n",
@ -229,7 +229,7 @@ integration_test! {
integration_test! { integration_test! {
name: alias_with_dependencies, name: alias_with_dependencies,
justfile: "foo:\n echo foo\nbar: foo\nalias b = bar", justfile: "foo:\n echo foo\nbar: foo\nalias b := bar",
args: ("b"), args: ("b"),
stdin: "", stdin: "",
stdout: "foo\n", stdout: "foo\n",
@ -239,13 +239,13 @@ integration_test! {
integration_test! { integration_test! {
name: duplicate_alias, name: duplicate_alias,
justfile: "alias foo = bar\nalias foo = baz\n", justfile: "alias foo := bar\nalias foo := baz\n",
args: (), args: (),
stdin: "", stdin: "",
stdout: "" , stdout: "" ,
stderr: "error: Alias `foo` first defined on line `1` is redefined on line `2` stderr: "error: Alias `foo` first defined on line `1` is redefined on line `2`
| |
2 | alias foo = baz 2 | alias foo := baz
| ^^^ | ^^^
", ",
status: EXIT_FAILURE, status: EXIT_FAILURE,
@ -253,13 +253,13 @@ integration_test! {
integration_test! { integration_test! {
name: unknown_alias_target, name: unknown_alias_target,
justfile: "alias foo = bar\n", justfile: "alias foo := bar\n",
args: (), args: (),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Alias `foo` has an unknown target `bar` stderr: "error: Alias `foo` has an unknown target `bar`
| |
1 | alias foo = bar 1 | alias foo := bar
| ^^^ | ^^^
", ",
status: EXIT_FAILURE, status: EXIT_FAILURE,
@ -267,13 +267,13 @@ integration_test! {
integration_test! { integration_test! {
name: alias_shadows_recipe, name: alias_shadows_recipe,
justfile: "bar:\n echo bar\nalias foo = bar\nfoo:\n echo foo", justfile: "bar:\n echo bar\nalias foo := bar\nfoo:\n echo foo",
args: (), args: (),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Alias `foo` defined on `3` shadows recipe defined on `4` stderr: "error: Alias `foo` defined on `3` shadows recipe defined on `4`
| |
3 | alias foo = bar 3 | alias foo := bar
| ^^^ | ^^^
", ",
status: EXIT_FAILURE, status: EXIT_FAILURE,
@ -387,8 +387,8 @@ c:
integration_test! { integration_test! {
name: show, name: show,
justfile: r#"hello = "foo" justfile: r#"hello := "foo"
bar = hello + hello bar := hello + hello
recipe: recipe:
echo {{hello + "bar" + bar}}"#, echo {{hello + "bar" + bar}}"#,
args: ("--show", "recipe"), args: ("--show", "recipe"),
@ -431,7 +431,7 @@ integration_test! {
integration_test! { integration_test! {
name: backtick_success, name: backtick_success,
justfile: "a = `printf Hello,`\nbar:\n printf '{{a + `printf ' world.'`}}'", justfile: "a := `printf Hello,`\nbar:\n printf '{{a + `printf ' world.'`}}'",
args: (), args: (),
stdin: "", stdin: "",
stdout: "Hello, world.", stdout: "Hello, world.",
@ -441,7 +441,7 @@ integration_test! {
integration_test! { integration_test! {
name: backtick_trimming, name: backtick_trimming,
justfile: "a = `echo Hello,`\nbar:\n echo '{{a + `echo ' world.'`}}'", justfile: "a := `echo Hello,`\nbar:\n echo '{{a + `echo ' world.'`}}'",
args: (), args: (),
stdin: "", stdin: "",
stdout: "Hello, world.\n", stdout: "Hello, world.\n",
@ -451,21 +451,21 @@ integration_test! {
integration_test! { integration_test! {
name: backtick_code_assignment, name: backtick_code_assignment,
justfile: "b = a\na = `exit 100`\nbar:\n echo '{{`exit 200`}}'", justfile: "b := a\na := `exit 100`\nbar:\n echo '{{`exit 200`}}'",
args: (), args: (),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Backtick failed with exit code 100 stderr: "error: Backtick failed with exit code 100
| |
2 | a = `exit 100` 2 | a := `exit 100`
| ^^^^^^^^^^ | ^^^^^^^^^^
", ",
status: 100, status: 100,
} }
integration_test! { integration_test! {
name: backtick_code_interpolation, name: backtick_code_interpolation,
justfile: "b = a\na = `echo hello`\nbar:\n echo '{{`exit 200`}}'", justfile: "b := a\na := `echo hello`\nbar:\n echo '{{`exit 200`}}'",
args: (), args: (),
stdin: "", stdin: "",
stdout: "", stdout: "",
@ -477,7 +477,6 @@ integration_test! {
status: 200, status: 200,
} }
// 😬鎌
integration_test! { integration_test! {
name: backtick_code_interpolation_mod, name: backtick_code_interpolation_mod,
justfile: "f:\n 無{{`exit 200`}}", justfile: "f:\n 無{{`exit 200`}}",
@ -579,7 +578,7 @@ backtick-fail:
integration_test! { integration_test! {
name: backtick_code_long, name: backtick_code_long,
justfile: "\n\n\n\n\n\nb = a\na = `echo hello`\nbar:\n echo '{{`exit 200`}}'", justfile: "\n\n\n\n\n\nb := a\na := `echo hello`\nbar:\n echo '{{`exit 200`}}'",
args: (), args: (),
stdin: "", stdin: "",
stdout: "", stdout: "",
@ -629,14 +628,14 @@ integration_test! {
justfile: "foo: justfile: "foo:
echo hello echo hello
echo {{`exit 111`}} echo {{`exit 111`}}
a = `exit 222`", a := `exit 222`",
args: (), args: (),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Backtick failed with exit code 222 stderr: "error: Backtick failed with exit code 222
| |
4 | a = `exit 222` 4 | a := `exit 222`
| ^^^^^^^^^^ | ^^^^^^^^^^
", ",
status: 222, status: 222,
} }
@ -646,7 +645,7 @@ integration_test! {
justfile: "foo: justfile: "foo:
echo hello echo hello
echo {{`exit 111`}} echo {{`exit 111`}}
a = `exit 222`", a := `exit 222`",
args: ("--set", "foo", "bar", "--set", "baz", "bob", "--set", "a", "b", "a", "b"), args: ("--set", "foo", "bar", "--set", "baz", "bob", "--set", "a", "b", "a", "b"),
stdin: "", stdin: "",
stdout: "", stdout: "",
@ -660,7 +659,7 @@ integration_test! {
justfile: "foo: justfile: "foo:
echo hello echo hello
echo {{`exit 111`}} echo {{`exit 111`}}
a = `exit 222`", a := `exit 222`",
args: ("foo=bar", "baz=bob", "a=b", "a", "b"), args: ("foo=bar", "baz=bob", "a=b", "a", "b"),
stdin: "", stdin: "",
stdout: "", stdout: "",
@ -674,7 +673,7 @@ integration_test! {
justfile: "foo: justfile: "foo:
echo hello echo hello
echo {{`exit 111`}} echo {{`exit 111`}}
a = `exit 222`", a := `exit 222`",
args: ("foo=bar", "a=b", "a", "b"), args: ("foo=bar", "a=b", "a", "b"),
stdin: "", stdin: "",
stdout: "", stdout: "",
@ -685,9 +684,9 @@ a = `exit 222`",
integration_test! { integration_test! {
name: overrides_first, name: overrides_first,
justfile: r#" justfile: r#"
foo = "foo" foo := "foo"
a = "a" a := "a"
baz = "baz" baz := "baz"
recipe arg: recipe arg:
echo arg={{arg}} echo arg={{arg}}
@ -702,9 +701,9 @@ recipe arg:
integration_test! { integration_test! {
name: overrides_not_evaluated, name: overrides_not_evaluated,
justfile: r#" justfile: r#"
foo = `exit 1` foo := `exit 1`
a = "a" a := "a"
baz = "baz" baz := "baz"
recipe arg: recipe arg:
echo arg={{arg}} echo arg={{arg}}
@ -719,7 +718,7 @@ recipe arg:
integration_test! { integration_test! {
name: dry_run, name: dry_run,
justfile: r#" justfile: r#"
var = `echo stderr 1>&2; echo backtick` var := `echo stderr 1>&2; echo backtick`
command: command:
@touch /this/is/not/a/file @touch /this/is/not/a/file
@ -748,20 +747,20 @@ echo `echo command interpolation`
integration_test! { integration_test! {
name: evaluate, name: evaluate,
justfile: r#" justfile: r#"
foo = "a\t" foo := "a\t"
hello = "c" hello := "c"
bar = "b\t" bar := "b\t"
ab = foo + bar + hello ab := foo + bar + hello
wut: wut:
touch /this/is/not/a/file touch /this/is/not/a/file
"#, "#,
args: ("--evaluate"), args: ("--evaluate"),
stdin: "", stdin: "",
stdout: r#"ab = "a b c" stdout: r#"ab := "a b c"
bar = "b " bar := "b "
foo = "a " foo := "a "
hello = "c" hello := "c"
"#, "#,
stderr: "", stderr: "",
status: EXIT_SUCCESS, status: EXIT_SUCCESS,
@ -770,10 +769,10 @@ hello = "c"
integration_test! { integration_test! {
name: export_success, name: export_success,
justfile: r#" justfile: r#"
export FOO = "a" export FOO := "a"
baz = "c" baz := "c"
export BAR = "b" export BAR := "b"
export ABC = FOO + BAR + baz export ABC := FOO + BAR + baz
wut: wut:
echo $FOO $BAR $ABC echo $FOO $BAR $ABC
@ -788,10 +787,10 @@ wut:
integration_test! { integration_test! {
name: export_override, name: export_override,
justfile: r#" justfile: r#"
export FOO = "a" export FOO := "a"
baz = "c" baz := "c"
export BAR = "b" export BAR := "b"
export ABC = FOO + "-" + BAR + "-" + baz export ABC := FOO + "-" + BAR + "-" + baz
wut: wut:
echo $FOO $BAR $ABC echo $FOO $BAR $ABC
@ -806,10 +805,10 @@ wut:
integration_test! { integration_test! {
name: export_shebang, name: export_shebang,
justfile: r#" justfile: r#"
export FOO = "a" export FOO := "a"
baz = "c" baz := "c"
export BAR = "b" export BAR := "b"
export ABC = FOO + BAR + baz export ABC := FOO + BAR + baz
wut: wut:
#!/bin/sh #!/bin/sh
@ -825,7 +824,7 @@ wut:
integration_test! { integration_test! {
name: export_recipe_backtick, name: export_recipe_backtick,
justfile: r#" justfile: r#"
export EXPORTED_VARIABLE = "A-IS-A" export EXPORTED_VARIABLE := "A-IS-A"
recipe: recipe:
echo {{`echo recipe $EXPORTED_VARIABLE`}} echo {{`echo recipe $EXPORTED_VARIABLE`}}
@ -840,7 +839,7 @@ recipe:
integration_test! { integration_test! {
name: raw_string, name: raw_string,
justfile: r#" justfile: r#"
export EXPORTED_VARIABLE = '\z' export EXPORTED_VARIABLE := '\z'
recipe: recipe:
printf "$EXPORTED_VARIABLE" printf "$EXPORTED_VARIABLE"
@ -931,7 +930,7 @@ default:
integration_test! { integration_test! {
name: quiet_flag_no_assignment_backtick_stderr, name: quiet_flag_no_assignment_backtick_stderr,
justfile: r#" justfile: r#"
a = `echo hello 1>&2` a := `echo hello 1>&2`
default: default:
exit 100 exit 100
"#, "#,
@ -1056,39 +1055,39 @@ integration_test! {
integration_test! { integration_test! {
name: color_always, name: color_always,
justfile: "b = a\na = `exit 100`\nbar:\n echo '{{`exit 200`}}'", justfile: "b := a\na := `exit 100`\nbar:\n echo '{{`exit 200`}}'",
args: ("--color", "always"), args: ("--color", "always"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "\u{1b}[1;31merror:\u{1b}[0m \u{1b}[1mBacktick failed with exit code 100 stderr: "\u{1b}[1;31merror:\u{1b}[0m \u{1b}[1mBacktick failed with exit code 100
\u{1b}[0m |\n2 | a = `exit 100`\n | \u{1b}[1;31m^^^^^^^^^^\u{1b}[0m\n", \u{1b}[0m |\n2 | a := `exit 100`\n | \u{1b}[1;31m^^^^^^^^^^\u{1b}[0m\n",
status: 100, status: 100,
} }
integration_test! { integration_test! {
name: color_never, name: color_never,
justfile: "b = a\na = `exit 100`\nbar:\n echo '{{`exit 200`}}'", justfile: "b := a\na := `exit 100`\nbar:\n echo '{{`exit 200`}}'",
args: ("--color", "never"), args: ("--color", "never"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Backtick failed with exit code 100 stderr: "error: Backtick failed with exit code 100
| |
2 | a = `exit 100` 2 | a := `exit 100`
| ^^^^^^^^^^ | ^^^^^^^^^^
", ",
status: 100, status: 100,
} }
integration_test! { integration_test! {
name: color_auto, name: color_auto,
justfile: "b = a\na = `exit 100`\nbar:\n echo '{{`exit 200`}}'", justfile: "b := a\na := `exit 100`\nbar:\n echo '{{`exit 200`}}'",
args: ("--color", "auto"), args: ("--color", "auto"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Backtick failed with exit code 100 stderr: "error: Backtick failed with exit code 100
| |
2 | a = `exit 100` 2 | a := `exit 100`
| ^^^^^^^^^^ | ^^^^^^^^^^
", ",
status: 100, status: 100,
} }
@ -1432,9 +1431,9 @@ foo:
integration_test! { integration_test! {
name: test_os_arch_functions_in_expression, name: test_os_arch_functions_in_expression,
justfile: r#" justfile: r#"
a = arch() a := arch()
o = os() o := os()
f = os_family() f := os_family()
foo: foo:
echo {{a}} {{o}} {{f}} echo {{a}} {{o}} {{f}}
@ -1450,9 +1449,9 @@ foo:
integration_test! { integration_test! {
name: env_var_functions, name: env_var_functions,
justfile: r#" justfile: r#"
p = env_var('USER') p := env_var('USER')
b = env_var_or_default('ZADDY', 'HTAP') b := env_var_or_default('ZADDY', 'HTAP')
x = env_var_or_default('XYZ', 'ABC') x := env_var_or_default('XYZ', 'ABC')
foo: foo:
/bin/echo '{{p}}' '{{b}}' '{{x}}' /bin/echo '{{p}}' '{{b}}' '{{x}}'
@ -1468,9 +1467,9 @@ foo:
integration_test! { integration_test! {
name: env_var_functions, name: env_var_functions,
justfile: r#" justfile: r#"
p = env_var('USERNAME') p := env_var('USERNAME')
b = env_var_or_default('ZADDY', 'HTAP') b := env_var_or_default('ZADDY', 'HTAP')
x = env_var_or_default('XYZ', 'ABC') x := env_var_or_default('XYZ', 'ABC')
foo: foo:
/bin/echo '{{p}}' '{{b}}' '{{x}}' /bin/echo '{{p}}' '{{b}}' '{{x}}'
@ -1573,7 +1572,7 @@ c: b a
integration_test! { integration_test! {
name: parameter_shadows_variable, name: parameter_shadows_variable,
justfile: "FOO = 'hello'\na FOO:", justfile: "FOO := 'hello'\na FOO:",
args: ("a"), args: ("a"),
stdin: "", stdin: "",
stdout: "", stdout: "",
@ -1587,15 +1586,15 @@ integration_test! {
integration_test! { integration_test! {
name: unknown_function_in_assignment, name: unknown_function_in_assignment,
justfile: r#"foo = foo() + "hello" justfile: r#"foo := foo() + "hello"
bar:"#, bar:"#,
args: ("bar"), args: ("bar"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: r#"error: Call to unknown function `foo` stderr: r#"error: Call to unknown function `foo`
| |
1 | foo = foo() + "hello" 1 | foo := foo() + "hello"
| ^^^ | ^^^
"#, "#,
status: EXIT_FAILURE, status: EXIT_FAILURE,
} }
@ -1659,13 +1658,13 @@ integration_test! {
integration_test! { integration_test! {
name: duplicate_variable, name: duplicate_variable,
justfile: "a = 'hello'\na = 'hello'\nfoo:", justfile: "a := 'hello'\na := 'hello'\nfoo:",
args: ("foo"), args: ("foo"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Variable `a` has multiple definitions stderr: "error: Variable `a` has multiple definitions
| |
2 | a = 'hello' 2 | a := 'hello'
| ^ | ^
", ",
status: EXIT_FAILURE, status: EXIT_FAILURE,
@ -1691,7 +1690,7 @@ integration_test! {
args: ("foo"), args: ("foo"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Expected name, '+', ':', or '=', but found raw string stderr: "error: Expected name, '+', ':', or ':=', but found raw string
| |
1 | foo 'bar' 1 | foo 'bar'
| ^^^^^ | ^^^^^
@ -1729,13 +1728,13 @@ integration_test! {
integration_test! { integration_test! {
name: variable_self_dependency, name: variable_self_dependency,
justfile: "z = z\na:", justfile: "z := z\na:",
args: ("a"), args: ("a"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Variable `z` is defined in terms of itself stderr: "error: Variable `z` is defined in terms of itself
| |
1 | z = z 1 | z := z
| ^ | ^
", ",
status: EXIT_FAILURE, status: EXIT_FAILURE,
@ -1743,13 +1742,13 @@ integration_test! {
integration_test! { integration_test! {
name: variable_circular_dependency, name: variable_circular_dependency,
justfile: "x = y\ny = z\nz = x\na:", justfile: "x := y\ny := z\nz := x\na:",
args: ("a"), args: ("a"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: Variable `x` depends on its own value: `x -> y -> z -> x` stderr: "error: Variable `x` depends on its own value: `x -> y -> z -> x`
| |
1 | x = y 1 | x := y
| ^ | ^
", ",
status: EXIT_FAILURE, status: EXIT_FAILURE,
@ -1757,15 +1756,15 @@ integration_test! {
integration_test! { integration_test! {
name: invalid_escape_sequence, name: invalid_escape_sequence,
justfile: r#"x = "\q" justfile: r#"x := "\q"
a:"#, a:"#,
args: ("a"), args: ("a"),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: "error: `\\q` is not a valid escape sequence stderr: "error: `\\q` is not a valid escape sequence
| |
1 | x = \"\\q\" 1 | x := \"\\q\"
| ^^^^ | ^^^^
", ",
status: EXIT_FAILURE, status: EXIT_FAILURE,
} }
@ -1773,7 +1772,7 @@ a:"#,
integration_test! { integration_test! {
name: multiline_raw_string, name: multiline_raw_string,
justfile: " justfile: "
string = 'hello string := 'hello
whatever' whatever'
a: a:
@ -1793,7 +1792,7 @@ whatever'
integration_test! { integration_test! {
name: error_line_after_multiline_raw_string, name: error_line_after_multiline_raw_string,
justfile: " justfile: "
string = 'hello string := 'hello
whatever' + 'yo' whatever' + 'yo'
@ -1814,7 +1813,7 @@ a:
integration_test! { integration_test! {
name: error_column_after_multiline_raw_string, name: error_column_after_multiline_raw_string,
justfile: " justfile: "
string = 'hello string := 'hello
whatever' + bar whatever' + bar
@ -2039,7 +2038,7 @@ integration_test! {
name: comment_before_variable, name: comment_before_variable,
justfile: " justfile: "
# #
A='1' A:='1'
echo: echo:
echo {{A}} echo {{A}}
", ",
@ -2068,7 +2067,7 @@ integration_test! {
name: dotenv_variable_in_backtick, name: dotenv_variable_in_backtick,
justfile: " justfile: "
# #
X=`echo $DOTENV_KEY` X:=`echo $DOTENV_KEY`
echo: echo:
echo {{X}} echo {{X}}
", ",
@ -2097,8 +2096,8 @@ integration_test! {
name: dotenv_variable_in_function_in_backtick, name: dotenv_variable_in_function_in_backtick,
justfile: " justfile: "
# #
X=env_var_or_default('DOTENV_KEY', 'foo') X:=env_var_or_default('DOTENV_KEY', 'foo')
Y=env_var('DOTENV_KEY') Y:=env_var('DOTENV_KEY')
echo: echo:
echo {{X}} echo {{X}}
echo {{Y}} echo {{Y}}
@ -2113,15 +2112,15 @@ echo:
integration_test! { integration_test! {
name: invalid_escape_sequence_message, name: invalid_escape_sequence_message,
justfile: r#" justfile: r#"
X = "\'" X := "\'"
"#, "#,
args: (), args: (),
stdin: "", stdin: "",
stdout: "", stdout: "",
stderr: r#"error: `\'` is not a valid escape sequence stderr: r#"error: `\'` is not a valid escape sequence
| |
2 | X = "\'" 2 | X := "\'"
| ^^^^ | ^^^^
"#, "#,
status: EXIT_FAILURE, status: EXIT_FAILURE,
} }
@ -2200,7 +2199,7 @@ foo x=`echo foo`:
integration_test! { integration_test! {
name: default_variable, name: default_variable,
justfile: " justfile: "
y = 'foo' y := 'foo'
foo x=y: foo x=y:
echo {{x}} echo {{x}}
", ",
@ -2292,7 +2291,7 @@ assembly_source_files = $(wildcard src/arch/$(arch)/*.s)
integration_test! { integration_test! {
name: backtick_variable_cat, name: backtick_variable_cat,
justfile: " justfile: "
stdin = `cat` stdin := `cat`
default: default:
echo {{stdin}} echo {{stdin}}
@ -2338,7 +2337,7 @@ default stdin = `cat justfile`:
integration_test! { integration_test! {
name: backtick_variable_read_single, name: backtick_variable_read_single,
justfile: " justfile: "
password = `read PW && echo $PW` password := `read PW && echo $PW`
default: default:
echo {{password}} echo {{password}}
@ -2353,8 +2352,8 @@ default:
integration_test! { integration_test! {
name: backtick_variable_read_multiple, name: backtick_variable_read_multiple,
justfile: " justfile: "
a = `read A && echo $A` a := `read A && echo $A`
b = `read B && echo $B` b := `read B && echo $B`
default: default:
echo {{a}} echo {{a}}
@ -2381,3 +2380,63 @@ default a=`read A && echo $A` b=`read B && echo $B`:
stderr: "echo foo\necho bar\n", stderr: "echo foo\necho bar\n",
status: EXIT_SUCCESS, status: EXIT_SUCCESS,
} }
integration_test! {
name: equals_deprecated_assignment,
justfile: "
foo = 'bar'
default:
echo {{foo}}
",
args: (),
stdin: "",
stdout: "bar\n",
stderr: "warning: `=` in assignments, exports, and aliases is being phased out on favor of `:=`
Please see this issue for more details: https://github.com/casey/just/issues/379
echo bar
",
status: EXIT_SUCCESS,
}
integration_test! {
name: equals_deprecated_export,
justfile: "
export FOO = 'bar'
default:
echo $FOO
",
args: (),
stdin: "",
stdout: "bar\n",
stderr: "warning: `=` in assignments, exports, and aliases is being phased out on favor of `:=`
Please see this issue for more details: https://github.com/casey/just/issues/379
echo $FOO
",
status: EXIT_SUCCESS,
}
integration_test! {
name: equals_deprecated_alias,
justfile: "
alias foo = default
default:
echo default
",
args: ("foo"),
stdin: "",
stdout: "default\n",
stderr: "warning: `=` in assignments, exports, and aliases is being phased out on favor of `:=`
Please see this issue for more details: https://github.com/casey/just/issues/379
echo default
",
status: EXIT_SUCCESS,
}