git-cat-file
Version:
A pure-JavaScript implementation of `git cat-file -p` for Node.js.
98 lines (80 loc) • 2.94 kB
text/typescript
/**
* https://github.com/kawanet/git-cat-file
*/
import {promises as fs} from "fs"
import type {GCF} from "../types/git-cat-file.d.ts"
import {shortCache} from "./cache.ts"
import {Loose} from "./loose.ts"
import {Pack} from "./pack.ts"
import {Ref} from "./ref.ts"
/**
* https://github.com/kawanet/git-cat-file
*/
const isObjectId = (oid: string) => (oid && /^[0-9a-f]{40}$/i.test(oid))
export class ObjStore {
private readonly loose: Loose
private readonly pack: {[name: string]: Pack} = {}
private readonly ref: Ref
private readonly root: string
constructor(root: string) {
this.root = root
this.loose = new Loose(root)
this.ref = new Ref(root)
}
/**
* get object with the exact objectId
*/
getObject = shortCache(async (object_id: string): Promise<GCF.IObject> => {
if (!isObjectId(object_id)) {
throw new TypeError(`Invalid object_id: ${object_id}`)
}
// packed object
const list = await this.getPackList() || []
for (const pack of list) {
const obj = await pack.getObject(object_id, this)
if (obj) return obj
}
// loose object
return this.loose.getObject(object_id)
})
/**
* get objectId with a loose objectId
*/
findObjectId = shortCache(async (object_id: string): Promise<string> => {
const index: {[oid: string]: 1} = {}
// packed object
{
const packs = await this.getPackList() || []
for (const pack of packs) {
const items = await pack.findAll(object_id)
if (!items) continue
for (const oid of items) {
index[oid] = 1
}
}
const matched = Object.keys(index)
// console.warn(`matched: ${matched.length} packed object`);
if (matched.length > 1) return
}
// loose object
{
const items = await this.loose.findAll(object_id) || []
// console.warn(`matched: ${items.length} loose object`);
for (const oid of items) {
index[oid] = 1
}
}
const matched = Object.keys(index)
if (matched.length === 1) return matched[0]
})
findCommitId = shortCache((commit_id: string): Promise<string> => this.ref.findCommitId(commit_id, this))
protected getPackList = shortCache(async (): Promise<Pack[]> => {
const base = `${this.root}/objects/pack/`
// console.warn(`readdir: ${base}`);
let names: string[] = await fs.readdir(base).catch((): null => null)
if (!names) return
names = names.filter(name => /^pack-.*\.pack$/.test(name))
// console.warn(`found: ${names.length} packs`);
return names.map(name => (this.pack[name] || (this.pack[name] = new Pack(base + name))))
})
}