mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 16:57:19 +00:00
fix(reference): separate local filesystem diagnostics from graph commitments
This commit is contained in:
1 parent
b165b0e830
commit
cae03361cf
12 files changed
+220
-38
No files matched your search
@@ -12,6 +12,7 @@ import {
|
||||
failure,
|
||||
filesystemFailureDetail,
|
||||
safeSize,
|
||||
type FilesystemFailureDetail,
|
||||
} from "./ReferenceSourceReaderErrors.js";
|
||||
import { isPathWithinRoot } from "../domain/localPath.js";
|
||||
import { pathFromRoot } from "./ReferenceSourceReaderPaths.js";
|
||||
@@ -37,8 +38,10 @@ const recordDirectoryFailure = (
|
||||
absolute: string,
|
||||
code: ReferenceSourceFailureCode,
|
||||
message: string,
|
||||
localDiagnostic?: string,
|
||||
): void => {
|
||||
if (absolute === state.root) state.rootFailure = { code, message };
|
||||
if (absolute === state.root)
|
||||
state.rootFailure = { code, message: localDiagnostic ?? message };
|
||||
else
|
||||
state.entries.push(
|
||||
entryFailure(
|
||||
@@ -46,6 +49,8 @@ const recordDirectoryFailure = (
|
||||
"directory",
|
||||
code,
|
||||
message,
|
||||
undefined,
|
||||
localDiagnostic,
|
||||
),
|
||||
);
|
||||
};
|
||||
@@ -62,7 +67,13 @@ export const traverseDirectory = async (
|
||||
);
|
||||
if (isAborted(state.signal)) return { ok: false, error: cancelled() };
|
||||
if (!before.ok) {
|
||||
recordDirectoryFailure(state, current.path, before.code, before.message);
|
||||
recordDirectoryFailure(
|
||||
state,
|
||||
current.path,
|
||||
before.code,
|
||||
before.message,
|
||||
before.localDiagnostic,
|
||||
);
|
||||
return { ok: true, value: undefined };
|
||||
}
|
||||
const policy = await state.beforeDirectory?.(
|
||||
@@ -71,7 +82,7 @@ export const traverseDirectory = async (
|
||||
if (policy !== undefined && !policy.ok) return policy;
|
||||
if (isAborted(state.signal)) return err(cancelled());
|
||||
const directories: PendingDirectory[] = [];
|
||||
let readFailure: string | undefined;
|
||||
let readFailure: FilesystemFailureDetail | undefined;
|
||||
let unrepresentableNameCount = 0;
|
||||
let firstUnrepresentableNameHex: string | undefined;
|
||||
let handle: Dir | undefined;
|
||||
@@ -100,7 +111,9 @@ export const traverseDirectory = async (
|
||||
}
|
||||
if (child === null) break;
|
||||
if (!Buffer.isBuffer(child.name)) {
|
||||
readFailure = "Directory entry name was not returned as raw bytes";
|
||||
readFailure = {
|
||||
message: "Directory entry name was not returned as raw bytes",
|
||||
};
|
||||
break;
|
||||
}
|
||||
const decoded = decodeDirectoryEntryName(child.name);
|
||||
@@ -121,7 +134,13 @@ export const traverseDirectory = async (
|
||||
}
|
||||
if (cleanup.kind === "failed") {
|
||||
if (result.ok && !isAborted(state.signal) && readFailure !== undefined)
|
||||
recordDirectoryFailure(state, current.path, "io", readFailure);
|
||||
recordDirectoryFailure(
|
||||
state,
|
||||
current.path,
|
||||
"io",
|
||||
readFailure.message,
|
||||
readFailure.localDiagnostic,
|
||||
);
|
||||
const observation = ArtifactReaderFailure.cleanupObservation(
|
||||
cleanup.cause,
|
||||
current.path,
|
||||
@@ -132,7 +151,8 @@ export const traverseDirectory = async (
|
||||
? cancelled()
|
||||
: failure(
|
||||
"io",
|
||||
readFailure ??
|
||||
readFailure?.localDiagnostic ??
|
||||
readFailure?.message ??
|
||||
`Reference directory cleanup failed: ${current.path}`,
|
||||
)
|
||||
: result.error;
|
||||
@@ -154,7 +174,13 @@ export const traverseDirectory = async (
|
||||
}
|
||||
if (isAborted(state.signal)) return { ok: false, error: cancelled() };
|
||||
if (readFailure !== undefined) {
|
||||
recordDirectoryFailure(state, current.path, "io", readFailure);
|
||||
recordDirectoryFailure(
|
||||
state,
|
||||
current.path,
|
||||
"io",
|
||||
readFailure.message,
|
||||
readFailure.localDiagnostic,
|
||||
);
|
||||
scheduleObservedDirectories(state, directories);
|
||||
return { ok: true, value: undefined };
|
||||
}
|
||||
@@ -171,6 +197,7 @@ export const traverseDirectory = async (
|
||||
current.path,
|
||||
after.ok ? "changed" : after.code,
|
||||
after.ok ? "Directory changed while it was read" : after.message,
|
||||
after.ok ? undefined : after.localDiagnostic,
|
||||
);
|
||||
scheduleObservedDirectories(state, directories);
|
||||
return { ok: true, value: undefined };
|
||||
@@ -200,27 +227,27 @@ const scheduleObservedDirectories = (
|
||||
state.pending.push(...directories);
|
||||
};
|
||||
|
||||
const directoryReadFailure = (cause: unknown): string => {
|
||||
const message = filesystemFailureDetail(cause, "Directory could not be read");
|
||||
if (message === undefined) throw cause;
|
||||
return message;
|
||||
const directoryReadFailure = (cause: unknown): FilesystemFailureDetail => {
|
||||
const detail = filesystemFailureDetail(cause, "Directory could not be read");
|
||||
if (detail === undefined) throw cause;
|
||||
return detail;
|
||||
};
|
||||
|
||||
const readMetadata = async (
|
||||
path: string,
|
||||
): Promise<
|
||||
| { readonly ok: true; readonly value: BigIntStats }
|
||||
| { readonly ok: false; readonly message: string }
|
||||
| ({ readonly ok: false } & FilesystemFailureDetail)
|
||||
> => {
|
||||
try {
|
||||
return { ok: true, value: await bigLstat(path) };
|
||||
} catch (cause: unknown) {
|
||||
const message = filesystemFailureDetail(
|
||||
const detail = filesystemFailureDetail(
|
||||
cause,
|
||||
"Entry metadata could not be read",
|
||||
);
|
||||
if (message === undefined) throw cause;
|
||||
return { ok: false, message };
|
||||
if (detail === undefined) throw cause;
|
||||
return { ok: false, ...detail };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -246,7 +273,16 @@ const processEntry = async (
|
||||
state.exclusions.push({ path, kind: "unknown" });
|
||||
return { ok: true, value: undefined };
|
||||
}
|
||||
state.entries.push(entryFailure(path, "unknown", "io", metadata.message));
|
||||
state.entries.push(
|
||||
entryFailure(
|
||||
path,
|
||||
"unknown",
|
||||
"io",
|
||||
metadata.message,
|
||||
undefined,
|
||||
metadata.localDiagnostic,
|
||||
),
|
||||
);
|
||||
return { ok: true, value: undefined };
|
||||
}
|
||||
const kind = metadata.value.isSymbolicLink()
|
||||
@@ -357,12 +393,19 @@ export const readStableSymlinkTarget = async (
|
||||
const code =
|
||||
cause instanceof Error ? Reflect.get(cause, "code") : undefined;
|
||||
if (code === "ENOENT" || code === "ENOTDIR") return changedSymlink(path);
|
||||
const message = filesystemFailureDetail(
|
||||
const detail = filesystemFailureDetail(
|
||||
cause,
|
||||
"Symbolic link target could not be read safely",
|
||||
);
|
||||
if (message === undefined) throw cause;
|
||||
return entryFailure(path, "symlink", "io", message);
|
||||
if (detail === undefined) throw cause;
|
||||
return entryFailure(
|
||||
path,
|
||||
"symlink",
|
||||
"io",
|
||||
detail.message,
|
||||
undefined,
|
||||
detail.localDiagnostic,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user