fix(reference): bind Git metadata joins to physical directories
This commit is contained in:
1 parent
b5e43edf7f
commit
5c16a85a67
2 files changed
+45
-5
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { lstat } from "node:fs/promises";
|
||||
import { lstat, realpath } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { absoluteCallerPath } from "../filesystem/callerPath.js";
|
||||
|
||||
@@ -29,20 +29,29 @@ export const locateReferenceSourceGitDirectory = async (
|
||||
repository = parent;
|
||||
continue;
|
||||
}
|
||||
let gitDirectory = dotgit;
|
||||
let selectedGitDirectory = dotgit;
|
||||
if (metadata.isFile()) {
|
||||
const pointer = (await readText(dotgit)).replace(/\r?\n$/u, "");
|
||||
if (!pointer.startsWith("gitdir: ") || pointer.length === 8)
|
||||
throw new Error("Invalid Git directory pointer");
|
||||
gitDirectory = absoluteCallerPath(pointer.slice(8), { cwd: repository });
|
||||
selectedGitDirectory = absoluteCallerPath(pointer.slice(8), {
|
||||
cwd: repository,
|
||||
});
|
||||
}
|
||||
// Derived joins and the Git library normalize paths lexically. Admit the
|
||||
// physical directory first, while the source pointer stays in its file.
|
||||
const gitDirectory = await realpath(selectedGitDirectory);
|
||||
let commonDirectory = gitDirectory;
|
||||
try {
|
||||
const common = (await readText(join(gitDirectory, "commondir"))).replace(
|
||||
/\r?\n$/u,
|
||||
"",
|
||||
);
|
||||
commonDirectory = absoluteCallerPath(common, { cwd: gitDirectory });
|
||||
if (common.length === 0)
|
||||
throw new Error("Invalid Git common-directory pointer");
|
||||
commonDirectory = await realpath(
|
||||
absoluteCallerPath(common, { cwd: gitDirectory }),
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
if (!hasCode(cause, "ENOENT")) throw cause;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { mkdir, readFile, symlink, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { expect, it } from "vitest";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
@@ -124,3 +124,34 @@ it.each([false, true])(
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(process.platform === "win32")(
|
||||
"binds Git pointer/configuration reads to physical symlink-parent selection",
|
||||
async () => {
|
||||
const root = await createTestTempDirectory("rea-reference-git-parent-");
|
||||
const source = join(root, "source");
|
||||
const physical = join(root, "physical");
|
||||
await mkdir(source);
|
||||
await mkdir(join(physical, "child"), { recursive: true });
|
||||
await mkdir(join(physical, "metadata"));
|
||||
await mkdir(join(source, "metadata"));
|
||||
await symlink(join(physical, "child"), join(source, "alias"));
|
||||
const intendedHead = "1".repeat(40);
|
||||
for (const [directory, head, ignoreCase] of [
|
||||
[join(physical, "metadata"), intendedHead, false],
|
||||
[join(source, "metadata"), "2".repeat(40), true],
|
||||
] as const) {
|
||||
await writeFile(join(directory, "HEAD"), `${head}\n`);
|
||||
await writeFile(
|
||||
join(directory, "config"),
|
||||
`[core]\nignorecase = ${String(ignoreCase)}\n`,
|
||||
);
|
||||
}
|
||||
await writeFile(join(source, ".git"), "gitdir: alias/../metadata\n");
|
||||
await writeFile(join(source, ".gitignore"), "*.TMP\n");
|
||||
await writeFile(join(source, "lower.tmp"), "selected policy\n");
|
||||
const graph = await importTree(source);
|
||||
expect(graph.entries.some(({ path }) => path === "lower.tmp")).toBe(true);
|
||||
expect(graph.vcs).toMatchObject({ kind: "git", head: intendedHead });
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user