99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import {
|
|
chmodSync,
|
|
existsSync,
|
|
lstatSync,
|
|
mkdirSync,
|
|
mkdtempSync,
|
|
readFileSync,
|
|
rmSync,
|
|
symlinkSync,
|
|
writeFileSync,
|
|
} from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { afterEach, test } from "vitest";
|
|
|
|
import { ensureManagedTools, resolveToolFromPath } from "../tool-bootstrap.js";
|
|
|
|
const FD_TARGET = process.platform === "win32" ? "fd.exe" : "fd";
|
|
const RG_TARGET = process.platform === "win32" ? "rg.exe" : "rg";
|
|
|
|
function makeExecutable(
|
|
dir: string,
|
|
name: string,
|
|
content = "#!/bin/sh\nexit 0\n",
|
|
): string {
|
|
const file = join(dir, name);
|
|
writeFileSync(file, content);
|
|
chmodSync(file, 0o755);
|
|
return file;
|
|
}
|
|
|
|
test("resolveToolFromPath finds fd via fdfind fallback", (_t) => {
|
|
const tmp = mkdtempSync(join(tmpdir(), "sf-tool-bootstrap-resolve-"));
|
|
afterEach(() => {
|
|
rmSync(tmp, { recursive: true, force: true });
|
|
});
|
|
|
|
makeExecutable(tmp, "fdfind");
|
|
const resolved = resolveToolFromPath("fd", tmp);
|
|
assert.equal(resolved, join(tmp, "fdfind"));
|
|
});
|
|
|
|
test("ensureManagedTools provisions fd and rg into managed bin dir", (_t) => {
|
|
const tmp = mkdtempSync(join(tmpdir(), "sf-tool-bootstrap-provision-"));
|
|
const sourceBin = join(tmp, "source-bin");
|
|
const targetBin = join(tmp, "target-bin");
|
|
|
|
mkdirSync(sourceBin, { recursive: true });
|
|
mkdirSync(targetBin, { recursive: true });
|
|
|
|
afterEach(() => {
|
|
rmSync(tmp, { recursive: true, force: true });
|
|
});
|
|
|
|
makeExecutable(sourceBin, "fdfind");
|
|
makeExecutable(sourceBin, "rg");
|
|
|
|
const provisioned = ensureManagedTools(targetBin, sourceBin);
|
|
|
|
assert.equal(provisioned.length, 2);
|
|
assert.ok(existsSync(join(targetBin, FD_TARGET)));
|
|
assert.ok(existsSync(join(targetBin, RG_TARGET)));
|
|
assert.ok(
|
|
lstatSync(join(targetBin, FD_TARGET)).isSymbolicLink() ||
|
|
lstatSync(join(targetBin, FD_TARGET)).isFile(),
|
|
);
|
|
assert.ok(
|
|
lstatSync(join(targetBin, RG_TARGET)).isSymbolicLink() ||
|
|
lstatSync(join(targetBin, RG_TARGET)).isFile(),
|
|
);
|
|
});
|
|
|
|
test("ensureManagedTools copies executable when symlink target already exists as a broken link", (_t) => {
|
|
const tmp = mkdtempSync(join(tmpdir(), "sf-tool-bootstrap-copy-"));
|
|
const sourceBin = join(tmp, "source-bin");
|
|
const targetBin = join(tmp, "target-bin");
|
|
const targetFd = join(targetBin, FD_TARGET);
|
|
|
|
mkdirSync(sourceBin, { recursive: true });
|
|
mkdirSync(targetBin, { recursive: true });
|
|
|
|
afterEach(() => {
|
|
rmSync(tmp, { recursive: true, force: true });
|
|
});
|
|
|
|
makeExecutable(sourceBin, "fdfind", "#!/bin/sh\necho fd\n");
|
|
makeExecutable(sourceBin, "rg", "#!/bin/sh\necho rg\n");
|
|
symlinkSync(join(tmp, "missing-target"), targetFd);
|
|
|
|
const provisioned = ensureManagedTools(targetBin, sourceBin);
|
|
|
|
assert.equal(provisioned.length, 2);
|
|
assert.ok(
|
|
lstatSync(targetFd).isFile(),
|
|
"fd fallback should replace broken symlink with a copied file",
|
|
);
|
|
assert.match(readFileSync(targetFd, "utf8"), /echo fd/);
|
|
});
|