better bash detection on unix - also try PATH

This commit is contained in:
Vaclav Synacek 2026-02-03 19:58:40 +01:00
parent c983bfdb1e
commit 12392790d1

View file

@ -7,14 +7,31 @@ import { SettingsManager } from "../core/settings-manager.js";
let cachedShellConfig: { shell: string; args: string[] } | null = null; let cachedShellConfig: { shell: string; args: string[] } | null = null;
/** /**
* Find bash executable on PATH (Windows) * Find bash executable on PATH (cross-platform)
*/ */
function findBashOnPath(): string | null { function findBashOnPath(): string | null {
if (process.platform === "win32") {
// Windows: Use 'where' and verify file exists (where can return non-existent paths)
try {
const result = spawnSync("where", ["bash.exe"], { encoding: "utf-8", timeout: 5000 });
if (result.status === 0 && result.stdout) {
const firstMatch = result.stdout.trim().split(/\r?\n/)[0];
if (firstMatch && existsSync(firstMatch)) {
return firstMatch;
}
}
} catch {
// Ignore errors
}
return null;
}
// Unix: Use 'which' and trust its output (handles Termux and special filesystems)
try { try {
const result = spawnSync("where", ["bash.exe"], { encoding: "utf-8", timeout: 5000 }); const result = spawnSync("which", ["bash"], { encoding: "utf-8", timeout: 5000 });
if (result.status === 0 && result.stdout) { if (result.status === 0 && result.stdout) {
const firstMatch = result.stdout.trim().split(/\r?\n/)[0]; const firstMatch = result.stdout.trim().split(/\r?\n/)[0];
if (firstMatch && existsSync(firstMatch)) { if (firstMatch) {
return firstMatch; return firstMatch;
} }
} }
@ -29,8 +46,7 @@ function findBashOnPath(): string | null {
* Resolution order: * Resolution order:
* 1. User-specified shellPath in settings.json * 1. User-specified shellPath in settings.json
* 2. On Windows: Git Bash in known locations, then bash on PATH * 2. On Windows: Git Bash in known locations, then bash on PATH
* 3. On Unix: /bin/bash * 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh
* 4. Fallback: sh
*/ */
export function getShellConfig(): { shell: string; args: string[] } { export function getShellConfig(): { shell: string; args: string[] } {
if (cachedShellConfig) { if (cachedShellConfig) {
@ -86,12 +102,18 @@ export function getShellConfig(): { shell: string; args: string[] } {
); );
} }
// Unix: prefer bash over sh // Unix: try /bin/bash, then bash on PATH, then fallback to sh
if (existsSync("/bin/bash")) { if (existsSync("/bin/bash")) {
cachedShellConfig = { shell: "/bin/bash", args: ["-c"] }; cachedShellConfig = { shell: "/bin/bash", args: ["-c"] };
return cachedShellConfig; return cachedShellConfig;
} }
const bashOnPath = findBashOnPath();
if (bashOnPath) {
cachedShellConfig = { shell: bashOnPath, args: ["-c"] };
return cachedShellConfig;
}
cachedShellConfig = { shell: "sh", args: ["-c"] }; cachedShellConfig = { shell: "sh", args: ["-c"] };
return cachedShellConfig; return cachedShellConfig;
} }