git ssb

0+

cel / pull-git-pack-concat



Tree: a2892aa5c1069e88aa08a58c5722a33c05a68adc

Files: a2892aa5c1069e88aa08a58c5722a33c05a68adc / index.js

3042 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 = Buffer.alloc(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 var next = loop(function () {
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 next()
28}
29
30function compareByOffset(a, b) {
31 return a.offset - b.offset
32}
33
34function dedupPacks(packs, cb) {
35 var seen = {}
36 var numObjects = 0
37 forEachAsync(packs, function (pack, cb) {
38 return pull(pack.readIdx, packidx(function (err, idx) {
39 if (err) return cb(err)
40 var blocks = []
41 var lastBlock
42 offset = 0
43 var objs = idx.objects.sort(compareByOffset)
44 for (var i = 0; i < objs.length; i++) {
45 var obj = objs[i]
46 var id = obj.oid.toString('hex')
47 if (seen[id]) continue
48 seen[id] = true
49 numObjects++
50 if (obj.offset > offset) {
51 blocks.push(lastBlock = {skip: obj.offset - offset, length: 0})
52 offset = obj.offset
53 } else if (obj.offset < offset) {
54 return cb(new Error('bad offset'))
55 }
56 var len = obj.next ? obj.next.offset - obj.offset : Infinity
57 lastBlock.length += len
58 offset += len
59 }
60 pack.read = pull(
61 pack.read,
62 skipFooter(20),
63 blockFilter(pull.values(blocks))
64 )
65 cb()
66 }))
67 }, function (err) {
68 cb(err, numObjects)
69 })
70}
71
72function closePacks(packs, cb) {
73 forEachAsync(packs, function (pack, cb) {
74 pack.read(true, cb)
75 }, cb)
76}
77
78module.exports = function concatPacks(packs) {
79 /* packs: [{read: source, readIdx: source}] */
80 if (packs.length === 1) return packs[0].read
81
82 var checksum = crypto.createHash('sha1')
83 var packI = 0
84 var state = 'begin'
85
86 return function next(end, cb) {
87 switch (state) {
88 case 'begin':
89 if (end) return closePacks(cb)
90 return dedupPacks(packs, function (err, numObjects) {
91 if (err) return cb(err)
92 var header = packHeader(numObjects)
93 checksum.update(header)
94 state = 'payload'
95 cb(null, header)
96 })
97
98 case 'payload':
99 if (end) return closePacks(cb)
100 if (packI >= packs.length) {
101 state = 'end'
102 return cb(null, checksum.digest())
103 }
104 var pack = packs[packI]
105 return pack.read(null, function (err, data) {
106 if (err === true) {
107 packI++
108 return next(null, cb)
109 }
110 if (err) return cb(err)
111 checksum.update(data)
112 cb(null, data)
113 })
114
115 case 'end':
116 return cb(true)
117 }
118 }
119}
120

Built with git-ssb-web