Files: 9879cbb757d4bcde4e81cb784c35900a61a22bd6 / lib / reconstruct.js
3999 bytesRaw
1 | var fs = require('fs') |
2 | var proc = require('child_process') |
3 | var pull = require('pull-stream') |
4 | var toPull = require('stream-to-pull-stream') |
5 | var paramap = require('pull-paramap') |
6 | var multicb = require('multicb') |
7 | var u = require('./util') |
8 | var ssbRef = require('ssb-ref') |
9 | |
10 | exports.help = ` |
11 | Usage: git ssb reconstruct <msg>... |
12 | |
13 | Reconstruct pack/idx blobs referenced by git-update messages. |
14 | On success, output the message ids and their pack and index blob ids. |
15 | |
16 | Arguments: |
17 | msg ssb message id |
18 | ` |
19 | |
20 | function reconstructBlobsForMsg(sbot, msg, cb) { |
21 | var c = msg.value.content |
22 | if (!c) return cb(new TypeError('Bad message: ' + JSON.stringify(msg))) |
23 | var packs = Array.isArray(c.packs) && c.packs.length === 1 && c.packs |
24 | var idxs = Array.isArray(c.indexes) && c.indexes.length === 1 && c.indexes |
25 | var packId = packs && packs[0] && packs[0].link |
26 | var idxId = idxs && idxs[0] && idxs[0].link |
27 | if (!packId || !idxId) return cb(new TypeError('Message should have ' + |
28 | 'exactly one pack link and idx link')) |
29 | var commits = Array.isArray(c.commits) ? c.commits : [] |
30 | var commitIds = commits.map(function (commit) { return commit.sha1 }) |
31 | var objectIds = Array.isArray(c.object_ids) ? c.object_ids : [] |
32 | var allObjectIds = commitIds.concat(objectIds) |
33 | if (c.num_objects && c.num_objects !== allObjectIds.length) { |
34 | return cb(new Error('Message ' + msg.key + ' ' + |
35 | 'does not have information to reconstruct its blobs')) |
36 | } |
37 | // replace incorrectly hashed empty blob id |
38 | allObjectIds = allObjectIds.map(function (id) { |
39 | return id === '77e98a59e190ce51ab7ec86deb24492d1434247e' |
40 | ? 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391' : id |
41 | }) |
42 | var tmpName = 'git-ssb-reconstruct' |
43 | var child = proc.spawn('git', ['pack-objects', '-q', tmpName], { |
44 | stdio: ['pipe', 'pipe', process.stderr], |
45 | }) |
46 | child.stdin.end(allObjectIds.join('\n')) |
47 | var bufs = [] |
48 | child.stdout.on('data', bufs.push.bind(bufs)) |
49 | child.on('error', onError) |
50 | function onError(err) { |
51 | if (!cb) return console.trace(err) |
52 | var _cb = cb |
53 | cb = null |
54 | _cb(err) |
55 | } |
56 | var done = multicb() |
57 | child.on('exit', done()) |
58 | child.stdout.on('end', done()) |
59 | done(function (code) { |
60 | if (code) return onError(new Error('failed to pack git objects. code: ' + code)) |
61 | if (!cb) return |
62 | var hash = Buffer.concat(bufs).toString('utf8').trim() |
63 | if (!hash) return cb(new Error('missing hash')) |
64 | var packFile = tmpName + '-' + hash + '.pack' |
65 | var idxFile = tmpName + '-' + hash + '.idx' |
66 | var done = multicb() |
67 | pull( |
68 | toPull(fs.createReadStream(packFile)), |
69 | sbot.blobs.add(packId, done()) |
70 | ) |
71 | pull( |
72 | toPull(fs.createReadStream(idxFile)), |
73 | sbot.blobs.add(idxId, done()) |
74 | ) |
75 | done(function (err) { |
76 | var done = multicb() |
77 | fs.unlink(packFile, done()) |
78 | fs.unlink(idxFile, done()) |
79 | done()(err) |
80 | done(function (err) { |
81 | if (err) return cb(err) |
82 | cb(null, {msg: msg, packId: packId, idxId: idxId}) |
83 | }) |
84 | }) |
85 | }) |
86 | } |
87 | |
88 | exports.fn = function (argv) { |
89 | if (argv._.length < 1) return u.help('reconstruct') |
90 | |
91 | var msgIds = argv._ |
92 | if (!msgIds.every(ssbRef.isMsgId)) throw 'invalid message ids: ' + |
93 | JSON.stringify(argv._) |
94 | |
95 | u.getSbot(argv, function (err, sbot) { |
96 | if (err) throw err |
97 | pull( |
98 | pull.values(msgIds), |
99 | paramap(function (id, cb) { |
100 | u.getMsg(sbot, id, function (err, msg) { |
101 | if (err) throw 'failed to get message ' + id + ': ' + (err.stack||err) |
102 | cb(null, msg) |
103 | }) |
104 | }, 8), |
105 | paramap(function (msg, cb) { |
106 | u.unbox(sbot, msg, function (err, msg) { |
107 | if (err) throw 'failed to get decrypt message ' + id |
108 | cb(null, msg) |
109 | }) |
110 | }, 4), |
111 | pull.asyncMap(function (msg, cb) { |
112 | reconstructBlobsForMsg(sbot, msg, cb) |
113 | }), |
114 | pull.drain(function (obj) { |
115 | console.log(obj.msg.key + ' ' + obj.packId + ' ' + obj.idxId) |
116 | }, function (err) { |
117 | if (err) throw err |
118 | sbot.close() |
119 | }) |
120 | ) |
121 | }) |
122 | } |
123 |
Built with git-ssb-web