index.jsView |
---|
61 | 61 | str.substr(i + 1) |
62 | 62 | ] |
63 | 63 | } |
64 | 64 | |
| 65 | +function split3(str) { |
| 66 | + var args = split2(str) |
| 67 | + return [args[0]].concat(split2(args[1])) |
| 68 | +} |
| 69 | + |
65 | 70 | function optionSource(cmd) { |
66 | 71 | var args = split2(cmd) |
67 | 72 | var msg = handleOption(args[0], args[1]) |
68 | 73 | msg = (msg === true) ? 'ok' |
86 | 91 | }) |
87 | 92 | return hasher |
88 | 93 | } |
89 | 94 | |
90 | | -function uploadPack(read) { |
91 | | - return function (abort, cb) { |
92 | | - var lines = packLineDecode(read) |
93 | | - receiveRefs(lines.packLines, function (err, refs) { |
94 | | - console.error('refs', refs, err) |
95 | | - if (err) return cb(err) |
96 | | - }) |
97 | | - } |
| 95 | +function uploadPack(read, objectSource, refSource) { |
| 96 | + |
| 97 | + * include-tag multi_ack_detailed symref=HEAD:refs/heads/master |
| 98 | + * agent=git/2.7.0 */ |
| 99 | + var sendRefs = receivePackHeader([ |
| 100 | + ], refSource, false) |
| 101 | + |
| 102 | + return packLineEncode( |
| 103 | + cat([ |
| 104 | + sendRefs, |
| 105 | + pull.once('') |
| 106 | + ]) |
| 107 | + ) |
98 | 108 | } |
99 | 109 | |
100 | 110 | function getRefs() { |
101 | 111 | return pull.values([ |
137 | 147 | var b = buffered(read) |
138 | 148 | var readPrefix = b.chunks(4) |
139 | 149 | var ended |
140 | 150 | |
141 | | - b.packLines = function (abort, cb) { |
| 151 | + function readPackLine(abort, cb) { |
142 | 152 | readPrefix(abort, function (end, buf) { |
143 | 153 | if (ended = end) return cb(end) |
144 | 154 | var len = parseInt(buf, 16) |
145 | | - b.chunks(len)(null, function (end, buf) { |
| 155 | + if (!len) |
| 156 | + return cb(null, new Buffer('')) |
| 157 | + |
| 158 | + b.chunks(len - 4)(null, function (end, buf) { |
146 | 159 | if (ended = end) return cb(end) |
147 | 160 | cb(end, buf) |
148 | 161 | }) |
149 | 162 | }) |
150 | 163 | } |
151 | 164 | |
| 165 | + function readUpdate(abort, cb) { |
| 166 | + readPackLine(abort, function (end, line) { |
| 167 | + if (end) return cb(end) |
| 168 | + console.error('line', line.toString('ascii')) |
| 169 | + if (!line.length) return cb(true) |
| 170 | + var args = split3(line.toString('ascii')) |
| 171 | + cb(null, { |
| 172 | + old: args[0], |
| 173 | + new: args[1], |
| 174 | + name: args[2] |
| 175 | + }) |
| 176 | + }) |
| 177 | + } |
| 178 | + |
| 179 | + b.packLines = readPackLine |
| 180 | + b.updates = readUpdate |
| 181 | + |
152 | 182 | return b |
153 | 183 | } |
154 | 184 | |
| 185 | + |
| 186 | + |
| 187 | +function onThroughEnd(onEnd) { |
| 188 | + return function (read) { |
| 189 | + return function (end, cb) { |
| 190 | + read(end, function (end, data) { |
| 191 | + cb(end, data) |
| 192 | + if (end) |
| 193 | + onEnd(end === true ? null : end) |
| 194 | + }) |
| 195 | + } |
| 196 | + } |
| 197 | +} |
| 198 | + |
155 | 199 | |
156 | 200 | TODO: investigate capabilities |
157 | 201 | report-status delete-refs side-band-64k quiet atomic ofs-delta |
158 | 202 | */ |
159 | 203 | |
160 | 204 | |
161 | 205 | |
162 | | -function receivePackHeader(capabilities, refsSource) { |
| 206 | +function receivePackHeader(capabilities, refSource, usePlaceholder) { |
163 | 207 | var first = true |
164 | 208 | var ended |
165 | 209 | return function (abort, cb) { |
166 | 210 | if (ended) return cb(true) |
167 | | - refsSource(abort, function (end, ref) { |
| 211 | + refSource(abort, function (end, ref) { |
168 | 212 | ended = end |
169 | 213 | var name = ref && ref.name |
170 | 214 | var hash = ref && ref.hash |
171 | | - if (first) { |
| 215 | + if (first && usePlaceholder) { |
172 | 216 | first = false |
173 | 217 | if (end) { |
174 | 218 | |
175 | 219 | hash = '0000000000000000000000000000000000000000' |
183 | 227 | }) |
184 | 228 | } |
185 | 229 | } |
186 | 230 | |
187 | | -function receiveActualPack(read, objectSink, onEnd) { |
| 231 | +function decodePack(read) { |
188 | 232 | var objects = pushable() |
189 | | - packCodec.decodePack(function (obj) { |
190 | | - if (obj) pushable.push(obj) |
191 | | - else pushable.end() |
| 233 | + var decode = packCodec.decodePack(function (obj) { |
| 234 | + if (obj) objects.push(obj) |
| 235 | + else objects.end() |
192 | 236 | }) |
193 | | - objectSink(objects) |
194 | | -} |
195 | | - |
196 | | -function receiveRefs(readLine, cb) { |
197 | | - var refs = [] |
198 | | - readLine(null, function next(end, line) { |
199 | | - if (end) |
200 | | - cb(end) |
201 | | - else if (line.length == 0) |
202 | | - cb(null, refs) |
203 | | - else { |
204 | | - var args = split2(line.toString('ascii')) |
205 | | - refs.push({ |
206 | | - hash: args[0], |
207 | | - name: args[1] |
208 | | - }) |
209 | | - readLine(null, next) |
210 | | - } |
| 237 | + read(null, function next(end, data) { |
| 238 | + if (end) decode() |
| 239 | + else decode(data) |
211 | 240 | }) |
| 241 | + return objects |
212 | 242 | } |
213 | 243 | |
214 | | -function receivePack(read, objectSink, refsSource) { |
| 244 | +function receivePack(read, objectSink, refSource, refSink) { |
215 | 245 | var ended |
216 | | - var sendRefs = receivePackHeader([], refsSource) |
| 246 | + var sendRefs = receivePackHeader([], refSource, true) |
217 | 247 | |
218 | 248 | return packLineEncode( |
219 | 249 | cat([ |
220 | 250 | |
223 | 253 | function (abort, cb) { |
224 | 254 | if (abort) return |
225 | 255 | |
226 | 256 | var lines = packLineDecode(read) |
227 | | - receiveRefs(lines.packLines, function (err, refs) { |
228 | | - |
| 257 | + pull( |
| 258 | + lines.updates, |
| 259 | + onThroughEnd(refsDone), |
| 260 | + refSink |
| 261 | + ) |
| 262 | + function refsDone(err) { |
229 | 263 | if (err) return cb(err) |
230 | 264 | |
231 | | - receiveActualPack(lines.passthrough, objectSink, function (err) { |
232 | | - if (err) return cb(err) |
233 | | - cb(true) |
234 | | - }) |
235 | | - }) |
| 265 | + pull( |
| 266 | + lines.passthrough, |
| 267 | + decodePack, |
| 268 | + onThroughEnd(objectsDone), |
| 269 | + objectSink |
| 270 | + ) |
| 271 | + } |
| 272 | + function objectsDone(err) { |
| 273 | + if (err) return cb(err) |
| 274 | + cb(true) |
| 275 | + } |
236 | 276 | }, |
237 | 277 | pull.once('unpack ok') |
238 | 278 | ]) |
239 | 279 | ) |
254 | 294 | module.exports = function (opts) { |
255 | 295 | var ended |
256 | 296 | var prefix = opts.prefix |
257 | 297 | var objectSink = opts.objectSink |
258 | | - var refsSource = opts.refsSource || pull.empty() |
| 298 | + var objectSource = opts.objectSource || pull.empty() |
| 299 | + var refSource = opts.refSource || pull.empty() |
| 300 | + var refSink = opts.refSink |
259 | 301 | |
260 | 302 | function handleConnect(cmd, read) { |
261 | 303 | var args = split2(cmd) |
262 | 304 | switch (args[0]) { |
263 | 305 | case 'git-upload-pack': |
264 | | - return prepend('\n', uploadPack(read)) |
| 306 | + return prepend('\n', uploadPack(read, objectSource, refSource)) |
265 | 307 | case 'git-receive-pack': |
266 | | - return prepend('\n', receivePack(read, objectSink, refsSource)) |
| 308 | + return prepend('\n', receivePack(read, objectSink, refSource, |
| 309 | + refSink)) |
267 | 310 | default: |
268 | 311 | return pull.error(new Error('Unknown service ' + args[0])) |
269 | 312 | } |
270 | 313 | } |