git-cat-file
Version:
A pure-JavaScript implementation of `git cat-file -p` for Node.js.
61 lines (48 loc) • 1.87 kB
text/typescript
/**
* https://github.com/kawanet/git-cat-file
*
* @see https://github.com/git/git/blob/master/Documentation/technical/pack-format.txt
*/
import {promises as fs} from "fs"
export type PackIndex = {[oid: string]: number}
const toHex = (buf: Buffer) => buf.toString("hex").replace(/(\w.)(?=\w)/g, "$1 ")
export async function readPackIndex(path: string): Promise<PackIndex> {
path = path.replace(/\.pack$/, ".idx")
if (!/\.idx$/.test(path)) throw TypeError(`Invalid pack index file: ${path}`)
const data = await fs.readFile(path)
return parsePackIndex(data)
}
async function parsePackIndex(data: Buffer): Promise<PackIndex> {
// validate header
const headByte = data.slice(0, 4)
const head = headByte.toString("latin1")
if (head !== "\xFFtOc") throw TypeError(`Invalid header: ${toHex(headByte)}`)
// validate version number
const version = data.readUInt32BE(4)
if (version !== 2) throw TypeError(`Invalid version number: ${version}`)
let oidIdx = 8 + 4 * 256
// total objects count
const total = data.readUInt32BE(oidIdx - 4)
// console.warn(`found: ${total} packed objects`);
const oidLast = oidIdx + 20 * total
let table4Idx = oidLast + 4 * total
let table8Idx = table4Idx + 4 * total
const packIndex: PackIndex = {}
while (oidIdx < oidLast) {
const end = oidIdx + 20
const oid = data.slice(oidIdx, end).toString("hex")
let pos = data.readUInt32BE(table4Idx)
table4Idx += 4
if (pos & 0x80000000) {
// console.warn(pos.toString(16));
const high = data.readUInt32BE(table8Idx)
table8Idx += 4
const low = data.readUInt32BE(table8Idx)
table8Idx += 4
pos = high * 0x100000000 + low
}
packIndex[oid] = pos
oidIdx = end
}
return packIndex
}