Resolve Python via where on Windows

This commit is contained in:
2026-05-02 20:46:09 +09:00
parent 4202911b3e
commit 2667fc2632

View File

@@ -28,6 +28,55 @@ async function canRun(command: string, args: string[]): Promise<boolean> {
});
}
async function captureStdout(command: string, args: string[]): Promise<string | null> {
return await new Promise<string | null>((resolve) => {
const child = spawn(command, args, {
stdio: ["ignore", "pipe", "ignore"],
windowsHide: true,
});
let stdout = "";
child.stdout.on("data", (chunk: Buffer) => {
stdout += chunk.toString();
});
child.on("error", () => {
resolve(null);
});
child.on("exit", (code) => {
if (code === 0) {
resolve(stdout);
return;
}
resolve(null);
});
});
}
async function resolveWindowsExecutable(name: string): Promise<string | null> {
const stdout = await captureStdout("cmd.exe", ["/d", "/s", "/c", `where ${name}`]);
if (!stdout) {
return null;
}
const candidates = stdout
.split(/\r?\n/)
.map((line) => line.trim())
.filter((line) => line.length > 0);
for (const candidate of candidates) {
try {
await access(candidate, fsConstants.F_OK);
return candidate;
} catch {
// ignore
}
}
return null;
}
async function fileExists(target: string): Promise<boolean> {
try {
await access(target, fsConstants.X_OK);
@@ -64,6 +113,11 @@ export async function resolveBasePythonCommand(config: AppConfig): Promise<{ com
];
for (const candidate of candidates) {
const absolute = await resolveWindowsExecutable(candidate.command);
if (absolute && (await canRun(absolute, candidate.args))) {
return { command: absolute, args: candidate.args };
}
if (await canRun(candidate.command, candidate.args)) {
return candidate;
}