Merge PR #7498: fix(utils): honor current PATH in cached lookups (@usr-bin-roygbiv)

This commit is contained in:
can1357
2026-08-05 01:11:56 +02:00
2 changed files with 43 additions and 4 deletions
+6 -4
View File
@@ -183,8 +183,8 @@ export interface WhichOptions extends Bun.WhichOptions {
// Darwin-specific "which" shim: consult Xcode/CLT toolchain directories after $PATH.
// Uses cached directory listings instead of per-command existsSync or xcrun subprocesses.
function darwinWhich(command: string, _options?: Bun.WhichOptions): string | null {
const regular = Bun.which(command);
function darwinWhich(command: string, options?: Bun.WhichOptions): string | null {
const regular = Bun.which(command, options);
if (regular) return regular;
if (isXcodeBin(command)) {
return getMacosToolPaths().get(command) ?? null;
@@ -214,17 +214,19 @@ function cacheKey(command: string, options?: Bun.WhichOptions): CacheKey {
*/
export function $which(command: string, options?: WhichOptions): string | null {
const cachePolicy = options?.cache ?? WhichCachePolicy.Cached;
const lookupOptions =
options?.PATH !== undefined || process.env.PATH === undefined ? options : { ...options, PATH: process.env.PATH };
let key: CacheKey | undefined;
if (cachePolicy !== WhichCachePolicy.Bypass) {
key = cacheKey(command, options);
key = cacheKey(command, lookupOptions);
if (cachePolicy !== WhichCachePolicy.Fresh) {
const cached = toolCache.get(key);
if (cached !== undefined) return cached;
}
}
const result = whichFresh(command, options);
const result = whichFresh(command, lookupOptions);
if (key != null && cachePolicy !== WhichCachePolicy.ReadOnly) {
toolCache.set(key, result);
}
+37
View File
@@ -0,0 +1,37 @@
import { afterEach, describe, expect, it } from "bun:test";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { $which } from "../src/which";
describe("$which", () => {
const originalPath = process.env.PATH;
const tempDirs: string[] = [];
afterEach(() => {
process.env.PATH = originalPath;
for (const dir of tempDirs.splice(0)) {
fs.rmSync(dir, { recursive: true, force: true });
}
});
it.skipIf(process.platform === "win32")("uses the current process PATH for each cached lookup", () => {
const firstDir = fs.mkdtempSync(path.join(os.tmpdir(), "omp-which-first-"));
const secondDir = fs.mkdtempSync(path.join(os.tmpdir(), "omp-which-second-"));
tempDirs.push(firstDir, secondDir);
const command = `omp-which-${process.pid}`;
const firstExecutable = path.join(firstDir, command);
const secondExecutable = path.join(secondDir, command);
fs.writeFileSync(firstExecutable, "#!/bin/sh\n");
fs.writeFileSync(secondExecutable, "#!/bin/sh\n");
fs.chmodSync(firstExecutable, 0o755);
fs.chmodSync(secondExecutable, 0o755);
process.env.PATH = firstDir;
expect($which(command)).toBe(firstExecutable);
process.env.PATH = secondDir;
expect($which(command)).toBe(secondExecutable);
});
});