Add windows-shell
setting (#1198)
This commit is contained in:
parent
ccc54fb8d9
commit
c24a194602
15
README.md
15
README.md
@ -671,9 +671,22 @@ foo:
|
||||
|
||||
`just` passes the command to be executed as an argument. Many shells will need an additional flag, often `-c`, to make them evaluate the first argument.
|
||||
|
||||
##### Windows Shell
|
||||
|
||||
`just` uses `sh` on Windows by default. To use a different shell on Windows, use `windows-shell`:
|
||||
|
||||
```make
|
||||
set windows-shell := ["pwsh.exe", "-NoLogo", "-Command"]
|
||||
|
||||
hello:
|
||||
Write-Host "Hello, world!"
|
||||
```
|
||||
|
||||
##### Windows PowerShell
|
||||
|
||||
`just` uses `sh` on Windows by default. To use PowerShell instead, set `windows-powershell` to true.
|
||||
*`set windows-powershell` uses the legacy `powershell.exe` binary, and is no longer recommended. See the `windows-shell` setting above for a more flexible way to control which shell is used on Windows.*
|
||||
|
||||
`just` uses `sh` on Windows by default. To use `powershell.exe` instead, set `windows-powershell` to true.
|
||||
|
||||
```make
|
||||
set windows-powershell := true
|
||||
|
@ -57,12 +57,14 @@ impl<'src> Analyzer<'src> {
|
||||
settings.positional_arguments = positional_arguments;
|
||||
}
|
||||
Setting::Shell(shell) => {
|
||||
assert!(settings.shell.is_none());
|
||||
settings.shell = Some(shell);
|
||||
}
|
||||
Setting::WindowsPowerShell(windows_powershell) => {
|
||||
settings.windows_powershell = windows_powershell;
|
||||
}
|
||||
Setting::WindowsShell(windows_shell) => {
|
||||
settings.windows_shell = Some(windows_shell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ pub(crate) use ::{
|
||||
};
|
||||
|
||||
// modules
|
||||
pub(crate) use crate::{completions, config, config_error, keyed, setting};
|
||||
pub(crate) use crate::{completions, config, config_error, keyed};
|
||||
|
||||
// functions
|
||||
pub(crate) use crate::{load_dotenv::load_dotenv, output::output, unindent::unindent};
|
||||
@ -64,11 +64,11 @@ pub(crate) use crate::{
|
||||
parser::Parser, platform::Platform, position::Position, positional::Positional, recipe::Recipe,
|
||||
recipe_context::RecipeContext, recipe_resolver::RecipeResolver, scope::Scope, search::Search,
|
||||
search_config::SearchConfig, search_error::SearchError, set::Set, setting::Setting,
|
||||
settings::Settings, shebang::Shebang, show_whitespace::ShowWhitespace, string_kind::StringKind,
|
||||
string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
|
||||
thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
|
||||
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
|
||||
verbosity::Verbosity, warning::Warning,
|
||||
settings::Settings, shebang::Shebang, shell::Shell, show_whitespace::ShowWhitespace,
|
||||
string_kind::StringKind, string_literal::StringLiteral, subcommand::Subcommand,
|
||||
suggestion::Suggestion, table::Table, thunk::Thunk, token::Token, token_kind::TokenKind,
|
||||
unresolved_dependency::UnresolvedDependency, unresolved_recipe::UnresolvedRecipe,
|
||||
use_color::UseColor, variables::Variables, verbosity::Verbosity, warning::Warning,
|
||||
};
|
||||
|
||||
// type aliases
|
||||
|
@ -15,6 +15,7 @@ pub(crate) enum Keyword {
|
||||
Shell,
|
||||
True,
|
||||
WindowsPowershell,
|
||||
WindowsShell,
|
||||
}
|
||||
|
||||
impl Keyword {
|
||||
|
@ -106,6 +106,7 @@ mod set;
|
||||
mod setting;
|
||||
mod settings;
|
||||
mod shebang;
|
||||
mod shell;
|
||||
mod show_whitespace;
|
||||
mod string_kind;
|
||||
mod string_literal;
|
||||
|
15
src/node.rs
15
src/node.rs
@ -215,20 +215,19 @@ impl<'src> Node<'src> for Fragment<'src> {
|
||||
|
||||
impl<'src> Node<'src> for Set<'src> {
|
||||
fn tree(&self) -> Tree<'src> {
|
||||
use Setting::*;
|
||||
|
||||
let mut set = Tree::atom(Keyword::Set.lexeme());
|
||||
set.push_mut(self.name.lexeme().replace('-', "_"));
|
||||
|
||||
match &self.value {
|
||||
AllowDuplicateRecipes(value)
|
||||
| DotenvLoad(value)
|
||||
| Export(value)
|
||||
| PositionalArguments(value)
|
||||
| WindowsPowerShell(value) => {
|
||||
Setting::AllowDuplicateRecipes(value)
|
||||
| Setting::DotenvLoad(value)
|
||||
| Setting::Export(value)
|
||||
| Setting::PositionalArguments(value)
|
||||
| Setting::WindowsPowerShell(value) => {
|
||||
set.push_mut(value.to_string());
|
||||
}
|
||||
Shell(setting::Shell { command, arguments }) => {
|
||||
Setting::Shell(Shell { command, arguments })
|
||||
| Setting::WindowsShell(Shell { command, arguments }) => {
|
||||
set.push_mut(Tree::string(&command.cooked));
|
||||
for argument in arguments {
|
||||
set.push_mut(Tree::string(&argument.cooked));
|
||||
|
@ -764,6 +764,24 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
self.expect(ColonEquals)?;
|
||||
|
||||
if name.lexeme() == Keyword::Shell.lexeme() {
|
||||
Ok(Set {
|
||||
value: Setting::Shell(self.parse_shell()?),
|
||||
name,
|
||||
})
|
||||
} else if name.lexeme() == Keyword::WindowsShell.lexeme() {
|
||||
Ok(Set {
|
||||
value: Setting::WindowsShell(self.parse_shell()?),
|
||||
name,
|
||||
})
|
||||
} else {
|
||||
Err(name.error(CompileErrorKind::UnknownSetting {
|
||||
setting: name.lexeme(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a shell setting value
|
||||
fn parse_shell(&mut self) -> CompileResult<'src, Shell<'src>> {
|
||||
self.expect(BracketL)?;
|
||||
|
||||
let command = self.parse_string_literal()?;
|
||||
@ -782,15 +800,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
||||
|
||||
self.expect(BracketR)?;
|
||||
|
||||
Ok(Set {
|
||||
value: Setting::Shell(setting::Shell { arguments, command }),
|
||||
name,
|
||||
})
|
||||
} else {
|
||||
Err(name.error(CompileErrorKind::UnknownSetting {
|
||||
setting: name.lexeme(),
|
||||
}))
|
||||
}
|
||||
Ok(Shell { arguments, command })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,7 @@ pub(crate) enum Setting<'src> {
|
||||
PositionalArguments(bool),
|
||||
Shell(Shell<'src>),
|
||||
WindowsPowerShell(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub(crate) struct Shell<'src> {
|
||||
pub(crate) arguments: Vec<StringLiteral<'src>>,
|
||||
pub(crate) command: StringLiteral<'src>,
|
||||
WindowsShell(Shell<'src>),
|
||||
}
|
||||
|
||||
impl<'src> Display for Setting<'src> {
|
||||
@ -24,19 +19,7 @@ impl<'src> Display for Setting<'src> {
|
||||
| Setting::Export(value)
|
||||
| Setting::PositionalArguments(value)
|
||||
| Setting::WindowsPowerShell(value) => write!(f, "{}", value),
|
||||
Setting::Shell(shell) => write!(f, "{}", shell),
|
||||
Setting::Shell(shell) | Setting::WindowsShell(shell) => write!(f, "{}", shell),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> Display for Shell<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
write!(f, "[{}", self.command)?;
|
||||
|
||||
for argument in &self.arguments {
|
||||
write!(f, ", {}", argument)?;
|
||||
}
|
||||
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,9 @@ pub(crate) struct Settings<'src> {
|
||||
pub(crate) dotenv_load: Option<bool>,
|
||||
pub(crate) export: bool,
|
||||
pub(crate) positional_arguments: bool,
|
||||
pub(crate) shell: Option<setting::Shell<'src>>,
|
||||
pub(crate) shell: Option<Shell<'src>>,
|
||||
pub(crate) windows_powershell: bool,
|
||||
pub(crate) windows_shell: Option<Shell<'src>>,
|
||||
}
|
||||
|
||||
impl<'src> Settings<'src> {
|
||||
@ -24,6 +25,7 @@ impl<'src> Settings<'src> {
|
||||
positional_arguments: false,
|
||||
shell: None,
|
||||
windows_powershell: false,
|
||||
windows_shell: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +44,8 @@ impl<'src> Settings<'src> {
|
||||
shell.command.cooked.as_ref()
|
||||
} else if let Some(shell) = &config.shell {
|
||||
shell
|
||||
} else if let (true, Some(shell)) = (cfg!(windows), &self.windows_shell) {
|
||||
shell.command.cooked.as_ref()
|
||||
} else if cfg!(windows) && self.windows_powershell {
|
||||
WINDOWS_POWERSHELL_SHELL
|
||||
} else {
|
||||
@ -60,6 +64,12 @@ impl<'src> Settings<'src> {
|
||||
.collect()
|
||||
} else if let Some(shell_args) = &config.shell_args {
|
||||
shell_args.iter().map(String::as_ref).collect()
|
||||
} else if let (true, Some(shell)) = (cfg!(windows), &self.windows_shell) {
|
||||
shell
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|argument| argument.cooked.as_ref())
|
||||
.collect()
|
||||
} else if cfg!(windows) && self.windows_powershell {
|
||||
WINDOWS_POWERSHELL_ARGS.to_vec()
|
||||
} else {
|
||||
@ -70,8 +80,6 @@ impl<'src> Settings<'src> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::setting::Shell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
19
src/shell.rs
Normal file
19
src/shell.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub(crate) struct Shell<'src> {
|
||||
pub(crate) arguments: Vec<StringLiteral<'src>>,
|
||||
pub(crate) command: StringLiteral<'src>,
|
||||
}
|
||||
|
||||
impl<'src> Display for Shell<'src> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
write!(f, "[{}", self.command)?;
|
||||
|
||||
for argument in &self.arguments {
|
||||
write!(f, ", {}", argument)?;
|
||||
}
|
||||
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ fn alias() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -73,6 +74,7 @@ fn assignment() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -114,6 +116,7 @@ fn body() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -165,6 +168,7 @@ fn dependencies() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -253,6 +257,7 @@ fn dependency_argument() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -305,6 +310,7 @@ fn duplicate_recipes() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -339,6 +345,7 @@ fn doc_comment() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -361,6 +368,7 @@ fn empty_justfile() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -492,6 +500,7 @@ fn parameters() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -562,6 +571,7 @@ fn priors() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -596,6 +606,7 @@ fn private() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -630,6 +641,7 @@ fn quiet() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -685,6 +697,7 @@ fn settings() {
|
||||
"command": "a",
|
||||
},
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -722,6 +735,7 @@ fn shebang() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
@ -756,6 +770,7 @@ fn simple() {
|
||||
"positional_arguments": false,
|
||||
"shell": null,
|
||||
"windows_powershell": false,
|
||||
"windows_shell": null,
|
||||
},
|
||||
"warnings": [],
|
||||
}),
|
||||
|
@ -45,4 +45,6 @@ mod tempdir;
|
||||
mod undefined_variables;
|
||||
#[cfg(target_family = "windows")]
|
||||
mod windows_powershell;
|
||||
#[cfg(target_family = "windows")]
|
||||
mod windows_shell;
|
||||
mod working_directory;
|
||||
|
18
tests/windows_shell.rs
Normal file
18
tests/windows_shell.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[test]
|
||||
fn windows_shell_setting() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
r#"
|
||||
set windows-shell := ["pwsh.exe", "-NoLogo", "-Command"]
|
||||
|
||||
foo:
|
||||
Write-Output bar
|
||||
"#,
|
||||
)
|
||||
.shell(false)
|
||||
.stdout("bar\r\n")
|
||||
.stderr("Write-Output bar\n")
|
||||
.run();
|
||||
}
|
Loading…
Reference in New Issue
Block a user