isomorphic-git
Version:
Node library for interacting with git repositories, circa 2017
73 lines (69 loc) • 2.24 kB
JavaScript
// @flow
import { Buffer } from 'buffer'
import GitObjectManager from '../managers/GitObjectManager'
import pad from 'pad'
import pako from 'pako'
import crypto from 'crypto'
/*::
import type {Writable} from 'stream'
*/
const types = {
commit: 0b0010000,
tree: 0b0100000,
blob: 0b0110000,
tag: 0b1000000
}
export default async function pack (
{
oids,
gitdir,
outputStream
} /*: {oids: Array<string>, gitdir: string, outputStream: Writable} */
) {
let hash = crypto.createHash('sha1')
let stream = outputStream
function write (chunk, enc) {
stream.write(chunk, enc)
hash.update(chunk, enc)
}
function writeObject ({ stype, object }) {
let lastFour, multibyte, length
// Object type is encoded in bits 654
let type = types[stype]
if (type === undefined) throw new Error('Unrecognized type: ' + stype)
// The length encoding get complicated.
length = object.length
// Whether the next byte is part of the variable-length encoded number
// is encoded in bit 7
multibyte = length > 0b1111 ? 0b10000000 : 0b0
// Last four bits of length is encoded in bits 3210
lastFour = length & 0b1111
// Discard those bits
length = length >>> 4
// The first byte is then (1-bit multibyte?), (3-bit type), (4-bit least sig 4-bits of length)
let byte = (multibyte | type | lastFour).toString(16)
write(byte, 'hex')
// Now we keep chopping away at length 7-bits at a time until its zero,
// writing out the bytes in what amounts to little-endian order.
while (multibyte) {
multibyte = length > 0b01111111 ? 0b10000000 : 0b0
byte = multibyte | (length & 0b01111111)
write(pad(2, byte.toString(16), '0'), 'hex')
length = length >>> 7
}
// Lastly, we can compress and write the object.
write(Buffer.from(pako.deflate(object)))
}
write('PACK')
write('00000002', 'hex')
// Write a 4 byte (32-bit) int
write(pad(8, oids.length.toString(16), '0'), 'hex')
for (let oid of oids) {
let { type, object } = await GitObjectManager.read({ gitdir, oid })
writeObject({ write, object, stype: type })
}
// Write SHA1 checksum
let digest = hash.digest()
stream.end(digest)
return stream
}