Improve bash detection on Windows (#43455)
qystishere
created 2 weeks ago
I have git installed via [scoop](https://scoop.sh). The current
implementation finds `git.exe` in scoop's shims folder and then tries to
find `bash.exe` relative to it.
For example, `git.exe` (shim) is located at:
```
C:\Users\<username>\scoop\shims\git.exe
```
And the code tries to find `bash.exe` at:
```
C:\Users\<username>\scoop\shims\..\bin\bash.exe
```
which doesn't exist.
This PR changes the logic to first check if `bash.exe` is available in
PATH (using `which::which`), and only falls back to the git-relative
path if that fails.
Change summary
crates/util/src/shell.rs | 33 +++++++++++++++++++++++----------
1 file changed, 23 insertions(+), 10 deletions(-)
Detailed changes
@@ -79,29 +79,42 @@ pub fn get_default_system_shell() -> String {
}
}
-/// Get the default system shell, preferring git-bash on Windows.
+/// Get the default system shell, preferring bash on Windows.
pub fn get_default_system_shell_preferring_bash() -> String {
if cfg!(windows) {
- get_windows_git_bash().unwrap_or_else(|| get_windows_system_shell())
+ get_windows_bash().unwrap_or_else(|| get_windows_system_shell())
} else {
"/bin/sh".to_string()
}
}
-pub fn get_windows_git_bash() -> Option<String> {
- static GIT_BASH: LazyLock<Option<String>> = LazyLock::new(|| {
+pub fn get_windows_bash() -> Option<String> {
+ use std::path::PathBuf;
+
+ fn find_bash_in_scoop() -> Option<PathBuf> {
+ let bash_exe =
+ PathBuf::from(std::env::var_os("USERPROFILE")?).join("scoop\\shims\\bash.exe");
+ bash_exe.exists().then_some(bash_exe)
+ }
+
+ fn find_bash_in_git() -> Option<PathBuf> {
// /path/to/git/cmd/git.exe/../../bin/bash.exe
let git = which::which("git").ok()?;
let git_bash = git.parent()?.parent()?.join("bin").join("bash.exe");
- if git_bash.is_file() {
- log::info!("Found git-bash at {}", git_bash.display());
- Some(git_bash.to_string_lossy().to_string())
- } else {
- None
+ git_bash.exists().then_some(git_bash)
+ }
+
+ static BASH: LazyLock<Option<String>> = LazyLock::new(|| {
+ let bash = find_bash_in_scoop()
+ .or_else(|| find_bash_in_git())
+ .map(|p| p.to_string_lossy().into_owned());
+ if let Some(ref path) = bash {
+ log::info!("Found bash at {}", path);
}
+ bash
});
- (*GIT_BASH).clone()
+ (*BASH).clone()
}
pub fn get_windows_system_shell() -> String {