Windows: improve Git Bash detection

This commit is contained in:
mechramc
2026-06-02 06:45:48 -05:00
committed by GitHub
parent 4709bb022e
commit 8efd7b3df6
3 changed files with 94 additions and 7 deletions

View File

@@ -14,6 +14,7 @@ Design rules:
from __future__ import annotations
import os
import ntpath
import shutil
import subprocess
from pathlib import Path
@@ -134,11 +135,40 @@ _BASH_CACHE: Optional[str] = None
_BASH_PROBED = False
# Common Git-for-Windows install locations to probe when bash isn't on PATH.
_WINDOWS_BASH_FALLBACKS = (
r"C:\Program Files\Git\bin\bash.exe",
r"C:\Program Files\Git\usr\bin\bash.exe",
r"C:\Program Files (x86)\Git\bin\bash.exe",
_WINDOWS_BASH_ROOT_ENV_VARS = (
"ProgramFiles",
"ProgramW6432",
"ProgramFiles(x86)",
"LocalAppData",
)
_WINDOWS_BASH_DEFAULT_ROOTS = (
r"C:\Program Files\Git",
r"C:\Program Files (x86)\Git",
)
_WINDOWS_BASH_RELATIVE_PATHS = (
("bin", "bash.exe"),
("usr", "bin", "bash.exe"),
)
def _windows_bash_fallbacks() -> List[str]:
roots: List[str] = []
for env_name in _WINDOWS_BASH_ROOT_ENV_VARS:
base = os.environ.get(env_name)
if base:
roots.append(ntpath.join(base, "Git"))
roots.extend(_WINDOWS_BASH_DEFAULT_ROOTS)
paths: List[str] = []
seen = set()
for root in roots:
for rel in _WINDOWS_BASH_RELATIVE_PATHS:
path = ntpath.join(root, *rel)
key = path.lower()
if key not in seen:
seen.add(key)
paths.append(path)
return paths
def find_bash() -> Optional[str]:
@@ -153,9 +183,9 @@ def find_bash() -> Optional[str]:
if _BASH_PROBED:
return _BASH_CACHE
_BASH_PROBED = True
found = shutil.which("bash")
found = which_tool("bash")
if not found and IS_WINDOWS:
for cand in _WINDOWS_BASH_FALLBACKS:
for cand in _windows_bash_fallbacks():
if os.path.exists(cand):
found = cand
break

View File

@@ -30,6 +30,26 @@ function Fail($msg) {
exit 1
}
function Find-GitBash {
$cmd = Get-Command bash -ErrorAction SilentlyContinue
if ($cmd) { return $cmd.Source }
$roots = @()
foreach ($name in @("ProgramFiles", "ProgramW6432", "ProgramFiles(x86)", "LocalAppData")) {
$base = [Environment]::GetEnvironmentVariable($name)
if ($base) { $roots += (Join-Path $base "Git") }
}
$roots += @("C:\Program Files\Git", "C:\Program Files (x86)\Git")
foreach ($root in ($roots | Select-Object -Unique)) {
foreach ($relative in @("bin\bash.exe", "usr\bin\bash.exe")) {
$candidate = Join-Path $root $relative
if (Test-Path $candidate) { return $candidate }
}
}
return $null
}
# 1. Locate a Python interpreter (3.11+ required)
Write-Step "Checking for Python"
function Get-PythonVersionText($launcher, $launcherArgs) {
@@ -101,7 +121,7 @@ Write-Step "Running first-time setup"
if ($LASTEXITCODE -ne 0) { Fail "setup.py failed." }
# 5. Friendly note about Git Bash (full Cookbook / agent-shell parity)
if (-not (Get-Command bash -ErrorAction SilentlyContinue)) {
if (-not (Find-GitBash)) {
Write-Host ""
Write-Host "NOTE: Git Bash (bash.exe) was not found on PATH." -ForegroundColor Yellow
Write-Host " The core app works without it. For full Cookbook background" -ForegroundColor Yellow

View File

@@ -0,0 +1,37 @@
"""Regression tests for cross-platform helper behavior."""
from core import platform_compat
def _reset_bash_cache(monkeypatch):
monkeypatch.setattr(platform_compat, "_BASH_CACHE", None)
monkeypatch.setattr(platform_compat, "_BASH_PROBED", False)
def test_find_bash_tries_windows_exe_suffix(monkeypatch):
_reset_bash_cache(monkeypatch)
monkeypatch.setattr(platform_compat, "IS_WINDOWS", True)
expected = r"C:\Program Files\Git\bin\bash.exe"
def fake_which(name):
return expected if name == "bash.exe" else None
monkeypatch.setattr(platform_compat.shutil, "which", fake_which)
monkeypatch.setattr(platform_compat.os.path, "exists", lambda _path: False)
assert platform_compat.find_bash() == expected
def test_find_bash_checks_local_app_data_git_install(monkeypatch):
_reset_bash_cache(monkeypatch)
monkeypatch.setattr(platform_compat, "IS_WINDOWS", True)
monkeypatch.setattr(platform_compat.shutil, "which", lambda _name: None)
for env_name in platform_compat._WINDOWS_BASH_ROOT_ENV_VARS:
monkeypatch.delenv(env_name, raising=False)
monkeypatch.setenv("LocalAppData", r"C:\Users\alice\AppData\Local")
expected = r"C:\Users\alice\AppData\Local\Git\bin\bash.exe"
monkeypatch.setattr(platform_compat.os.path, "exists", lambda path: path == expected)
assert platform_compat.find_bash() == expected