From 0ad5574ecc40891dd653102c78fd56b2c59bcad5 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Thu, 18 Apr 2019 11:48:02 -0700 Subject: [PATCH] Deprecate `=` in assignments, aliases, and exports in favor of `:=` (#413) --- GRAMMAR.md | 8 +- README.adoc | 46 ++++---- justfile | 4 +- src/alias.rs | 2 +- src/color.rs | 4 + src/justfile.rs | 5 +- src/lexer.rs | 16 ++- src/parser.rs | 107 +++++++++-------- src/run.rs | 18 +++ src/testing.rs | 1 + src/token_kind.rs | 2 + tests/integration.rs | 269 ++++++++++++++++++++++++++----------------- 12 files changed, 298 insertions(+), 184 deletions(-) diff --git a/GRAMMAR.md b/GRAMMAR.md index 03efab3..1e21295 100644 --- a/GRAMMAR.md +++ b/GRAMMAR.md @@ -49,23 +49,23 @@ item : recipe eol : NEWLINE | COMMENT NEWLINE -assignment : NAME '=' expression eol +alias : 'alias' NAME ':=' NAME -alias : 'alias' NAME '=' NAME +assignment : NAME ':=' expression eol export : 'export' assignment expression : value '+' expression | value -value : NAME '(' arguments? ')' +value : NAME '(' sequence? ')' | STRING | RAW_STRING | BACKTICK | NAME | '(' expression ')' -arguments : expression ',' arguments +sequence : expression ',' sequence | expression ','? recipe : '@'? NAME parameter* ('+' parameter)? ':' dependencies? body? diff --git a/README.adoc b/README.adoc index 372d63b..9ba698b 100644 --- a/README.adoc +++ b/README.adoc @@ -210,7 +210,7 @@ build test deploy lint Aliases allow recipes to be invoked with alternative names: ```make -alias b = build +alias b := build build: echo 'Building!' @@ -249,9 +249,9 @@ Available recipes: Variables, strings, concatenation, and substitution using `{{...}}` are supported: ```make -version = "0.2.7" -tardir = "awesomesauce-" + version -tarball = tardir + ".tar.gz" +version := "0.2.7" +tardir := "awesomesauce-" + version +tarball := tardir + ".tar.gz" publish: rm -f {{tarball}} @@ -285,29 +285,29 @@ braces: Double-quoted strings support escape sequences: ```make -string-with-tab = "\t" -string-with-newline = "\n" -string-with-carriage-return = "\r" -string-with-double-quote = "\"" -string-with-slash = "\\" +string-with-tab := "\t" +string-with-newline := "\n" +string-with-carriage-return := "\r" +string-with-double-quote := "\"" +string-with-slash := "\\" ``` ```sh $ just --evaluate -"tring-with-carriage-return = " -string-with-double-quote = """ -string-with-newline = " +"tring-with-carriage-return := " +string-with-double-quote := """ +string-with-newline := " " -string-with-slash = "\" -string-with-tab = " " +string-with-slash := "\" +string-with-tab := " " ``` Single-quoted strings do not recognize escape sequences and may contain line breaks: ```make -escapes = '\t\n\r\"\\' +escapes := '\t\n\r\"\\' -line-breaks = 'hello +line-breaks := 'hello this is a @@ -318,9 +318,9 @@ string! ```sh $ just --evaluate -escapes = "\t\n\r\"\\" +escapes := "\t\n\r\"\\" -line-breaks = "hello +line-breaks := "hello this is a @@ -410,7 +410,7 @@ Starting server with database localhost:6379 on port 1337... Backticks can be used to store the result of commands: ```make -localhost = `dumpinterfaces | cut -d: -f2 | sed 's/\/.*//' | sed 's/ //g'` +localhost := `dumpinterfaces | cut -d: -f2 | sed 's/\/.*//' | sed 's/ //g'` serve: ./serve {{localhost}} 8080 @@ -421,7 +421,7 @@ serve: Variables can be overridden from the command line. ```make -os = "linux" +os := "linux" test: build ./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: ```make -export RUST_BACKTRACE = "1" +export RUST_BACKTRACE := "1" test: # will print a stack trace if it crashes @@ -487,7 +487,7 @@ cd my-awesome-project && make Parameters may have default values: ```make -default = 'all' +default := 'all' test target tests=default: @echo 'Testing {{target}}:{{tests}}...' @@ -513,7 +513,7 @@ Testing server:unit... Default values may be arbitrary expressions, but concatenations must be parenthesized: ```make -arch = "wasm" +arch := "wasm" test triple=(arch + "-unknown-unknown"): ./test {{triple}} diff --git a/justfile b/justfile index 2730006..82c9c2a 100755 --- a/justfile +++ b/justfile @@ -2,9 +2,9 @@ # ^ A shebang isn't required, but allows a justfile to be executed # like a script, with `./justfile test`, for example. -bt='0' +bt = '0' -export RUST_BACKTRACE=bt +export RUST_BACKTRACE = bt alias t = test diff --git a/src/alias.rs b/src/alias.rs index ad4e826..b1ae10e 100644 --- a/src/alias.rs +++ b/src/alias.rs @@ -10,6 +10,6 @@ pub struct Alias<'a> { impl<'a> Display for Alias<'a> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "alias {} = {}", self.name, self.target) + write!(f, "alias {} := {}", self.name, self.target) } } diff --git a/src/color.rs b/src/color.rs index c9bb990..196c483 100644 --- a/src/color.rs +++ b/src/color.rs @@ -76,6 +76,10 @@ impl Color { self.restyle(Style::new().fg(Red).bold()) } + pub fn warning(self) -> Color { + self.restyle(Style::new().fg(Yellow).bold()) + } + pub fn banner(self) -> Color { self.restyle(Style::new().fg(Cyan).bold()) } diff --git a/src/justfile.rs b/src/justfile.rs index 8905e9c..f86bde3 100644 --- a/src/justfile.rs +++ b/src/justfile.rs @@ -6,6 +6,7 @@ pub struct Justfile<'a> { pub assignments: BTreeMap<&'a str, Expression<'a>>, pub exports: BTreeSet<&'a str>, pub aliases: BTreeMap<&'a str, Alias<'a>>, + pub deprecated_equals: bool, } impl<'a> Justfile<'a> where { @@ -80,7 +81,7 @@ impl<'a> Justfile<'a> where { } for (name, value) in scope { - println!("{0:1$} = \"{2}\"", name, width, value); + println!("{0:1$} := \"{2}\"", name, width, value); } return Ok(()); } @@ -175,7 +176,7 @@ impl<'a> Display for Justfile<'a> { if self.exports.contains(name) { write!(f, "export ")?; } - write!(f, "{} = {}", name, expression)?; + write!(f, "{} := {}", name, expression)?; items -= 1; if items != 0 { write!(f, "\n\n")?; diff --git a/src/lexer.rs b/src/lexer.rs index 63a11b0..2927a22 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -323,7 +323,7 @@ impl<'a> Lexer<'a> { '@' => self.lex_single(At), '=' => self.lex_single(Equals), ',' => self.lex_single(Comma), - ':' => self.lex_single(Colon), + ':' => self.lex_colon(), '(' => self.lex_single(ParenL), ')' => self.lex_single(ParenR), '{' => self.lex_brace_l(), @@ -442,6 +442,20 @@ impl<'a> Lexer<'a> { 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 '{' fn lex_brace_l(&mut self) -> CompilationResult<'a, ()> { if !self.rest_starts_with("{{") { diff --git a/src/parser.rs b/src/parser.rs index 939b12c..0b6e7b6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -12,6 +12,7 @@ pub struct Parser<'a> { exports: BTreeSet<&'a str>, aliases: BTreeMap<&'a str, Alias<'a>>, alias_tokens: BTreeMap<&'a str, Token<'a>>, + deprecated_equals: bool, } impl<'a> Parser<'a> { @@ -31,6 +32,7 @@ impl<'a> Parser<'a> { exports: empty(), aliases: empty(), alias_tokens: empty(), + deprecated_equals: false, text, } } @@ -152,10 +154,10 @@ impl<'a> Parser<'a> { } 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 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 { return Err(self.unexpected_token(&token, &[Name, Plus, Colon])); } @@ -420,6 +422,10 @@ impl<'a> Parser<'a> { if token.lexeme() == "export" { let next = self.tokens.next().unwrap(); 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)?; doc = None; } else { @@ -430,6 +436,10 @@ impl<'a> Parser<'a> { } else if token.lexeme() == "alias" { let next = self.tokens.next().unwrap(); 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)?; doc = None; } else { @@ -438,6 +448,10 @@ impl<'a> Parser<'a> { doc = None; } } else if self.accepted(Equals) { + self.deprecated_equals = true; + self.assignment(token, false)?; + doc = None; + } else if self.accepted(ColonEquals) { self.assignment(token, false)?; doc = None; } else { @@ -501,6 +515,7 @@ impl<'a> Parser<'a> { assignments: self.assignments, exports: self.exports, aliases: self.aliases, + deprecated_equals: self.deprecated_equals, }) } } @@ -604,10 +619,10 @@ foo a='b\t': summary_test! { parse_export, r#" -export a = "hello" +export a := "hello" "#, - r#"export a = "hello""#, + r#"export a := "hello""#, } summary_test! { @@ -615,9 +630,9 @@ export a = "hello" r#" foo: echo a -alias f = foo +alias f := foo "#, -r#"alias f = foo +r#"alias f := foo foo: echo a"# @@ -626,11 +641,11 @@ foo: summary_test! { parse_alias_before_target, r#" -alias f = foo +alias f := foo foo: echo a "#, -r#"alias f = foo +r#"alias f := foo foo: echo a"# @@ -639,11 +654,11 @@ foo: summary_test! { parse_alias_with_comment, r#" -alias f = foo #comment +alias f := foo #comment foo: echo a "#, -r#"alias f = foo +r#"alias f := foo foo: echo a"# @@ -655,9 +670,9 @@ foo: x: y: z: -foo = \"xx\" -bar = foo -goodbye = \"y\" +foo := \"xx\" +bar := foo +goodbye := \"y\" hello a b c : x y z #hello #! blah #blarg @@ -666,11 +681,11 @@ hello a b c : x y z #hello 2 3 ", - "bar = foo + "bar := foo -foo = \"xx\" +foo := \"xx\" -goodbye = \"y\" +goodbye := \"y\" hello a b c: x y z #! blah @@ -690,14 +705,14 @@ z:" summary_test! { parse_shebang, " -practicum = 'hello' +practicum := 'hello' install: \t#!/bin/sh \tif [[ -f {{practicum}} ]]; then \t\treturn \tfi ", - "practicum = 'hello' + "practicum := 'hello' install: #!/bin/sh @@ -714,27 +729,27 @@ install: summary_test! { parse_assignments, - r#"a = "0" -c = a + b + a + b -b = "1" + r#"a := "0" +c := a + b + a + b +b := "1" "#, - r#"a = "0" + r#"a := "0" -b = "1" +b := "1" -c = a + b + a + b"#, +c := a + b + a + b"#, } summary_test! { parse_assignment_backticks, - "a = `echo hello` -c = a + b + a + b -b = `echo goodbye`", - "a = `echo hello` + "a := `echo hello` +c := a + b + a + b +b := `echo goodbye`", + "a := `echo hello` -b = `echo goodbye` +b := `echo goodbye` -c = a + b + a + b", +c := a + b + a + b", } summary_test! { @@ -753,14 +768,14 @@ c = a + b + a + b", summary_test! { string_quote_escape, - r#"a = "hello\"""#, - r#"a = "hello\"""#, + r#"a := "hello\"""#, + r#"a := "hello\"""#, } summary_test! { string_escapes, - r#"a = "\n\t\r\"\\""#, - r#"a = "\n\t\r\"\\""#, + r#"a := "\n\t\r\"\\""#, + r#"a := "\n\t\r\"\\""#, } summary_test! { @@ -774,11 +789,11 @@ c = a + b + a + b", summary_test! { unary_functions, " -x = arch() +x := arch() a: {{os()}} {{os_family()}}", - "x = arch() + "x := arch() a: {{os()}} {{os_family()}}", @@ -787,11 +802,11 @@ a: summary_test! { env_functions, r#" -x = env_var('foo',) +x := env_var('foo',) a: {{env_var_or_default('foo' + 'bar', 'baz',)}} {{env_var(env_var("baz"))}}"#, - r#"x = env_var('foo') + r#"x := env_var('foo') a: {{env_var_or_default('foo' + 'bar', 'baz')}} {{env_var(env_var("baz"))}}"#, @@ -832,10 +847,10 @@ f x=(`echo hello` + "foo"): summary_test! { parameter_default_concatination_variable, r#" -x = "10" +x := "10" f y=(`echo hello` + x) +z="foo": "#, - r#"x = "10" + r#"x := "10" f y=(`echo hello` + x) +z="foo":"#, } @@ -843,24 +858,24 @@ f y=(`echo hello` + x) +z="foo":"#, summary_test! { parameter_default_multiple, r#" -x = "10" +x := "10" f y=(`echo hello` + x) +z=("foo" + "bar"): "#, - r#"x = "10" + r#"x := "10" f y=(`echo hello` + x) +z=("foo" + "bar"):"#, } summary_test! { concatination_in_group, - "x = ('0' + '1')", - "x = ('0' + '1')", + "x := ('0' + '1')", + "x := ('0' + '1')", } summary_test! { string_in_group, - "x = ('0' )", - "x = ('0')", + "x := ('0' )", + "x := ('0')", } #[rustfmt::skip] diff --git a/src/run.rs b/src/run.rs index 132e772..14e899c 100644 --- a/src/run.rs +++ b/src/run.rs @@ -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 justfile.count() == 0 { eprintln!("Justfile contains no recipes."); diff --git a/src/testing.rs b/src/testing.rs index 03c5a46..773e2ee 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -16,6 +16,7 @@ pub fn token_summary(tokens: &[Token]) -> String { At => "@", Backtick => "`", Colon => ":", + ColonEquals => ":=", Comma => ",", Comment => "#", Dedent => "<", diff --git a/src/token_kind.rs b/src/token_kind.rs index 23cda3d..08e4f22 100644 --- a/src/token_kind.rs +++ b/src/token_kind.rs @@ -5,6 +5,7 @@ pub enum TokenKind { At, Backtick, Colon, + ColonEquals, Comma, Comment, Dedent, @@ -35,6 +36,7 @@ impl Display for TokenKind { At => "'@'", Backtick => "backtick", Colon => "':'", + ColonEquals => "':='", Comma => "','", Comment => "comment", Dedent => "dedent", diff --git a/tests/integration.rs b/tests/integration.rs index 33b8db3..8d15268 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -157,7 +157,7 @@ fn integration_test( integration_test! { name: alias_listing, - justfile: "foo:\n echo foo\nalias f = foo", + justfile: "foo:\n echo foo\nalias f := foo", args: ("--list"), stdin: "", stdout: "Available recipes: @@ -170,7 +170,7 @@ integration_test! { integration_test! { 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"), stdin: "", stdout: "Available recipes: @@ -184,7 +184,7 @@ integration_test! { integration_test! { 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"), stdin: "", stdout: "Available recipes: @@ -197,7 +197,7 @@ integration_test! { integration_test! { 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"), stdin: "", stdout: "Available recipes: @@ -209,7 +209,7 @@ integration_test! { integration_test! { name: alias, - justfile: "foo:\n echo foo\nalias f = foo", + justfile: "foo:\n echo foo\nalias f := foo", args: ("f"), stdin: "", stdout: "foo\n", @@ -219,7 +219,7 @@ integration_test! { integration_test! { 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"), stdin: "", stdout: "bar\n", @@ -229,7 +229,7 @@ integration_test! { integration_test! { 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"), stdin: "", stdout: "foo\n", @@ -239,13 +239,13 @@ integration_test! { integration_test! { name: duplicate_alias, - justfile: "alias foo = bar\nalias foo = baz\n", + justfile: "alias foo := bar\nalias foo := baz\n", args: (), stdin: "", stdout: "" , 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, @@ -253,13 +253,13 @@ integration_test! { integration_test! { name: unknown_alias_target, - justfile: "alias foo = bar\n", + justfile: "alias foo := bar\n", args: (), stdin: "", stdout: "", stderr: "error: Alias `foo` has an unknown target `bar` | -1 | alias foo = bar +1 | alias foo := bar | ^^^ ", status: EXIT_FAILURE, @@ -267,13 +267,13 @@ integration_test! { integration_test! { 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: (), stdin: "", stdout: "", stderr: "error: Alias `foo` defined on `3` shadows recipe defined on `4` | -3 | alias foo = bar +3 | alias foo := bar | ^^^ ", status: EXIT_FAILURE, @@ -387,8 +387,8 @@ c: integration_test! { name: show, - justfile: r#"hello = "foo" -bar = hello + hello + justfile: r#"hello := "foo" +bar := hello + hello recipe: echo {{hello + "bar" + bar}}"#, args: ("--show", "recipe"), @@ -431,7 +431,7 @@ integration_test! { integration_test! { name: backtick_success, - justfile: "a = `printf Hello,`\nbar:\n printf '{{a + `printf ' world.'`}}'", + justfile: "a := `printf Hello,`\nbar:\n printf '{{a + `printf ' world.'`}}'", args: (), stdin: "", stdout: "Hello, world.", @@ -441,7 +441,7 @@ integration_test! { integration_test! { name: backtick_trimming, - justfile: "a = `echo Hello,`\nbar:\n echo '{{a + `echo ' world.'`}}'", + justfile: "a := `echo Hello,`\nbar:\n echo '{{a + `echo ' world.'`}}'", args: (), stdin: "", stdout: "Hello, world.\n", @@ -451,21 +451,21 @@ integration_test! { integration_test! { 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: (), stdin: "", stdout: "", stderr: "error: Backtick failed with exit code 100 | -2 | a = `exit 100` - | ^^^^^^^^^^ +2 | a := `exit 100` + | ^^^^^^^^^^ ", status: 100, } integration_test! { 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: (), stdin: "", stdout: "", @@ -477,7 +477,6 @@ integration_test! { status: 200, } -// 😬鎌 integration_test! { name: backtick_code_interpolation_mod, justfile: "f:\n 無{{`exit 200`}}", @@ -579,7 +578,7 @@ backtick-fail: integration_test! { 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: (), stdin: "", stdout: "", @@ -629,14 +628,14 @@ integration_test! { justfile: "foo: echo hello echo {{`exit 111`}} -a = `exit 222`", +a := `exit 222`", args: (), stdin: "", stdout: "", stderr: "error: Backtick failed with exit code 222 | -4 | a = `exit 222` - | ^^^^^^^^^^ +4 | a := `exit 222` + | ^^^^^^^^^^ ", status: 222, } @@ -646,7 +645,7 @@ integration_test! { justfile: "foo: echo hello echo {{`exit 111`}} -a = `exit 222`", +a := `exit 222`", args: ("--set", "foo", "bar", "--set", "baz", "bob", "--set", "a", "b", "a", "b"), stdin: "", stdout: "", @@ -660,7 +659,7 @@ integration_test! { justfile: "foo: echo hello echo {{`exit 111`}} -a = `exit 222`", +a := `exit 222`", args: ("foo=bar", "baz=bob", "a=b", "a", "b"), stdin: "", stdout: "", @@ -674,7 +673,7 @@ integration_test! { justfile: "foo: echo hello echo {{`exit 111`}} -a = `exit 222`", +a := `exit 222`", args: ("foo=bar", "a=b", "a", "b"), stdin: "", stdout: "", @@ -685,9 +684,9 @@ a = `exit 222`", integration_test! { name: overrides_first, justfile: r#" -foo = "foo" -a = "a" -baz = "baz" +foo := "foo" +a := "a" +baz := "baz" recipe arg: echo arg={{arg}} @@ -702,9 +701,9 @@ recipe arg: integration_test! { name: overrides_not_evaluated, justfile: r#" -foo = `exit 1` -a = "a" -baz = "baz" +foo := `exit 1` +a := "a" +baz := "baz" recipe arg: echo arg={{arg}} @@ -719,7 +718,7 @@ recipe arg: integration_test! { name: dry_run, justfile: r#" -var = `echo stderr 1>&2; echo backtick` +var := `echo stderr 1>&2; echo backtick` command: @touch /this/is/not/a/file @@ -748,20 +747,20 @@ echo `echo command interpolation` integration_test! { name: evaluate, justfile: r#" -foo = "a\t" -hello = "c" -bar = "b\t" -ab = foo + bar + hello +foo := "a\t" +hello := "c" +bar := "b\t" +ab := foo + bar + hello wut: touch /this/is/not/a/file "#, args: ("--evaluate"), stdin: "", - stdout: r#"ab = "a b c" -bar = "b " -foo = "a " -hello = "c" + stdout: r#"ab := "a b c" +bar := "b " +foo := "a " +hello := "c" "#, stderr: "", status: EXIT_SUCCESS, @@ -770,10 +769,10 @@ hello = "c" integration_test! { name: export_success, justfile: r#" -export FOO = "a" -baz = "c" -export BAR = "b" -export ABC = FOO + BAR + baz +export FOO := "a" +baz := "c" +export BAR := "b" +export ABC := FOO + BAR + baz wut: echo $FOO $BAR $ABC @@ -788,10 +787,10 @@ wut: integration_test! { name: export_override, justfile: r#" -export FOO = "a" -baz = "c" -export BAR = "b" -export ABC = FOO + "-" + BAR + "-" + baz +export FOO := "a" +baz := "c" +export BAR := "b" +export ABC := FOO + "-" + BAR + "-" + baz wut: echo $FOO $BAR $ABC @@ -806,10 +805,10 @@ wut: integration_test! { name: export_shebang, justfile: r#" -export FOO = "a" -baz = "c" -export BAR = "b" -export ABC = FOO + BAR + baz +export FOO := "a" +baz := "c" +export BAR := "b" +export ABC := FOO + BAR + baz wut: #!/bin/sh @@ -825,7 +824,7 @@ wut: integration_test! { name: export_recipe_backtick, justfile: r#" -export EXPORTED_VARIABLE = "A-IS-A" +export EXPORTED_VARIABLE := "A-IS-A" recipe: echo {{`echo recipe $EXPORTED_VARIABLE`}} @@ -840,7 +839,7 @@ recipe: integration_test! { name: raw_string, justfile: r#" -export EXPORTED_VARIABLE = '\z' +export EXPORTED_VARIABLE := '\z' recipe: printf "$EXPORTED_VARIABLE" @@ -931,7 +930,7 @@ default: integration_test! { name: quiet_flag_no_assignment_backtick_stderr, justfile: r#" -a = `echo hello 1>&2` +a := `echo hello 1>&2` default: exit 100 "#, @@ -1056,39 +1055,39 @@ integration_test! { integration_test! { 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"), stdin: "", stdout: "", 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, } integration_test! { 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"), stdin: "", stdout: "", stderr: "error: Backtick failed with exit code 100 | -2 | a = `exit 100` - | ^^^^^^^^^^ +2 | a := `exit 100` + | ^^^^^^^^^^ ", status: 100, } integration_test! { 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"), stdin: "", stdout: "", stderr: "error: Backtick failed with exit code 100 | -2 | a = `exit 100` - | ^^^^^^^^^^ +2 | a := `exit 100` + | ^^^^^^^^^^ ", status: 100, } @@ -1432,9 +1431,9 @@ foo: integration_test! { name: test_os_arch_functions_in_expression, justfile: r#" -a = arch() -o = os() -f = os_family() +a := arch() +o := os() +f := os_family() foo: echo {{a}} {{o}} {{f}} @@ -1450,9 +1449,9 @@ foo: integration_test! { name: env_var_functions, justfile: r#" -p = env_var('USER') -b = env_var_or_default('ZADDY', 'HTAP') -x = env_var_or_default('XYZ', 'ABC') +p := env_var('USER') +b := env_var_or_default('ZADDY', 'HTAP') +x := env_var_or_default('XYZ', 'ABC') foo: /bin/echo '{{p}}' '{{b}}' '{{x}}' @@ -1468,9 +1467,9 @@ foo: integration_test! { name: env_var_functions, justfile: r#" -p = env_var('USERNAME') -b = env_var_or_default('ZADDY', 'HTAP') -x = env_var_or_default('XYZ', 'ABC') +p := env_var('USERNAME') +b := env_var_or_default('ZADDY', 'HTAP') +x := env_var_or_default('XYZ', 'ABC') foo: /bin/echo '{{p}}' '{{b}}' '{{x}}' @@ -1573,7 +1572,7 @@ c: b a integration_test! { name: parameter_shadows_variable, - justfile: "FOO = 'hello'\na FOO:", + justfile: "FOO := 'hello'\na FOO:", args: ("a"), stdin: "", stdout: "", @@ -1587,15 +1586,15 @@ integration_test! { integration_test! { name: unknown_function_in_assignment, - justfile: r#"foo = foo() + "hello" + justfile: r#"foo := foo() + "hello" bar:"#, args: ("bar"), stdin: "", stdout: "", stderr: r#"error: Call to unknown function `foo` | -1 | foo = foo() + "hello" - | ^^^ +1 | foo := foo() + "hello" + | ^^^ "#, status: EXIT_FAILURE, } @@ -1659,13 +1658,13 @@ integration_test! { integration_test! { name: duplicate_variable, - justfile: "a = 'hello'\na = 'hello'\nfoo:", + justfile: "a := 'hello'\na := 'hello'\nfoo:", args: ("foo"), stdin: "", stdout: "", stderr: "error: Variable `a` has multiple definitions | -2 | a = 'hello' +2 | a := 'hello' | ^ ", status: EXIT_FAILURE, @@ -1691,7 +1690,7 @@ integration_test! { args: ("foo"), stdin: "", stdout: "", - stderr: "error: Expected name, '+', ':', or '=', but found raw string + stderr: "error: Expected name, '+', ':', or ':=', but found raw string | 1 | foo 'bar' | ^^^^^ @@ -1729,13 +1728,13 @@ integration_test! { integration_test! { name: variable_self_dependency, - justfile: "z = z\na:", + justfile: "z := z\na:", args: ("a"), stdin: "", stdout: "", stderr: "error: Variable `z` is defined in terms of itself | -1 | z = z +1 | z := z | ^ ", status: EXIT_FAILURE, @@ -1743,13 +1742,13 @@ integration_test! { integration_test! { name: variable_circular_dependency, - justfile: "x = y\ny = z\nz = x\na:", + justfile: "x := y\ny := z\nz := x\na:", args: ("a"), stdin: "", stdout: "", stderr: "error: Variable `x` depends on its own value: `x -> y -> z -> x` | -1 | x = y +1 | x := y | ^ ", status: EXIT_FAILURE, @@ -1757,15 +1756,15 @@ integration_test! { integration_test! { name: invalid_escape_sequence, - justfile: r#"x = "\q" + justfile: r#"x := "\q" a:"#, args: ("a"), stdin: "", stdout: "", stderr: "error: `\\q` is not a valid escape sequence | -1 | x = \"\\q\" - | ^^^^ +1 | x := \"\\q\" + | ^^^^ ", status: EXIT_FAILURE, } @@ -1773,7 +1772,7 @@ a:"#, integration_test! { name: multiline_raw_string, justfile: " -string = 'hello +string := 'hello whatever' a: @@ -1793,7 +1792,7 @@ whatever' integration_test! { name: error_line_after_multiline_raw_string, justfile: " -string = 'hello +string := 'hello whatever' + 'yo' @@ -1814,7 +1813,7 @@ a: integration_test! { name: error_column_after_multiline_raw_string, justfile: " -string = 'hello +string := 'hello whatever' + bar @@ -2039,7 +2038,7 @@ integration_test! { name: comment_before_variable, justfile: " # -A='1' +A:='1' echo: echo {{A}} ", @@ -2068,7 +2067,7 @@ integration_test! { name: dotenv_variable_in_backtick, justfile: " # -X=`echo $DOTENV_KEY` +X:=`echo $DOTENV_KEY` echo: echo {{X}} ", @@ -2097,8 +2096,8 @@ integration_test! { name: dotenv_variable_in_function_in_backtick, justfile: " # -X=env_var_or_default('DOTENV_KEY', 'foo') -Y=env_var('DOTENV_KEY') +X:=env_var_or_default('DOTENV_KEY', 'foo') +Y:=env_var('DOTENV_KEY') echo: echo {{X}} echo {{Y}} @@ -2113,15 +2112,15 @@ echo: integration_test! { name: invalid_escape_sequence_message, justfile: r#" -X = "\'" +X := "\'" "#, args: (), stdin: "", stdout: "", stderr: r#"error: `\'` is not a valid escape sequence | -2 | X = "\'" - | ^^^^ +2 | X := "\'" + | ^^^^ "#, status: EXIT_FAILURE, } @@ -2200,7 +2199,7 @@ foo x=`echo foo`: integration_test! { name: default_variable, justfile: " -y = 'foo' +y := 'foo' foo x=y: echo {{x}} ", @@ -2292,7 +2291,7 @@ assembly_source_files = $(wildcard src/arch/$(arch)/*.s) integration_test! { name: backtick_variable_cat, justfile: " -stdin = `cat` +stdin := `cat` default: echo {{stdin}} @@ -2338,7 +2337,7 @@ default stdin = `cat justfile`: integration_test! { name: backtick_variable_read_single, justfile: " -password = `read PW && echo $PW` +password := `read PW && echo $PW` default: echo {{password}} @@ -2353,8 +2352,8 @@ default: integration_test! { name: backtick_variable_read_multiple, justfile: " -a = `read A && echo $A` -b = `read B && echo $B` +a := `read A && echo $A` +b := `read B && echo $B` default: echo {{a}} @@ -2381,3 +2380,63 @@ default a=`read A && echo $A` b=`read B && echo $B`: stderr: "echo foo\necho bar\n", 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, +}