import {} from "./utils/get_temp_directory.ts";import { ensureDir } from "./deps/fs.ts";import { path } from "./deps/path.ts";import { Logger } from "./deps/std.ts";import { CacheError } from "./errors.ts";import { createLogger } from "./logger.ts";import { Store } from "./store.ts";import { getPath } from "./utils.ts";import { getHomeDirectory } from "./utils/get_home_directory.ts";
export interface Cache { hasKey(key: string): boolean;
getDownloadPath(key: string): string;
getKey(hash: string, object: object): string;}
export class EmptyCache implements Cache { getDownloadPath(key: string): string { return getPath(path.join(getTempDirectory(), ".scaffold", key)); }
getKey(_: string, _object: object): string { return crypto.randomUUID(); }
hasKey(_: string): boolean { return false; }}
export interface RepositoryCacheProps { directory?: string; log?: Logger;}
export class RepositoryCache extends EmptyCache { readonly #directory: string; readonly #log: Logger; readonly #store: Store;
#entries = new Map<string, string>();
get store(): Store { return this.#store; }
constructor(props: RepositoryCacheProps) { super(); const directory = props.directory ?? getDefaultCache();
if (!directory) { throw new CacheError( "Could not determine home directory for this operating system.", ); }
this.#log = props.log ?? createLogger({ name: "scaffold:cache", levelName: "CRITICAL" }); this.#directory = directory; this.#store = new Store(path.join(directory, "store.json")); }
async load() { this.#log.debug("loading cache", { directory: this.#directory }); await ensureDir(this.#directory);
for await (const entry of Deno.readDir(this.#directory)) { if (!entry.isDirectory) { continue; }
this.#entries.set(entry.name, path.join(this.#directory, entry.name)); }
await this.#store.load();
this.#log.debug("Every cache item", ...this.#entries.keys()); }
override getDownloadPath(key = "") { return getPath(path.join(this.#directory, key)); }
async reset() { this.#entries.clear(); await Deno.remove(this.#directory, { recursive: true }); await this.store.reset(); }
permissions(key: string): string { return path.join(this.#directory, `${key}.json`); }
get(hash: string) { return this.#entries.get(hash); }
override hasKey(hash: string): boolean { return this.#entries.has(hash); }
override getKey( hash: string, object: Record<string, string | undefined>, ): string { const { user = "", name = "", site = "", subdirectory = "" } = object; const parts = [user, name, site, subdirectory, hash]; let key = "";
for (let part of parts) { part = clean(part, key ? "-" : ""); key += part; }
return key; }}
function clean(value: string | undefined, prefix = "") { return value ? `${prefix}${value.replace(/\//g, "--").replace(/[^a-zA-Z0-9_-]/g, "")}` : "";}
function getDefaultCache() { const homeDirectory = getHomeDirectory();
if (!homeDirectory) { return; }
return path.join(homeDirectory, ".scaffold", "cache");}
export function getTempDirectory() { if (Deno.build.os === "windows") { return Deno.env.get("TMP") || Deno.env.get("TEMP") || Deno.env.get("USERPROFILE") || Deno.env.get("SystemRoot") || ""; }
return Deno.env.get("TMPDIR") || "/tmp";}