This commit is contained in:
Andrew Bradley 2025-12-15 14:36:39 -05:00 committed by GitHub
commit 353fec7bcb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 75 additions and 2 deletions

View file

@ -93,6 +93,11 @@ path = "src/main.rs"
name = "just"
test = false
[[bin]]
path = "src/bin/echoargs.rs"
name = "echoargs"
test = false
# The public documentation is minimal and doesn't change between
# platforms, so we only build them for linux on docs.rs to save
# their build machines some cycles.

6
src/bin/echoargs.rs Normal file
View file

@ -0,0 +1,6 @@
use std::env;
fn main() {
let args: Vec<String> = env::args().skip(1).collect();
println!("{}", args.join(" "));
}

View file

@ -1,6 +1,8 @@
use super::*;
pub(crate) trait CommandExt {
fn with_explicit_path(&mut self) -> &mut Command;
fn export(
&mut self,
settings: &Settings,
@ -19,6 +21,18 @@ pub(crate) trait CommandExt {
}
impl CommandExt for Command {
fn with_explicit_path(&mut self) -> &mut Command {
// On Windows, set child's path explicitly so that spawned executable
// is located on path before System32 fallback, not the other way around.
// https://blog.rust-lang.org/2022/01/13/Rust-1.58.0/#reduced-windows-command-search-path
#[cfg(windows)]
if let Some(path) = std::env::var_os("Path") {
self.env("Path", path);
}
self
}
fn export(
&mut self,
settings: &Settings,

View file

@ -16,6 +16,7 @@ impl Executor<'_> {
match self {
Self::Command(interpreter) => {
let mut command = Command::new(&interpreter.command.cooked);
command.with_explicit_path();
if let Some(working_directory) = working_directory {
command.current_dir(working_directory);

View file

@ -157,7 +157,9 @@ impl<'src> Justfile<'src> {
command.arg(binary);
command
} else {
Command::new(binary)
let mut command = Command::new(binary);
command.with_explicit_path();
command
};
command

View file

@ -32,6 +32,7 @@ impl PlatformInterface for Platform {
};
let mut cmd = Command::new(command.as_ref());
cmd.with_explicit_path();
if let Some(working_directory) = working_directory {
cmd.current_dir(working_directory);

View file

@ -106,6 +106,7 @@ impl<'src> Settings<'src> {
let (command, args) = self.shell(config);
let mut cmd = Command::new(command);
cmd.with_explicit_path();
cmd.args(args);

View file

@ -307,7 +307,7 @@ impl Subcommand {
.or_else(|| env::var_os("EDITOR"))
.unwrap_or_else(|| "vim".into());
let error = Command::new(&editor)
let error = Command::new(&editor).with_explicit_path()
.current_dir(&search.working_directory)
.arg(&search.justfile)
.status();

View file

@ -135,6 +135,8 @@ mod unstable;
mod which_function;
#[cfg(windows)]
mod windows;
#[cfg(windows)]
mod windows_path_resolution;
#[cfg(target_family = "windows")]
mod windows_shell;
mod working_directory;

View file

@ -0,0 +1,41 @@
use super::*;
#[cfg(windows)]
#[test]
fn windows_path_resolution() {
// Goal: Confirm that $PATH entries are respected *before* C:\Windows\System32 when
// locating shell executable. This can happen when PATH is configured to prefer
// Git-for-Windows' bash.exe, and just must not call C:\Windows\System32\bash.exe
// https://github.com/casey/just/issues/2947
// Copy echoargs.exe to temp directory as where.exe, to intentionally match
// the name of an executable in C:\Windows\System32
let mut echoargs_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
echoargs_path.push("target");
echoargs_path.push("debug");
echoargs_path.push("echoargs.exe");
let tmp = tempdir();
let tmp_subdir= tmp.path().join("subdir");
let tmp_subdir_path = tmp_subdir.as_path();
let exe_path = tmp_subdir_path.join("where.exe");
std::fs::create_dir(tmp_subdir_path).expect("Failed to create temp subdirectory");
std::fs::copy(&echoargs_path, &exe_path)
.expect("Failed to copy exe to temp directory");
// Prepend temp directory to PATH
let new_path = tmp_subdir_path.to_str().unwrap().to_owned() + ";" + &env::var("PATH").unwrap();
Test::with_tempdir(tmp)
.shell(false)
.env("Path", &new_path)
.justfile(
r#"
set shell := ['where.exe']
@default:
test_marker
"#,
)
.stdout("test_marker\n")
.run();
}