Skip to content

Commit

Permalink
Add skip-comments setting (#1333)
Browse files Browse the repository at this point in the history
Add a new setting "skip-comments", which defaults to true. If unset,
this causes lines internal to a non-shebang recipe beginning with the
character '#' (including '#!' internal to a non-shebang recipe; that is,
any such instances occurring after the first line of a recipe) to be
treated as comments of the justfile itself. They will not be echoed to
stderr when the recipe executes.
  • Loading branch information
neunenak committed Oct 5, 2022
1 parent 7680b19 commit e445cfb
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 81 deletions.
1 change: 1 addition & 0 deletions GRAMMAR.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ assignment : NAME ':=' expression eol
export : 'export' assignment

setting : 'set' 'dotenv-load' boolean?
| 'set' 'ignore-comments' boolean?
| 'set' 'export' boolean?
| 'set' 'positional-arguments' boolean?
| 'set' 'allow-duplicate-recipes' boolean?
Expand Down
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -641,15 +641,16 @@ foo:

#### Table of Settings

| Name | Value | Description |
| ------------------------- | ------------------ | --------------------------------------------------------------------------------------------- |
| `allow-duplicate-recipes` | boolean | Allow recipes appearing later in a `justfile` to override earlier recipes with the same name. |
| `dotenv-load` | boolean | Load a `.env` file, if present. |
| `export` | boolean | Export all variables as environment variables. |
| `positional-arguments` | boolean | Pass positional arguments. |
| `shell` | `[COMMAND, ARGS…]` | Set the command used to invoke recipes and evaluate backticks. |
| `windows-shell` | `[COMMAND, ARGS…]` | Set the command used to invoke recipes and evaluate backticks. |
| `windows-powershell` | boolean | Use PowerShell on Windows as default shell. (Deprecated. Use `windows-shell` instead. |
| Name | Value | Default | Description |
| ------------------------- | ------------------ | --------|---------------------------------------------------------------------------------------------- |
| `allow-duplicate-recipes` | boolean | False | Allow recipes appearing later in a `justfile` to override earlier recipes with the same name. |
| `dotenv-load` | boolean | False | Load a `.env` file, if present. |
| `export` | boolean | False | Export all variables as environment variables. |
| `ignore-comments` | boolean | False | Ignore recipe lines beginning with `#`. |
| `positional-arguments` | boolean | False | Pass positional arguments. |
| `shell` | `[COMMAND, ARGS…]` | - | Set the command used to invoke recipes and evaluate backticks. |
| `windows-powershell` | boolean | False | Use PowerShell on Windows as default shell. (Deprecated. Use `windows-shell` instead. |
| `windows-shell` | `[COMMAND, ARGS…]` | - | Set the command used to invoke recipes and evaluate backticks. |

Boolean settings can be written as:

Expand Down
5 changes: 4 additions & 1 deletion src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl<'src> Analyzer<'src> {
}
}

let mut settings = Settings::new();
let mut settings = Settings::default();

for (_, set) in self.sets {
match set.value {
Expand All @@ -53,6 +53,9 @@ impl<'src> Analyzer<'src> {
Setting::Export(export) => {
settings.export = export;
}
Setting::IgnoreComments(ignore_comments) => {
settings.ignore_comments = ignore_comments;
}
Setting::PositionalArguments(positional_arguments) => {
settings.positional_arguments = positional_arguments;
}
Expand Down
13 changes: 12 additions & 1 deletion src/justfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,15 @@ impl<'src> Justfile<'src> {

let mut ran = BTreeSet::new();
for (recipe, arguments) in grouped {
Self::run_recipe(&context, recipe, arguments, &dotenv, search, &mut ran)?;
Self::run_recipe(
&context,
recipe,
arguments,
&dotenv,
search,
&self.settings,
&mut ran,
)?;
}

Ok(())
Expand All @@ -281,6 +289,7 @@ impl<'src> Justfile<'src> {
arguments: &[&str],
dotenv: &BTreeMap<String, String>,
search: &Search,
settings: &Settings,
ran: &mut BTreeSet<Vec<String>>,
) -> RunResult<'src, ()> {
let mut invocation = vec![recipe.name().to_owned()];
Expand Down Expand Up @@ -319,6 +328,7 @@ impl<'src> Justfile<'src> {
&arguments.iter().map(String::as_ref).collect::<Vec<&str>>(),
dotenv,
search,
settings,
ran,
)?;
}
Expand All @@ -341,6 +351,7 @@ impl<'src> Justfile<'src> {
&evaluated.iter().map(String::as_ref).collect::<Vec<&str>>(),
dotenv,
search,
settings,
&mut ran,
)?;
}
Expand Down
1 change: 1 addition & 0 deletions src/keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) enum Keyword {
Export,
False,
If,
IgnoreComments,
PositionalArguments,
Set,
Shell,
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![deny(clippy::all, clippy::pedantic)]
#![allow(
clippy::default_trait_access,
clippy::doc_markdown,
clippy::enum_glob_use,
clippy::missing_errors_doc,
Expand Down
7 changes: 7 additions & 0 deletions src/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ impl<'src> Line<'src> {
self.fragments.is_empty()
}

pub(crate) fn is_comment(&self) -> bool {
match self.fragments.first() {
Some(Fragment::Text { token }) => token.lexeme().starts_with('#'),
_ => false,
}
}

pub(crate) fn is_continuation(&self) -> bool {
match self.fragments.last() {
Some(Fragment::Text { token }) => token.lexeme().ends_with('\\'),
Expand Down
3 changes: 2 additions & 1 deletion src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,8 @@ impl<'src> Node<'src> for Set<'src> {
| Setting::DotenvLoad(value)
| Setting::Export(value)
| Setting::PositionalArguments(value)
| Setting::WindowsPowerShell(value) => {
| Setting::WindowsPowerShell(value)
| Setting::IgnoreComments(value) => {
set.push_mut(value.to_string());
}
Setting::Shell(Shell { command, arguments })
Expand Down
47 changes: 17 additions & 30 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,36 +755,23 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
let name = Name::from_identifier(self.presume(Identifier)?);
let lexeme = name.lexeme();

if Keyword::AllowDuplicateRecipes == lexeme {
let value = self.parse_set_bool()?;
return Ok(Set {
value: Setting::AllowDuplicateRecipes(value),
name,
});
} else if Keyword::DotenvLoad == lexeme {
let value = self.parse_set_bool()?;
return Ok(Set {
value: Setting::DotenvLoad(value),
name,
});
} else if Keyword::Export == lexeme {
let value = self.parse_set_bool()?;
return Ok(Set {
value: Setting::Export(value),
name,
});
} else if Keyword::PositionalArguments == lexeme {
let value = self.parse_set_bool()?;
return Ok(Set {
value: Setting::PositionalArguments(value),
name,
});
} else if Keyword::WindowsPowershell == lexeme {
let value = self.parse_set_bool()?;
return Ok(Set {
value: Setting::WindowsPowerShell(value),
name,
});
let set_bool: Option<Setting> = match Keyword::from_lexeme(lexeme) {
Some(kw) => match kw {
Keyword::AllowDuplicateRecipes => {
Some(Setting::AllowDuplicateRecipes(self.parse_set_bool()?))
}
Keyword::DotenvLoad => Some(Setting::DotenvLoad(self.parse_set_bool()?)),
Keyword::IgnoreComments => Some(Setting::IgnoreComments(self.parse_set_bool()?)),
Keyword::Export => Some(Setting::Export(self.parse_set_bool()?)),
Keyword::PositionalArguments => Some(Setting::PositionalArguments(self.parse_set_bool()?)),
Keyword::WindowsPowershell => Some(Setting::WindowsPowerShell(self.parse_set_bool()?)),
_ => None,
},
None => None,
};

if let Some(value) = set_bool {
return Ok(Set { name, value });
}

self.expect(ColonEquals)?;
Expand Down
12 changes: 10 additions & 2 deletions src/recipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl<'src, D> Recipe<'src, D> {
}
}

pub(crate) fn run_linewise<'run>(
fn run_linewise<'run>(
&self,
context: &RecipeContext<'src, 'run>,
dotenv: &BTreeMap<String, String>,
Expand All @@ -114,14 +114,18 @@ impl<'src, D> Recipe<'src, D> {
let mut continued = false;
let quiet_command = lines.peek().map_or(false, |line| line.is_quiet());
let infallible_command = lines.peek().map_or(false, |line| line.is_infallible());

let comment_line =
context.settings.ignore_comments && lines.peek().map_or(false, |line| line.is_comment());

loop {
if lines.peek().is_none() {
break;
}
let line = lines.next().unwrap();
line_number += 1;
evaluated += &evaluator.evaluate_line(line, continued)?;
if line.is_continuation() {
if line.is_continuation() && !comment_line {
continued = true;
evaluated.pop();
} else {
Expand All @@ -138,6 +142,10 @@ impl<'src, D> Recipe<'src, D> {
command = &command[1..];
}

if comment_line {
continue;
}

if command.is_empty() {
continue;
}
Expand Down
2 changes: 2 additions & 0 deletions src/setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::*;
pub(crate) enum Setting<'src> {
AllowDuplicateRecipes(bool),
DotenvLoad(bool),
IgnoreComments(bool),
Export(bool),
PositionalArguments(bool),
Shell(Shell<'src>),
Expand All @@ -16,6 +17,7 @@ impl<'src> Display for Setting<'src> {
match self {
Setting::AllowDuplicateRecipes(value)
| Setting::DotenvLoad(value)
| Setting::IgnoreComments(value)
| Setting::Export(value)
| Setting::PositionalArguments(value)
| Setting::WindowsPowerShell(value) => write!(f, "{}", value),
Expand Down
72 changes: 35 additions & 37 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,19 @@ pub(crate) const DEFAULT_SHELL_ARGS: &[&str] = &["-cu"];
pub(crate) const WINDOWS_POWERSHELL_SHELL: &str = "powershell.exe";
pub(crate) const WINDOWS_POWERSHELL_ARGS: &[&str] = &["-NoLogo", "-Command"];

#[derive(Debug, PartialEq, Serialize)]
#[derive(Debug, PartialEq, Serialize, Default)]
pub(crate) struct Settings<'src> {
pub(crate) allow_duplicate_recipes: bool,
pub(crate) dotenv_load: Option<bool>,
pub(crate) export: bool,
pub(crate) ignore_comments: bool,
pub(crate) positional_arguments: bool,
pub(crate) shell: Option<Shell<'src>>,
pub(crate) windows_powershell: bool,
pub(crate) windows_shell: Option<Shell<'src>>,
}

impl<'src> Settings<'src> {
pub(crate) fn new() -> Settings<'src> {
Settings {
allow_duplicate_recipes: false,
dotenv_load: None,
export: false,
positional_arguments: false,
shell: None,
windows_powershell: false,
windows_shell: None,
}
}

pub(crate) fn shell_command(&self, config: &Config) -> Command {
let (command, args) = self.shell(config);

Expand Down Expand Up @@ -82,7 +71,7 @@ mod tests {

#[test]
fn default_shell() {
let settings = Settings::new();
let settings = Settings::default();

let config = Config {
shell_command: false,
Expand All @@ -94,8 +83,10 @@ mod tests {

#[test]
fn default_shell_powershell() {
let mut settings = Settings::new();
settings.windows_powershell = true;
let settings = Settings {
windows_powershell: true,
..Default::default()
};

let config = Config {
shell_command: false,
Expand All @@ -114,7 +105,7 @@ mod tests {

#[test]
fn overwrite_shell() {
let settings = Settings::new();
let settings = Settings::default();

let config = Config {
shell_command: true,
Expand All @@ -128,8 +119,10 @@ mod tests {

#[test]
fn overwrite_shell_powershell() {
let mut settings = Settings::new();
settings.windows_powershell = true;
let settings = Settings {
windows_powershell: true,
..Default::default()
};

let config = Config {
shell_command: true,
Expand All @@ -143,20 +136,21 @@ mod tests {

#[test]
fn shell_cooked() {
let mut settings = Settings::new();

settings.shell = Some(Shell {
command: StringLiteral {
kind: StringKind::from_token_start("\"").unwrap(),
raw: "asdf.exe",
cooked: "asdf.exe".to_string(),
},
arguments: vec![StringLiteral {
kind: StringKind::from_token_start("\"").unwrap(),
raw: "-nope",
cooked: "-nope".to_string(),
}],
});
let settings = Settings {
shell: Some(Shell {
command: StringLiteral {
kind: StringKind::from_token_start("\"").unwrap(),
raw: "asdf.exe",
cooked: "asdf.exe".to_string(),
},
arguments: vec![StringLiteral {
kind: StringKind::from_token_start("\"").unwrap(),
raw: "-nope",
cooked: "-nope".to_string(),
}],
}),
..Default::default()
};

let config = Config {
shell_command: false,
Expand All @@ -168,8 +162,10 @@ mod tests {

#[test]
fn shell_present_but_not_shell_args() {
let mut settings = Settings::new();
settings.windows_powershell = true;
let settings = Settings {
windows_powershell: true,
..Default::default()
};

let config = Config {
shell: Some("lol".to_string()),
Expand All @@ -181,8 +177,10 @@ mod tests {

#[test]
fn shell_args_present_but_not_shell() {
let mut settings = Settings::new();
settings.windows_powershell = true;
let settings = Settings {
windows_powershell: true,
..Default::default()
};

let config = Config {
shell_command: false,
Expand Down
Loading

0 comments on commit e445cfb

Please sign in to comment.