git ssb

0+

cel / pull-git-pack-concat



Tree: faf06baee09eb29236cd233fcfd7ff82bfcff755

Files: faf06baee09eb29236cd233fcfd7ff82bfcff755 / index.js

3024 bytesRaw
1var pull = require('pull-stream')
2var cat = require('pull-cat')
3var loop = require('looper')
4var multicb = require('multicb')
5var crypto = require('crypto')
6var skipFooter = require('pull-skip-footer')
7var packidx = require('pull-git-packidx-parser')
8var blockFilter = require('pull-block-filter')
9
10function packHeader(numObjects) {
11 var header = new Buffer(12)
12 header.write('PACK')
13 header.writeUInt32BE(2, 4)
14 header.writeUInt32BE(numObjects, 8)
15 return header
16}
17
18function forEachAsync(arr, fn, cb) {
19 var i = 0
20 loop(function (next) {
21 if (i >= arr.length) return cb && cb()
22 fn(arr[i++], function (err) {
23 if (err) return cb && cb(err)
24 next()
25 })
26 })
27}
28
29function compareByOffset(a, b) {
30 return a.offset - b.offset
31}
32
33function dedupPacks(packs, cb) {
34 var seen = {}
35 var numObjects = 0
36 forEachAsync(packs, function (pack, cb) {
37 return pull(pack.readIdx, packidx(function (err, idx) {
38 if (err) return cb(err)
39 var blocks = []
40 var lastBlock
41 offset = 0
42 var objs = idx.objects.sort(compareByOffset)
43 for (var i = 0; i < objs.length; i++) {
44 var obj = objs[i]
45 var id = obj.oid.toString('hex')
46 if (seen[id]) continue
47 seen[id] = true
48 numObjects++
49 if (obj.offset > offset) {
50 blocks.push(lastBlock = {skip: obj.offset - offset, length: 0})
51 offset = obj.offset
52 } else if (obj.offset < offset) {
53 return cb(new Error('bad offset'))
54 }
55 var len = obj.next ? obj.next.offset - obj.offset : Infinity
56 lastBlock.length += len
57 offset += len
58 }
59 pack.read = pull(
60 pack.read,
61 skipFooter(20),
62 blockFilter(pull.values(blocks))
63 )
64 cb()
65 }))
66 }, function (err) {
67 cb(err, numObjects)
68 })
69}
70
71function closePacks(packs, cb) {
72 forEachAsync(packs, function (pack, cb) {
73 pack.read(true, cb)
74 }, cb)
75}
76
77module.exports = function concatPacks(packs) {
78 /* packs: [{read: source, readIdx: source}] */
79 if (packs.length === 1) return packs[0].read
80
81 var checksum = crypto.createHash('sha1')
82 var packI = 0
83 var state = 'begin'
84
85 return function next(end, cb) {
86 switch (state) {
87 case 'begin':
88 if (end) return closePacks(cb)
89 return dedupPacks(packs, function (err, numObjects) {
90 if (err) return cb(err)
91 var header = packHeader(numObjects)
92 checksum.update(header)
93 state = 'payload'
94 cb(null, header)
95 })
96
97 case 'payload':
98 if (end) return closePacks(cb)
99 if (packI >= packs.length) {
100 state = 'end'
101 return cb(null, checksum.digest())
102 }
103 var pack = packs[packI]
104 return pack.read(null, function (err, data) {
105 if (err === true) {
106 packI++
107 return next(null, cb)
108 }
109 if (err) return cb(err)
110 checksum.update(data)
111 cb(null, data)
112 })
113
114 case 'end':
115 return cb(true)
116 }
117 }
118}
119

Built with git-ssb-web