index.jsView |
---|
4 | 4 | var buffered = require('pull-buffered') |
5 | 5 | var pack = require('./lib/pack') |
6 | 6 | var pktLine = require('./lib/pkt-line') |
7 | 7 | var util = require('./lib/util') |
| 8 | +var multicb = require('multicb') |
8 | 9 | |
9 | 10 | function handleOption(options, name, value) { |
10 | 11 | switch (name) { |
11 | 12 | case 'verbosity': |
52 | 53 | } |
53 | 54 | |
54 | 55 | |
55 | 56 | function uploadPack(read, repo, options) { |
56 | | - |
57 | 57 | |
58 | 58 | * include-tag multi_ack_detailed symref=HEAD:refs/heads/master |
59 | 59 | * agent=git/2.7.0 */ |
60 | 60 | var refSource = repo.refs.bind(repo) |
65 | 65 | var readHave = lines.haves() |
66 | 66 | var acked |
67 | 67 | var commonHash |
68 | 68 | var sendPack |
69 | | - var earlyDisconnect |
| 69 | + var wants = {} |
| 70 | + var shallows = {} |
70 | 71 | |
71 | 72 | |
72 | 73 | return cat([ |
73 | 74 | pktLine.encode(cat([ |
75 | 76 | pull.once(''), |
76 | 77 | function (abort, cb) { |
77 | 78 | if (abort) return |
78 | 79 | if (acked) return cb(true) |
| 80 | + |
79 | 81 | |
80 | | - var readWant = lines.wants(wantsDone) |
| 82 | + var readWant = lines.wants() |
81 | 83 | readWant(null, function (end, want) { |
82 | | - if (end === true) { |
83 | | - |
84 | | - earlyDisconnect = true |
85 | | - cb(true) |
86 | | - } else if (end) { |
87 | | - cb(end) |
| 84 | + |
| 85 | + if (end === true) cb(true) |
| 86 | + else if (end) cb(end) |
| 87 | + else readWant(null, nextWant) |
| 88 | + }) |
| 89 | + function nextWant(end, want) { |
| 90 | + if (end) return wantsDone(end === true ? null : end) |
| 91 | + if (want.type == 'want') { |
| 92 | + wants[want.hash] = true |
| 93 | + } else if (want.type == 'shallow') { |
| 94 | + shallows[want.hash] = true |
88 | 95 | } else { |
89 | | - wantSink(readWant) |
| 96 | + var err = new Error("Unknown thing", want.type, want.hash) |
| 97 | + return readWant(err, function (e) { cb(e || err) }) |
90 | 98 | } |
91 | | - }) |
| 99 | + readWant(null, nextWant) |
| 100 | + } |
92 | 101 | |
93 | 102 | function wantsDone(err) { |
94 | | - |
| 103 | + console.error('wants done', err) |
95 | 104 | if (err) return cb(err) |
96 | | - if (earlyDisconnect) return cb(true) |
97 | 105 | |
98 | 106 | |
99 | 107 | |
100 | 108 | |
119 | 127 | }) |
120 | 128 | } |
121 | 129 | }, |
122 | 130 | ])), |
| 131 | + |
123 | 132 | function havesDone(abort, cb) { |
124 | | - |
125 | | - if (abort || earlyDisconnect) return cb(abort || true) |
| 133 | + if (abort) return cb(abort) |
126 | 134 | |
127 | 135 | if (!sendPack) |
128 | | - getObjects(commonHash, function (err, numObjects, readObject) { |
129 | | - sendPack = pack.encode(numObjects, readObject) |
130 | | - havesDone(abort, cb) |
131 | | - }) |
| 136 | + getObjects(repo, commonHash, wants, shallows, |
| 137 | + function (err, numObjects, readObjects) { |
| 138 | + if (err) return cb(err) |
| 139 | + sendPack = pack.encode(numObjects, readObjects) |
| 140 | + havesDone(abort, cb) |
| 141 | + } |
| 142 | + ) |
132 | 143 | else |
133 | 144 | sendPack(abort, cb) |
134 | 145 | } |
135 | 146 | ]) |
136 | 147 | } |
137 | 148 | |
| 149 | +function getObjects(repo, commonHash, heads, shallows, cb) { |
| 150 | + |
| 151 | + |
| 152 | + var objects = [] |
| 153 | + var objectsAdded = {} |
| 154 | + var done = multicb({pluck: 1}) |
| 155 | + var ended |
| 156 | + |
| 157 | + |
| 158 | + for (var hash in heads) |
| 159 | + addObject(hash, done()) |
| 160 | + |
| 161 | + |
| 162 | + |
| 163 | + function addObject(hash, cb) { |
| 164 | + if (ended) return cb(ended) |
| 165 | + if (hash in objectsAdded || hash == commonHash) return cb() |
| 166 | + objectsAdded[hash] = true |
| 167 | + repo.getObject(hash, function (err, object) { |
| 168 | + if (err) return cb(err) |
| 169 | + if (object.type == 'blob') { |
| 170 | + objects.push(object) |
| 171 | + cb() |
| 172 | + } else { |
| 173 | + |
| 174 | + bufferObject(object, function (err, object) { |
| 175 | + if (err) return cb(err) |
| 176 | + objects.push(object) |
| 177 | + var hashes = getObjectLinks(object) |
| 178 | + for (var sha1 in hashes) |
| 179 | + addObject(sha1, done()) |
| 180 | + cb() |
| 181 | + }) |
| 182 | + } |
| 183 | + }) |
| 184 | + } |
| 185 | + |
| 186 | + done(function (err) { |
| 187 | + if (err) return cb(err) |
| 188 | + cb(null, objects.length, pull.values(objects)) |
| 189 | + }) |
| 190 | +} |
| 191 | + |
| 192 | +function bufferObject(object, cb) { |
| 193 | + pull( |
| 194 | + object.read, |
| 195 | + pull.collect(function (err, bufs) { |
| 196 | + if (err) return cb(err) |
| 197 | + var buf = Buffer.concat(bufs, object.length) |
| 198 | + cb(null, { |
| 199 | + type: object.type, |
| 200 | + length: object.length, |
| 201 | + data: buf, |
| 202 | + read: pull.once(buf) |
| 203 | + }) |
| 204 | + }) |
| 205 | + ) |
| 206 | +} |
| 207 | + |
| 208 | + |
| 209 | +function getObjectLinks(object, cb) { |
| 210 | + switch (object.type) { |
| 211 | + case 'blob': |
| 212 | + return {} |
| 213 | + case 'tree': |
| 214 | + return getTreeLinks(object.data) |
| 215 | + case 'tag': |
| 216 | + case 'commit': |
| 217 | + return getCommitOrTagLinks(object.data) |
| 218 | + } |
| 219 | +} |
| 220 | + |
| 221 | +function getTreeLinks(buf) { |
| 222 | + var links = {} |
| 223 | + for (var i = 0, j; j = buf.indexOf(0, i, 'ascii') + 1; i = j + 20) { |
| 224 | + var hash = buf.slice(j, j + 20).toString('hex') |
| 225 | + if (!(hash in links)) |
| 226 | + links[hash] = true |
| 227 | + } |
| 228 | + return links |
| 229 | +} |
| 230 | + |
| 231 | +function getCommitOrTagLinks(buf) { |
| 232 | + var lines = buf.toString('utf8').split('\n') |
| 233 | + var links = {} |
| 234 | + |
| 235 | + for (var i = 0; lines[i]; i++) { |
| 236 | + var args = lines[i].split(' ') |
| 237 | + switch (args[0]) { |
| 238 | + case 'tree': |
| 239 | + case 'parent': |
| 240 | + case 'object': |
| 241 | + var hash = args[1] |
| 242 | + if (!(hash in links)) |
| 243 | + links[hash] = true |
| 244 | + } |
| 245 | + } |
| 246 | + return links |
| 247 | +} |
| 248 | + |
138 | 249 | |
139 | 250 | TODO: investigate capabilities |
140 | 251 | report-status delete-refs side-band-64k quiet atomic ofs-delta |
141 | 252 | */ |
217 | 328 | } |
218 | 329 | |
219 | 330 | module.exports = function (repo) { |
220 | 331 | var ended |
221 | | - |
222 | | - var getObjects = opts.getObjects || function (id, cb) { |
223 | | - cb(null, 0, pull.empty()) |
224 | | - } |
225 | | - */ |
226 | | - |
227 | 332 | var options = { |
228 | 333 | verbosity: 1, |
229 | 334 | progress: false |
230 | 335 | } |