This is a doozy, but I've done my best to explain it concisely.
Bug
just on Windows, by virtue of std::process::Command, does not respect $Path they way we want when resolving shell or interpreter executables. This means, when you try to use bash and you have a bash.exe on your $Path (perhaps it's Git Bash), and you coincidentally have WSL2 installed, just ignores your preferred bash.exe and instead calls C:\Windows\System32\bash.exe, which launches a shell inside the WSL2 guest virtual machine, not a bash shell on your host.
This breaks integration tests on Windows, because test.rs sets --shell bash.
It's also a bug for anyone who wants to use Git Bash or any other bash.exe as their just shell.
Fix
My proposed fix is for just to resolve executables to absolute paths using "which" or "pathsearch" crates. It can use this implementation consistently across:
which() function
set shell
[script()] / set script-interpreter
We already want which() functionality, so using it to resolve shells and interpreters to absolute paths, fixing a bug in the process, and fixing the integration tests on Windows: seems like a win all around.
Reproduction
You can reproduce it quickly if you have WSL2 installed:
# Put C:\Program Files\git\bin at the top of $Path
# Open any shell to confirm this works:
$ bash -c 'if wslinfo --version >/dev/null 2>&1; then echo BAD we are in WSL2 ; else echo GOOD, we are in Git Bash! ; fi'
GOOD, we are in Git Bash!
Now create this justfile:
set shell := ["bash", "-c"]
@default:
if wslinfo --version >/dev/null 2>&1; then echo BAD we are in WSL2 ; else echo GOOD, we are in Git Bash! ; fi
...and run it in the shell:
$ just
BAD we are in WSL2
I've created a more exhaustive reproduction here: https://github.com/cspotcode/repros2/tree/just-path-behavior-windows
Q&A
Why in the world does std::process::Command prioritize System32?
EDIT previous link was outdated
These rust release notes explain it clearly.
It checks in this order: child's $PATH if it's been explicitly set, then System32, then parent's $PATH
We want it to check $PATH before System32. (note that $PATH always contains a System32 entry, too)
It makes some (buggy, undocumented) attempts to resolve the executable only when a PATH env var has been explicitly set. In just's case, it doesn't resolve the executable, leaving it to CreateProcess which checks a bunch of places before $Path: the local directory, System32/, etc.
https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
But isn't default resolution the correct (albeit strange) behavior, since it's the rust standard library?
I argue: no, it's not what we want. The proof is that other shells intentionally don't behave this way! They resolve the target executable according to $Path before the System32 fallback, which matches user expectations. They do not give C:\Windows\System32 special treatment.
What's the problem with using WSL2 bash.exe as your shell?
It might work sometimes, break in others. For example, the C: drive is often mounted at a different location in WSL. Ultimately, just should respect $Path the same way that other shells do both on Windows and Linux.
Related tickets
#2926
#2826
rust-lang/rust#15149
rust-lang/rust#37519
This is a doozy, but I've done my best to explain it concisely.
Bug
juston Windows, by virtue ofstd::process::Command, does not respect$Paththey way we want when resolving shell or interpreter executables. This means, when you try to usebashand you have abash.exeon your$Path(perhaps it's Git Bash), and you coincidentally have WSL2 installed,justignores your preferredbash.exeand instead callsC:\Windows\System32\bash.exe, which launches a shell inside the WSL2 guest virtual machine, not a bash shell on your host.This breaks integration tests on Windows, because
test.rssets--shell bash.It's also a bug for anyone who wants to use Git Bash or any other
bash.exeas theirjustshell.Fix
My proposed fix is for
justto resolve executables to absolute paths using "which" or "pathsearch" crates. It can use this implementation consistently across:which()functionset shell[script()]/set script-interpreterWe already want
which()functionality, so using it to resolve shells and interpreters to absolute paths, fixing a bug in the process, and fixing the integration tests on Windows: seems like a win all around.Reproduction
You can reproduce it quickly if you have WSL2 installed:
Now create this justfile:
...and run it in the shell:
I've created a more exhaustive reproduction here: https://github.com/cspotcode/repros2/tree/just-path-behavior-windows
Q&A
Why in the world does std::process::Command prioritize System32?
EDIT previous link was outdated
These rust release notes explain it clearly.
It checks in this order: child's
$PATHif it's been explicitly set, then System32, then parent's$PATHWe want it to check
$PATHbefore System32. (note that$PATHalways contains a System32 entry, too)It makes some (buggy, undocumented) attempts to resolve the executable only when a PATH env var has been explicitly set. Injust's case, it doesn't resolve the executable, leaving it toCreateProcesswhich checks a bunch of places before$Path: the local directory,System32/, etc.https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessaBut isn't default resolution the correct (albeit strange) behavior, since it's the rust standard library?
I argue: no, it's not what we want. The proof is that other shells intentionally don't behave this way! They resolve the target executable according to
$Pathbefore the System32 fallback, which matches user expectations. They do not giveC:\Windows\System32special treatment.What's the problem with using WSL2 bash.exe as your shell?
It might work sometimes, break in others. For example, the C: drive is often mounted at a different location in WSL. Ultimately,
justshould respect$Paththe same way that other shells do both on Windows and Linux.Related tickets
#2926
#2826
rust-lang/rust#15149
rust-lang/rust#37519