Commit c2f96fca4e0046fd6b5ee048898f8db2c2c1d247
Almost got upload-pack working
Charles Lehner committed on 2/8/2016, 4:37:24 AMParent: 20c102b7036f7fee19f151e269d33cd7da837a3b
Files changed
index.js | changed |
pack.js | changed |
test/git-remote-empty.js | changed |
test/git-remote-full.js | changed |
test/run.js | changed |
test/repo.js | added |
index.js | ||
---|---|---|
@@ -64,115 +64,93 @@ | ||
64 | 64 | } |
65 | 65 | } |
66 | 66 | |
67 | 67 | // upload-pack: fetch to client |
68 | -function uploadPack(read, objectSource, refSource, wantSink, options) { | |
68 | +function uploadPack(read, getObjects, refSource, wantSink, options) { | |
69 | 69 | /* multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress |
70 | 70 | * include-tag multi_ack_detailed symref=HEAD:refs/heads/master |
71 | 71 | * agent=git/2.7.0 */ |
72 | 72 | var sendRefs = receivePackHeader([ |
73 | 73 | ], refSource, false) |
74 | 74 | |
75 | 75 | var lines = packLineDecode(read, options) |
76 | 76 | // var havesSink = pull.drain(console.error.bind(console, 'have:')) |
77 | - var readHave = lines.haves | |
77 | + var readHave = lines.haves() | |
78 | 78 | var acked |
79 | 79 | var commonHash |
80 | 80 | var sendPack |
81 | 81 | var earlyDisconnect |
82 | 82 | |
83 | 83 | function haveObject(hash, cb) { |
84 | 84 | cb(/* TODO */) |
85 | + // cb(true) | |
85 | 86 | } |
86 | 87 | |
87 | - function getObjects(commonObjId, cb) { | |
88 | - console.error('get obj', commonObjId) | |
89 | - cb(null, 0, function readObject(end, cb) { | |
90 | - console.error('read obj', end) | |
91 | - // cb(new Error('Not implemented')) | |
92 | - cb(true) | |
93 | - }) | |
94 | - } | |
95 | - | |
96 | 88 | // Packfile negotiation |
97 | - return packLineEncode( | |
98 | - cat([ | |
89 | + return cat([ | |
90 | + packLineEncode(cat([ | |
99 | 91 | sendRefs, |
100 | 92 | pull.once(''), |
101 | 93 | function (abort, cb) { |
102 | 94 | if (abort) return |
103 | 95 | if (acked) return cb(true) |
104 | 96 | // read upload request (wants list) from client |
105 | - pull( | |
106 | - lines.wants, | |
107 | - onThroughEnd(wantsDone), | |
108 | - wantSink | |
109 | - ) | |
97 | + var readWant = lines.wants(wantsDone) | |
98 | + readWant(null, function (end, want) { | |
99 | + if (end === true) { | |
100 | + // client disconnected before sending wants | |
101 | + earlyDisconnect = true | |
102 | + cb(true) | |
103 | + } else if (end) { | |
104 | + cb(end) | |
105 | + } else { | |
106 | + wantSink(readWant) | |
107 | + } | |
108 | + }) | |
110 | 109 | |
111 | - var gotAnyHaves = false | |
112 | - | |
113 | 110 | function wantsDone(err) { |
114 | - console.error('wants done', err) | |
111 | + // console.error('wants done', err, earlyDisconnect) | |
115 | 112 | if (err) return cb(err) |
113 | + if (earlyDisconnect) return cb(true) | |
116 | 114 | // Read upload haves (haves list). |
117 | 115 | // On first obj-id that we have, ACK |
118 | 116 | // If we have none, NAK. |
119 | 117 | // TODO: implement multi_ack_detailed |
120 | 118 | readHave(null, function next(end, have) { |
121 | 119 | if (end === true) { |
122 | - if (gotAnyHaves) { | |
123 | - // found no common object | |
124 | - acked = true | |
125 | - cb(null, 'NAK') | |
126 | - } else { | |
127 | - earlyDisconnect = true | |
128 | - // client disconnected before sending haves. | |
129 | - cb(true) | |
130 | - } | |
120 | + // found no common object | |
121 | + acked = true | |
122 | + cb(null, 'NAK') | |
131 | 123 | } else if (end) |
132 | 124 | cb(end) |
133 | 125 | else if (have.type != 'have') |
134 | 126 | cb(new Error('Unknown have' + JSON.stringify(have))) |
135 | - else { | |
136 | - gotAnyHaves = true | |
127 | + else | |
128 | + console.error('got have', have), | |
137 | 129 | haveObject(have.hash, function (haveIt) { |
138 | 130 | if (!haveIt) |
139 | 131 | return readHave(null, next) |
140 | 132 | commonHash = haveIt |
141 | 133 | acked = true |
142 | 134 | cb(null, 'ACK ' + have.hash) |
143 | 135 | }) |
144 | - } | |
145 | 136 | }) |
146 | 137 | } |
147 | - /* | |
148 | - function havesDone(err) { | |
149 | - console.error('haves done', err) | |
150 | - if (err) return cb(err) | |
151 | - cb(true) | |
152 | - pull( | |
153 | - lines.passthrough, | |
154 | - pull.drain(function (buf) { | |
155 | - console.error('got buf after wants', buf.length, buf.toString('ascii')) | |
156 | - }) | |
157 | - ) | |
158 | - } | |
159 | - */ | |
160 | 138 | }, |
161 | - function havesDone(abort, cb) { | |
162 | - console.error("haves done", abort && typeof abort, sendPack && typeof sendPack) | |
163 | - if (abort || earlyDisconnect) return cb(abort || true) | |
164 | - // send pack file to client | |
165 | - if (!sendPack) | |
166 | - getObjects(commonHash, function (err, numObjects, readObject) { | |
167 | - sendPack = pack.encode(numObjects, readObject) | |
168 | - havesDone(abort, cb) | |
169 | - }) | |
170 | - else | |
171 | - sendPack(abort, cb) | |
172 | - } | |
173 | - ]) | |
174 | - ) | |
139 | + ])), | |
140 | + function havesDone(abort, cb) { | |
141 | + // console.error("haves done", abort && typeof abort, sendPack && typeof sendPack, abort, earlyDisconnect) | |
142 | + if (abort || earlyDisconnect) return cb(abort || true) | |
143 | + // send pack file to client | |
144 | + if (!sendPack) | |
145 | + getObjects(commonHash, function (err, numObjects, readObject) { | |
146 | + sendPack = pack.encode(numObjects, readObject) | |
147 | + havesDone(abort, cb) | |
148 | + }) | |
149 | + else | |
150 | + sendPack(abort, cb) | |
151 | + } | |
152 | + ]) | |
175 | 153 | } |
176 | 154 | |
177 | 155 | function packLineEncode(read) { |
178 | 156 | var ended |
@@ -189,9 +167,9 @@ | ||
189 | 167 | data = '' |
190 | 168 | var len = data ? data.length + 4 : 0 |
191 | 169 | var hexLen = ('000' + len.toString(16)).substr(-4) |
192 | 170 | var pkt = hexLen + data |
193 | - // console.error('>', JSON.stringify(pkt)) | |
171 | + console.error('>', JSON.stringify(pkt)) | |
194 | 172 | cb(end, pkt) |
195 | 173 | } |
196 | 174 | }) |
197 | 175 | } |
@@ -200,8 +178,15 @@ | ||
200 | 178 | function rev(str) { |
201 | 179 | return str === '0000000000000000000000000000000000000000' ? null : str |
202 | 180 | } |
203 | 181 | |
182 | +/* pull-stream/source.js */ | |
183 | +function abortCb(cb, abort, onAbort) { | |
184 | + cb(abort) | |
185 | + onAbort && onAbort(abort === true ? null: abort) | |
186 | + return | |
187 | +} | |
188 | + | |
204 | 189 | function packLineDecode(read, options) { |
205 | 190 | var b = buffered(read) |
206 | 191 | var readPrefix = b.chunks(4) |
207 | 192 | var ended |
@@ -252,24 +237,27 @@ | ||
252 | 237 | }) |
253 | 238 | }) |
254 | 239 | } |
255 | 240 | |
256 | - function readWant(abort, cb) { | |
257 | - readPackLineStr(abort, function (end, line) { | |
258 | - if (end) return cb(end) | |
259 | - if (options.verbosity >= 2) | |
260 | - console.error('line', line) | |
261 | - // if (!line.length) return cb(true) | |
262 | - if (!line.length || line == 'done') return cb(true) | |
263 | - var args = split3(line) | |
264 | - var caps = args[2] | |
265 | - if (caps && options.verbosity >= 2) | |
266 | - console.error('want capabilities:', caps) | |
267 | - cb(null, { | |
268 | - type: args[0], | |
269 | - hash: args[1], | |
241 | + function havesWants(onEnd) { | |
242 | + return function readWant(abort, cb) { | |
243 | + readPackLineStr(abort, function (end, line) { | |
244 | + if (end) return abortCb(cb, end, onEnd) | |
245 | + if (options.verbosity >= 2) | |
246 | + console.error('line', line) | |
247 | + // if (!line.length) return cb(true) | |
248 | + if (!line.length || line == 'done') | |
249 | + return abortCb(cb, true, onEnd) | |
250 | + var args = split3(line) | |
251 | + var caps = args[2] | |
252 | + if (caps && options.verbosity >= 2) | |
253 | + console.error('want capabilities:', caps) | |
254 | + cb(null, { | |
255 | + type: args[0], | |
256 | + hash: args[1], | |
257 | + }) | |
270 | 258 | }) |
271 | - }) | |
259 | + } | |
272 | 260 | } |
273 | 261 | |
274 | 262 | /* |
275 | 263 | function readWant(abort, cb) { |
@@ -294,9 +282,9 @@ | ||
294 | 282 | */ |
295 | 283 | |
296 | 284 | b.packLines = readPackLine |
297 | 285 | b.updates = readUpdate |
298 | - b.wants = b.haves = readWant | |
286 | + b.wants = b.haves = havesWants | |
299 | 287 | |
300 | 288 | return b |
301 | 289 | } |
302 | 290 | |
@@ -396,9 +384,11 @@ | ||
396 | 384 | module.exports = function (opts) { |
397 | 385 | var ended |
398 | 386 | var prefix = opts.prefix |
399 | 387 | var objectSink = opts.objectSink |
400 | - var objectSource = opts.objectSource || pull.empty() | |
388 | + var getObjects = opts.getObjects || function (id, cb) { | |
389 | + cb(null, 0, pull.empty()) | |
390 | + } | |
401 | 391 | var refSource = opts.refSource || pull.empty() |
402 | 392 | var refSink = opts.refSink || pull.drain() |
403 | 393 | var wantSink = opts.wantSink || pull.drain() |
404 | 394 | |
@@ -410,9 +400,9 @@ | ||
410 | 400 | function handleConnect(cmd, read) { |
411 | 401 | var args = split2(cmd) |
412 | 402 | switch (args[0]) { |
413 | 403 | case 'git-upload-pack': |
414 | - return prepend('\n', uploadPack(read, objectSource, refSource, | |
404 | + return prepend('\n', uploadPack(read, getObjects, refSource, | |
415 | 405 | wantSink, options)) |
416 | 406 | case 'git-receive-pack': |
417 | 407 | return prepend('\n', receivePack(read, objectSink, refSource, |
418 | 408 | refSink, options)) |
pack.js | ||
---|---|---|
@@ -1,8 +1,8 @@ | ||
1 | 1 | var buffered = require('pull-buffered') |
2 | 2 | var pull = require('pull-stream') |
3 | 3 | var toPull = require('stream-to-pull-stream') |
4 | -var Inflate = require('pako/lib/inflate').Inflate | |
4 | +var pako = require('pako') | |
5 | 5 | var createHash = require('./util').createHash |
6 | 6 | var cat = require('pull-cat') |
7 | 7 | |
8 | 8 | exports.decode = decodePack |
@@ -13,17 +13,23 @@ | ||
13 | 13 | var objectTypes = [ |
14 | 14 | 'none', 'commit', 'tree', 'blob', |
15 | 15 | 'tag', 'unused', 'ofs-delta', 'ref-delta' |
16 | 16 | ] |
17 | +var objectTypeNums = { | |
18 | + commit: 1, | |
19 | + tree: 2, | |
20 | + blob: 3, | |
21 | + tag: 4 | |
22 | +} | |
17 | 23 | |
18 | 24 | function error(cb) { |
19 | 25 | return function (err) { |
20 | 26 | cb(err || true) |
21 | 27 | } |
22 | 28 | } |
23 | 29 | |
24 | 30 | function inflateBytes(read) { |
25 | - var inflate = new Inflate() | |
31 | + var inflate = new pako.Inflate() | |
26 | 32 | var ended, dataOut |
27 | 33 | |
28 | 34 | inflate.onData = function (data) { |
29 | 35 | dataOut = new Buffer(data) |
@@ -55,8 +61,45 @@ | ||
55 | 61 | }) |
56 | 62 | } |
57 | 63 | } |
58 | 64 | |
65 | +function deflate(read) { | |
66 | + var def = new pako.Deflate() | |
67 | + var queue = [] | |
68 | + var ended | |
69 | + | |
70 | + def.onData = function (data) { | |
71 | + queue.push([null, new Buffer(data)]) | |
72 | + } | |
73 | + | |
74 | + def.onEnd = function (status) { | |
75 | + queue.push([(status === 0) ? true : new Error(def.msg)]) | |
76 | + } | |
77 | + | |
78 | + return function readOut(abort, cb) { | |
79 | + /* | |
80 | + function _cb(end, data) { | |
81 | + console.error('sending deflated', end, | |
82 | + data && JSON.stringify(data.toString())) | |
83 | + cb(end, data) | |
84 | + } | |
85 | + */ | |
86 | + if (ended) | |
87 | + cb(ended) | |
88 | + else if (queue.length) | |
89 | + cb.apply(this, queue.shift()) | |
90 | + else | |
91 | + read(abort, function next(end, data) { | |
92 | + if (data) | |
93 | + console.error('read into deflat', data.length, JSON.stringify(data)) | |
94 | + if (end === true) def.push([], true) | |
95 | + else if (end) return cb(end) | |
96 | + else def.push(data) | |
97 | + readOut(null, cb) | |
98 | + }) | |
99 | + } | |
100 | +} | |
101 | + | |
59 | 102 | function decodePack(onEnd, read) { |
60 | 103 | if (read === undefined) |
61 | 104 | return decodePack.bind(this, onEnd) |
62 | 105 | |
@@ -111,9 +154,9 @@ | ||
111 | 154 | if (ended = end) return cb(end) |
112 | 155 | var firstByte = buf[0] |
113 | 156 | type = objectTypes[(firstByte >> 4) & 7] |
114 | 157 | value = firstByte & 15 |
115 | - // console.error('byte1', firstByte, firstByte.toString(2), value, value.toString(2)) | |
158 | + console.error('byte1', firstByte, firstByte.toString(2), value, value.toString(2)) | |
116 | 159 | shift = 4 |
117 | 160 | checkByte(firstByte) |
118 | 161 | }) |
119 | 162 | |
@@ -128,9 +171,9 @@ | ||
128 | 171 | if (ended = end) return cb(end) |
129 | 172 | var byte = buf[0] |
130 | 173 | value += (byte & 0x7f) << shift |
131 | 174 | shift += 7 |
132 | - // console.error('byte', byte, byte.toString(2), value, value.toString(2)) | |
175 | + console.error('byte', byte, byte.toString(2), value, value.toString(2)) | |
133 | 176 | checkByte(byte) |
134 | 177 | } |
135 | 178 | } |
136 | 179 | |
@@ -175,28 +218,87 @@ | ||
175 | 218 | |
176 | 219 | return readObject |
177 | 220 | } |
178 | 221 | |
222 | +function once(read) { | |
223 | + var done | |
224 | + return function (abort, cb) { | |
225 | + if (done) cb(done) | |
226 | + else done = true, read(abort, cb) | |
227 | + } | |
228 | +} | |
229 | + | |
230 | +function encodeVarInt(typeStr, length, cb) { | |
231 | + var type = objectTypeNums[typeStr] | |
232 | + // console.error('TYPE', type, typeStr, 'len', length, typeof cb) | |
233 | + if (!type) | |
234 | + return cb(new Error("Bad object type " + typeStr)) | |
235 | + | |
236 | + var vals = [] | |
237 | + var b = (type << 4) | (length & 15) | |
238 | + for (length >>= 4; length; length >>= 7) { | |
239 | + vals.push(b | 0x80) | |
240 | + b = length & 0x7f | |
241 | + } | |
242 | + vals.push(b) | |
243 | + console.error('sending var int', vals, vals.map(function (n) { | |
244 | + return ('00000000' + Number(n).toString(2)).substr(-8) | |
245 | + })) | |
246 | + cb(null, new Buffer(vals)) | |
247 | +} | |
248 | + | |
249 | +/* | |
250 | +function flow(read) { | |
251 | + return function (abort, cb) { | |
252 | + read(abort, cb, function nextCb(newRead, onEnd) { | |
253 | + read = newRead | |
254 | + return function (end, data) { | |
255 | + cb(end, data) | |
256 | + if (end) onEnd(end === true ? null : end) | |
257 | + } | |
258 | + }) | |
259 | + } | |
260 | +} | |
261 | +*/ | |
262 | + | |
179 | 263 | function encodePack(numObjects, readObject) { |
180 | - var ended | |
264 | + // var ended | |
181 | 265 | var header = new Buffer(12) |
182 | 266 | header.write('PACK') |
183 | 267 | header.writeUInt32BE(PACK_VERSION, 4) |
184 | 268 | header.writeUInt32BE(numObjects, 8) |
185 | 269 | var checksum = createHash('sha1') |
270 | + var readData | |
186 | 271 | |
272 | + /* | |
187 | 273 | return pull.through(function (data) { |
188 | - console.error('> ' + data.length, data.toString()) | |
274 | + console.error('> ' + data.length, JSON.stringify(data.toString('ascii'))) | |
189 | 275 | })(cat([ |
276 | + */ | |
277 | + return cat([ | |
190 | 278 | checksum(cat([ |
191 | 279 | pull.once(header), |
192 | - function (abort, cb) { | |
193 | - if (ended) return cb(ended) | |
194 | - readObject(abort, function (end, type, length, read) { | |
195 | - if (ended = end) return cb(end) | |
196 | - console.error('TODO: encode object') | |
197 | - }) | |
198 | - } | |
280 | + encodeObject | |
199 | 281 | ])), |
200 | 282 | checksum.readDigest |
201 | - ])) | |
283 | + ]) | |
284 | + // ) | |
285 | + | |
286 | + function encodeObject(abort, cb) { | |
287 | + if (readData) | |
288 | + readData(abort, function (end, data) { | |
289 | + if (end === true) | |
290 | + readObject(abort, nextObject) | |
291 | + else | |
292 | + cb(end, data) | |
293 | + }) | |
294 | + else | |
295 | + readObject(abort, nextObject) | |
296 | + | |
297 | + function nextObject(end, type, length, read) { | |
298 | + // console.error('got obj', end, type, length) | |
299 | + if (end) return cb(end) | |
300 | + readData = deflate(read) | |
301 | + encodeVarInt(type, length, cb) // nextCb(deflate(read), encodeObject)) | |
302 | + } | |
303 | + } | |
202 | 304 | } |
test/git-remote-empty.js | ||
---|---|---|
@@ -25,8 +25,9 @@ | ||
25 | 25 | hasher, |
26 | 26 | pull.collect(function (err, bufs) { |
27 | 27 | if (err) throw err |
28 | 28 | var buf = Buffer.concat(bufs) |
29 | + console.error('obj', type, length, JSON.stringify(buf.toString('ascii'))) | |
29 | 30 | process.send({object: { |
30 | 31 | type: type, |
31 | 32 | data: buf.toString('ascii'), |
32 | 33 | length: length, |
test/git-remote-full.js | ||
---|---|---|
@@ -1,8 +1,9 @@ | ||
1 | 1 | #!/usr/bin/env node |
2 | 2 | |
3 | 3 | var toPull = require('stream-to-pull-stream') |
4 | 4 | var pull = require('pull-stream') |
5 | +var repo = require('./repo') | |
5 | 6 | |
6 | 7 | process.on('uncaughtException', function (err) { |
7 | 8 | if (err.stack) |
8 | 9 | err = {stack: err.stack, message: err.message} |
@@ -15,16 +16,40 @@ | ||
15 | 16 | {name: 'refs/heads/master', value: HEAD}, |
16 | 17 | {name: 'HEAD', value: HEAD} |
17 | 18 | ] |
18 | 19 | |
20 | +var objects = [ | |
21 | + {type: 'commit', object: repo.commit}, | |
22 | + {type: 'tree', object: repo.tree}, | |
23 | + {type: 'blob', object: repo.file} | |
24 | +] | |
25 | + | |
26 | +function streamObject(read) { | |
27 | + var ended | |
28 | + return function readObject(abort, cb) { | |
29 | + read(abort, function (end, item) { | |
30 | + if (ended = end) return cb(end) | |
31 | + var data = item.object.data | |
32 | + cb(null, item.type, data.length, pull.once(data)) | |
33 | + }) | |
34 | + } | |
35 | +} | |
36 | + | |
19 | 37 | pull( |
20 | 38 | toPull(process.stdin), |
21 | 39 | require('../')({ |
22 | 40 | prefix: 'foo', |
23 | 41 | refSource: pull.values(refs), |
24 | 42 | wantSink: pull.drain(function (want) { |
25 | 43 | process.send({want: want}) |
26 | 44 | }), |
45 | + getObjects: function (ancestorHash, cb) { | |
46 | + // console.error('get obj!', ancestorHash) | |
47 | + cb(null, objects.length, pull( | |
48 | + pull.values(objects), | |
49 | + streamObject | |
50 | + )) | |
51 | + } | |
27 | 52 | }), |
28 | 53 | toPull(process.stdout, function (err) { |
29 | 54 | if (err) |
30 | 55 | throw err |
test/run.js | ||
---|---|---|
@@ -3,19 +3,14 @@ | ||
3 | 3 | var path = require('path') |
4 | 4 | var mktemp = require('mktemp') |
5 | 5 | var rimraf = require('rimraf') |
6 | 6 | var fs = require('fs') |
7 | +var repo = require('./repo') | |
7 | 8 | |
8 | -function noop() {} | |
9 | - | |
10 | 9 | var env = Object.create(process.env) |
11 | 10 | env.PATH = __dirname + ':' + env.PATH |
12 | -env.GIT_AUTHOR_DATE = env.GIT_COMMITTER_DATE = '1000000000 -0500' | |
13 | -var user = { | |
14 | - name: 'test', | |
15 | - email: 'test@localhost' | |
16 | -} | |
17 | -user.str = user.name + ' <' + user.email + '>' | |
11 | +env.GIT_AUTHOR_DATE = env.GIT_COMMITTER_DATE = repo.date | |
12 | +var user = repo.user | |
18 | 13 | var remote = { |
19 | 14 | empty: 'empty.js://', |
20 | 15 | full: 'full.js://' |
21 | 16 | } |
@@ -78,38 +73,16 @@ | ||
78 | 73 | t.end() |
79 | 74 | }) |
80 | 75 | }) |
81 | 76 | |
82 | -function hexToStr(str) { | |
83 | - var buf = new Buffer(str.length / 2) | |
84 | - buf.hexWrite(str) | |
85 | - return buf.toString('ascii') | |
86 | -} | |
87 | - | |
88 | 77 | tape('make a commit and push', function (t) { |
89 | 78 | t.plan(8) // write, add, commit, push, ref, commit, tree, blob |
90 | 79 | |
91 | - var file = { | |
92 | - name: 'blah.txt', | |
93 | - data: 'i am a file', | |
94 | - hash: '68bd10497ea68e91fa85024d0a0b2fe54e212914' | |
95 | - } | |
80 | + var file = repo.file | |
81 | + var commitMessage = repo.commitMessage | |
82 | + var commit = repo.commit | |
83 | + var tree = repo.tree | |
96 | 84 | |
97 | - var tree = { | |
98 | - hash: '75c54aa020772a916853987a03bff7079463a861', | |
99 | - data: '100644 ' + file.name + '\0' + hexToStr(file.hash) | |
100 | - } | |
101 | - | |
102 | - var commitMessage = 'Initial commit' | |
103 | - var commit = { | |
104 | - hash: 'edb5b50e8019797925820007d318870f8c346726', | |
105 | - data: ['tree ' + tree.hash, | |
106 | - 'author ' + user.str + ' 1000000000 -0500', | |
107 | - 'committer ' + user.str + ' 1000000000 -0500', | |
108 | - '', commitMessage, '' | |
109 | - ].join('\n') | |
110 | - } | |
111 | - | |
112 | 85 | function obj(type, o) { |
113 | 86 | return { |
114 | 87 | type: type, |
115 | 88 | data: o.data, |
@@ -165,9 +138,9 @@ | ||
165 | 138 | |
166 | 139 | 0 && |
167 | 140 | tape('clone into new dir', function (t) { |
168 | 141 | var dir = path.join(tmpDir, 'clonedir') |
169 | - t.plan(3) | |
142 | + t.plan(2) | |
170 | 143 | t.git('clone', '-vv', remote.full, dir, function (msg) { |
171 | 144 | if (msg.want) |
172 | 145 | t.deepEquals(msg.want, { |
173 | 146 | type: 'want', |
test/repo.js | ||
---|---|---|
@@ -1,0 +1,41 @@ | ||
1 | +function hexToStr(str) { | |
2 | + var buf = new Buffer(str.length / 2) | |
3 | + buf.hexWrite(str) | |
4 | + return buf.toString('ascii') | |
5 | +} | |
6 | + | |
7 | +var date = '1000000000 -0500' | |
8 | + | |
9 | +var user = { | |
10 | + name: 'test', | |
11 | + email: 'test@localhost' | |
12 | +} | |
13 | +user.str = user.name + ' <' + user.email + '>' | |
14 | + | |
15 | +var file = { | |
16 | + name: 'blah.txt', | |
17 | + data: 'i am a file', | |
18 | + hash: '68bd10497ea68e91fa85024d0a0b2fe54e212914' | |
19 | +} | |
20 | + | |
21 | +var tree = { | |
22 | + hash: '75c54aa020772a916853987a03bff7079463a861', | |
23 | + data: '100644 ' + file.name + '\0' + hexToStr(file.hash) | |
24 | +} | |
25 | + | |
26 | +var commitMessage = 'Initial commit' | |
27 | +var commit = { | |
28 | + hash: 'edb5b50e8019797925820007d318870f8c346726', | |
29 | + data: ['tree ' + tree.hash, | |
30 | + 'author ' + user.str + ' ' + date, | |
31 | + 'committer ' + user.str + ' ' + date, | |
32 | + '', commitMessage, '' | |
33 | + ].join('\n') | |
34 | +} | |
35 | + | |
36 | +exports.date = date | |
37 | +exports.user = user | |
38 | +exports.file = file | |
39 | +exports.tree = tree | |
40 | +exports.commitMessage = commitMessage | |
41 | +exports.commit = commit |
Built with git-ssb-web