Allow shebang lines so justfiles can be used as scripts (#393)
This commit is contained in:
parent
cee9ac21e0
commit
37639d68d7
21
README.adoc
21
README.adoc
@ -653,6 +653,27 @@ $ just foo/build
|
|||||||
$ just foo/
|
$ just foo/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
=== Just Scripts
|
||||||
|
|
||||||
|
By adding a shebang line to the top of a justfile and making it executable, `just` can be used as an interpreter for scripts:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ cat > script <<EOF
|
||||||
|
#!/usr/bin/env just --justfile
|
||||||
|
|
||||||
|
foo:
|
||||||
|
echo foo
|
||||||
|
EOF
|
||||||
|
$ chmod +x script
|
||||||
|
$ ./script foo
|
||||||
|
echo foo
|
||||||
|
foo
|
||||||
|
```
|
||||||
|
|
||||||
|
When a script with a shebang is executed, the system supplies the path to the script as an argument to the command in the shebang. So, with a shebang of `#!/usr/bin/env just --justfile`, the command will be `/usr/bin/env just --justfile PATH_TO_SCRIPT`.
|
||||||
|
|
||||||
|
With the above shebang, `just` will change its working directory to the location of the script. If you'd rather leave the working directory unchanged, use `#!/usr/bin/env just --working-directory . --justfile`.
|
||||||
|
|
||||||
== Frequently Asked Questions
|
== Frequently Asked Questions
|
||||||
|
|
||||||
=== What are the idiosyncrasies of make that just avoids?
|
=== What are the idiosyncrasies of make that just avoids?
|
||||||
|
4
justfile
Normal file → Executable file
4
justfile
Normal file → Executable file
@ -1,3 +1,7 @@
|
|||||||
|
#!/usr/bin/env just --justfile
|
||||||
|
# ^ 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
|
||||||
|
@ -62,7 +62,6 @@ pub enum CompilationErrorKind<'a> {
|
|||||||
MixedLeadingWhitespace {
|
MixedLeadingWhitespace {
|
||||||
whitespace: &'a str,
|
whitespace: &'a str,
|
||||||
},
|
},
|
||||||
OuterShebang,
|
|
||||||
ParameterFollowsVariadicParameter {
|
ParameterFollowsVariadicParameter {
|
||||||
parameter: &'a str,
|
parameter: &'a str,
|
||||||
},
|
},
|
||||||
@ -229,9 +228,6 @@ impl<'a> Display for CompilationError<'a> {
|
|||||||
show_whitespace(found)
|
show_whitespace(found)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
OuterShebang => {
|
|
||||||
writeln!(f, "`#!` is reserved syntax outside of recipes")?;
|
|
||||||
}
|
|
||||||
UnknownDependency { recipe, unknown } => {
|
UnknownDependency { recipe, unknown } => {
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
|
16
src/lexer.rs
16
src/lexer.rs
@ -135,7 +135,7 @@ impl<'a> Lexer<'a> {
|
|||||||
static ref BACKTICK: Regex = token(r"`[^`\n\r]*`");
|
static ref BACKTICK: Regex = token(r"`[^`\n\r]*`");
|
||||||
static ref COLON: Regex = token(r":");
|
static ref COLON: Regex = token(r":");
|
||||||
static ref COMMA: Regex = token(r",");
|
static ref COMMA: Regex = token(r",");
|
||||||
static ref COMMENT: Regex = token(r"#([^!\n\r][^\n\r]*)?\r?$");
|
static ref COMMENT: Regex = token(r"#([^\n\r][^\n\r]*)?\r?$");
|
||||||
static ref EOF: Regex = token(r"\z");
|
static ref EOF: Regex = token(r"\z");
|
||||||
static ref EOL: Regex = token(r"\n|\r\n");
|
static ref EOL: Regex = token(r"\n|\r\n");
|
||||||
static ref EQUALS: Regex = token(r"=");
|
static ref EQUALS: Regex = token(r"=");
|
||||||
@ -322,8 +322,6 @@ impl<'a> Lexer<'a> {
|
|||||||
return Err(self.error(UnterminatedString));
|
return Err(self.error(UnterminatedString));
|
||||||
}
|
}
|
||||||
(prefix, &self.rest[start..content_end + 1], StringToken)
|
(prefix, &self.rest[start..content_end + 1], StringToken)
|
||||||
} else if self.rest.starts_with("#!") {
|
|
||||||
return Err(self.error(OuterShebang));
|
|
||||||
} else {
|
} else {
|
||||||
return Err(self.error(UnknownStartOfToken));
|
return Err(self.error(UnknownStartOfToken));
|
||||||
};
|
};
|
||||||
@ -340,7 +338,7 @@ impl<'a> Lexer<'a> {
|
|||||||
_ => {
|
_ => {
|
||||||
return Err(last.error(Internal {
|
return Err(last.error(Internal {
|
||||||
message: format!("zero length token: {:?}", last),
|
message: format!("zero length token: {:?}", last),
|
||||||
}))
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -647,16 +645,6 @@ c: b
|
|||||||
kind: InconsistentLeadingWhitespace{expected: "\t\t", found: "\t "},
|
kind: InconsistentLeadingWhitespace{expected: "\t\t", found: "\t "},
|
||||||
}
|
}
|
||||||
|
|
||||||
error_test! {
|
|
||||||
name: tokenize_outer_shebang,
|
|
||||||
input: "#!/usr/bin/env bash",
|
|
||||||
index: 0,
|
|
||||||
line: 0,
|
|
||||||
column: 0,
|
|
||||||
width: None,
|
|
||||||
kind: OuterShebang,
|
|
||||||
}
|
|
||||||
|
|
||||||
error_test! {
|
error_test! {
|
||||||
name: tokenize_unknown,
|
name: tokenize_unknown,
|
||||||
input: "~",
|
input: "~",
|
||||||
|
@ -578,28 +578,6 @@ wut:
|
|||||||
status: EXIT_SUCCESS,
|
status: EXIT_SUCCESS,
|
||||||
}
|
}
|
||||||
|
|
||||||
integration_test! {
|
|
||||||
name: outer_shebang,
|
|
||||||
justfile: r#"#!/lol/wut
|
|
||||||
export FOO = "a"
|
|
||||||
baz = "c"
|
|
||||||
export BAR = "b"
|
|
||||||
export ABC = FOO + BAR + baz
|
|
||||||
|
|
||||||
wut:
|
|
||||||
#!/bin/sh
|
|
||||||
echo $FOO $BAR $ABC
|
|
||||||
"#,
|
|
||||||
args: (),
|
|
||||||
stdout: "",
|
|
||||||
stderr: "error: `#!` is reserved syntax outside of recipes
|
|
||||||
|
|
|
||||||
1 | #!/lol/wut
|
|
||||||
| ^
|
|
||||||
",
|
|
||||||
status: EXIT_FAILURE,
|
|
||||||
}
|
|
||||||
|
|
||||||
integration_test! {
|
integration_test! {
|
||||||
name: export_shebang,
|
name: export_shebang,
|
||||||
justfile: r#"
|
justfile: r#"
|
||||||
|
Loading…
Reference in New Issue
Block a user