isogit-lfs/src/pointers.ts

88 lines
2 KiB
TypeScript

import path from "path-browserify";
import { Sha256 } from "@aws-crypto/sha256-universal";
import { Buffer } from "buffer";
import { SPEC_URL, toHex } from "./util";
export interface PointerInfo {
/** OID (currently, SHA256 hash) of actual blob contents. */
oid: string;
/** Actual blob size in bytes. */
size: number;
}
export interface Pointer {
info: PointerInfo;
/** Absolute path to actual blob in LFS cache. */
objectPath: string;
}
function isValidPointerInfo(val: Record<string, any>): val is PointerInfo {
return val.oid.trim !== undefined && typeof val.size === "number";
}
export function readPointerInfo(content: Buffer): PointerInfo {
const info = content
.toString()
.trim()
.split("\n")
.reduce((accum, line) => {
const [k, v] = line.split(" ", 2);
if (k === "oid") {
accum[k] = v.split(":", 2)[1];
} else if (k === "size") {
accum[k] = parseInt(v, 10);
}
return accum;
}, {} as Record<string, any>);
if (isValidPointerInfo(info)) {
return info;
} else {
throw new Error("LFS pointer is incomplete or cannot be read");
}
}
interface PointerRequest {
dir: string;
gitdir?: string;
content: Buffer;
}
export function readPointer({
dir,
gitdir = path.join(dir, ".git"),
content,
}: PointerRequest): Pointer {
const info = readPointerInfo(content);
const objectPath = path.join(
gitdir,
"lfs",
"objects",
info.oid.substr(0, 2),
info.oid.substr(2, 2),
info.oid
);
return { info, objectPath };
}
/** Formats given PointerInfo for writing in Git tree. */
export function formatPointerInfo(info: PointerInfo): Buffer {
const lines = [
`version ${SPEC_URL}`,
`oid sha256:${info.oid}`,
`size ${info.size}`,
"",
];
return Buffer.from(lines.join("\n"));
}
export async function buildPointerInfo(content: Buffer): Promise<PointerInfo> {
const size = content.byteLength;
const hash = await crypto.subtle.digest("SHA-256", content);
const oid = toHex(hash);
return { oid, size };
}