mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
136 lines
4.2 KiB
TypeScript
136 lines
4.2 KiB
TypeScript
import {
|
|
ArtifactResourceScope,
|
|
type ArtifactResourceOwner,
|
|
} from "../../src/artifacts/ArtifactResourceScope.js";
|
|
import { onTestFinished } from "vitest";
|
|
import { ArtifactReaderFailure } from "../../src/artifacts/ArtifactReader.js";
|
|
import { classifyAndHashRootForInventory } from "../../src/artifacts/inventory/classify.js";
|
|
import {
|
|
inventoryArtifact as inventoryArtifactOwned,
|
|
scanArtifactInventoryInScope,
|
|
} from "../../src/artifacts/inventory/ArtifactInventory.js";
|
|
import { scanCanonicalArtifactInventoryInScope } from "../../src/artifacts/inventory/scanCanonical.js";
|
|
import type { createReader } from "../../src/artifacts/inventory/reader.js";
|
|
import {
|
|
materializeArtifactInventoryInScope,
|
|
type ArtifactExtractionInput,
|
|
} from "../../src/artifacts/extraction/ArtifactExtraction.js";
|
|
import type { ArtifactInventorySnapshot } from "../../src/domain/artifactInventorySnapshot.js";
|
|
import type { ArtifactInventoryOptions } from "../../src/artifacts/inventory/types.js";
|
|
|
|
type InventoryOptions = Omit<ArtifactInventoryOptions, "resourceScope">;
|
|
|
|
export const inventoryArtifact = (
|
|
path: string,
|
|
options: InventoryOptions = {},
|
|
) =>
|
|
withArtifactResourceScope((resourceScope) =>
|
|
inventoryArtifactOwned(path, { ...options, resourceScope }),
|
|
);
|
|
|
|
export const classifyAndHashRoot = (
|
|
path: string,
|
|
directory: boolean,
|
|
expectedMetadata: import("node:fs").Stats,
|
|
signal?: AbortSignal,
|
|
) =>
|
|
withArtifactResourceScope((resourceScope) =>
|
|
resourceScope.run(async () => {
|
|
const result = await classifyAndHashRootForInventory(
|
|
path,
|
|
directory,
|
|
expectedMetadata,
|
|
{ resourceScope, ...(signal === undefined ? {} : { signal }) },
|
|
);
|
|
const rootSource = result.rootSource;
|
|
if (rootSource !== undefined) {
|
|
const owner: ArtifactResourceOwner = {
|
|
kind: "file-handle",
|
|
handle: rootSource.owner,
|
|
resource: `root artifact descriptor for ${path}`,
|
|
};
|
|
const cleanupAttempt = await resourceScope.release(owner);
|
|
if (cleanupAttempt.kind === "failed")
|
|
throw resourceScope.cleanupFailure({ kind: "completed" }, [
|
|
cleanupAttempt,
|
|
]);
|
|
}
|
|
return { format: result.format, digest: result.digest };
|
|
}),
|
|
);
|
|
|
|
export const scanArtifactInventory = (
|
|
path: string,
|
|
options: InventoryOptions = {},
|
|
) =>
|
|
withArtifactResourceScope((resourceScope) =>
|
|
resourceScope.run(() =>
|
|
scanArtifactInventoryInScope(path, { ...options, resourceScope }),
|
|
),
|
|
);
|
|
|
|
export const scanCanonicalArtifactInventory = (
|
|
path: string,
|
|
options: InventoryOptions = {},
|
|
readerFactory?: typeof createReader,
|
|
) =>
|
|
withArtifactResourceScope((resourceScope) =>
|
|
resourceScope.run(() =>
|
|
scanCanonicalArtifactInventoryInScope(
|
|
path,
|
|
{ ...options, resourceScope },
|
|
readerFactory,
|
|
),
|
|
),
|
|
);
|
|
|
|
export const materializeArtifactInventory = (
|
|
input: Omit<ArtifactExtractionInput, "resourceScope">,
|
|
sourcePath: string,
|
|
snapshot: ArtifactInventorySnapshot,
|
|
signal?: AbortSignal,
|
|
) =>
|
|
withArtifactResourceScope((resourceScope) =>
|
|
resourceScope.run(() =>
|
|
materializeArtifactInventoryInScope(
|
|
{ ...input, resourceScope },
|
|
sourcePath,
|
|
snapshot,
|
|
signal,
|
|
),
|
|
),
|
|
);
|
|
|
|
export const withArtifactResourceScope = async <T>(
|
|
operation: (resourceScope: ArtifactResourceScope) => Promise<T>,
|
|
): Promise<T> => {
|
|
const resourceScope = new ArtifactResourceScope();
|
|
onTestFinished(() => resourceScope.close());
|
|
let outcome:
|
|
| { readonly kind: "completed"; readonly value: T }
|
|
| { readonly kind: "failed"; readonly cause: unknown };
|
|
try {
|
|
outcome = {
|
|
kind: "completed",
|
|
value: await operation(resourceScope),
|
|
};
|
|
} catch (cause: unknown) {
|
|
outcome = { kind: "failed", cause };
|
|
}
|
|
try {
|
|
await resourceScope.close();
|
|
} catch (cleanupCause: unknown) {
|
|
if (outcome.kind === "failed")
|
|
throw ArtifactReaderFailure.withCleanup(
|
|
outcome.cause,
|
|
ArtifactReaderFailure.cleanupObservation(
|
|
cleanupCause,
|
|
"artifact resources",
|
|
),
|
|
);
|
|
throw cleanupCause;
|
|
}
|
|
if (outcome.kind === "failed") throw outcome.cause;
|
|
return outcome.value;
|
|
};
|