Commit a53fb68ffb75c9fc0ff72ebbe56746e37f323cdc
Start using abstract-pull-git-repo API
Charles Lehner committed on 2/17/2016, 11:09:24 PMParent: 9c5fc252c08c46239564a18250cc3d09354a620b
Files changed
README.md | changed |
index.js | changed |
package.json | changed |
test/remote/git-remote-empty.js | changed |
test/remote/git-remote-full.js | changed |
test/run.js | changed |
README.md | ||
---|---|---|
@@ -11,99 +11,53 @@ | ||
11 | 11 | var toPull = require('stream-to-pull-stream') |
12 | 12 | var pull = require('pull-stream') |
13 | 13 | var gitRemoteHelper = require('.') |
14 | 14 | |
15 | -var options = { | |
16 | - updateSink: pull.drain(function (update) { | |
17 | - console.error('Updating ' + update.name + ' to ' + update.new) | |
18 | - }), | |
19 | - objectSink: function (read) { | |
20 | - read(null, function next(end, object) { | |
15 | +var repo = { | |
16 | + refs: pull.empty(), | |
17 | + hasObject: function (hash, cb) { cb(null, false) }, | |
18 | + getObject: function (hash, cb) { cb(null, null) }, | |
19 | + update: function (readUpdates, readObjects) { | |
20 | + pull( | |
21 | + readUpdates, | |
22 | + pull.drain(function (update) { | |
23 | + console.error('Updating ' + update.name + ' to ' + update.new) | |
24 | + }) | |
25 | + ) | |
26 | + readObjects(null, function next(end, object) { | |
21 | 27 | if (end === true) return |
22 | 28 | if (end) throw end |
23 | 29 | pull( |
24 | 30 | object.read, |
25 | 31 | pull.collect(function (err, bufs) { |
26 | 32 | if (err) throw err |
27 | 33 | var buf = Buffer.concat(bufs, object.length) |
28 | 34 | console.error('Got object', object, buf) |
29 | - read(null, next) | |
35 | + readObjects(null, next) | |
30 | 36 | }) |
31 | 37 | ) |
32 | 38 | }) |
33 | 39 | } |
34 | 40 | } |
35 | 41 | |
36 | 42 | pull( |
37 | 43 | toPull(process.stdin), |
38 | - gitRemoteHelper(options), | |
44 | + gitRemoteHelper(repo), | |
39 | 45 | toPull(process.stdout) |
40 | 46 | ) |
47 | + | |
41 | 48 | ``` |
42 | 49 | |
43 | 50 | ## API |
44 | 51 | |
45 | -The streams in this module are [pull-streams](https://github.com/dominictarr/pull-stream). | |
52 | +#### `gitRemoteHelper(repo)` | |
46 | 53 | |
47 | -- `gitRemoteHelper(options)` | |
48 | - | |
49 | 54 | Create a through-stream for the stdio of a git-remote-helper |
50 | 55 | |
51 | -- `options.refsSource` | |
56 | +- `repo`: an [abstract-pull-git-repo][]-compliant git repo object. | |
52 | 57 | |
53 | - Readable stream of refs that the remote has. | |
58 | +[abstract-pull-git-repo]: https://github.com/clehner/abstract-pull-git-repo | |
54 | 59 | |
55 | - Ref object are of the form `{name: name, value: hash}` | |
56 | - | |
57 | - - `ref.name`: a name like `"HEAD"` or `"refs/heads/master"` | |
58 | - - `ref.value`: 20-character SHA1 hash of a commit | |
59 | - | |
60 | -- `options.updateSink` | |
61 | - | |
62 | - Reader for updates received from the client during a `git push`. | |
63 | - | |
64 | - - `update.name`: the name of the ref, e.g. `"refs/heads/master"` | |
65 | - - `update.old`: the previous rev (commit SHA1 hash) of the branch. | |
66 | - May be null if the branch did not exist before. | |
67 | - - `update.new`: the new rev of the branch. null to delete the ref. | |
68 | - | |
69 | -- `options.objectSink` | |
70 | - | |
71 | - Reader for git objects received in a `git push`. | |
72 | - | |
73 | - - `object.type`: the type of the object, either | |
74 | - `"tag"`, `"commit"`, `"tree"`, or `"blob"` | |
75 | - - `object.length`: the size in bytes of the object | |
76 | - - `object.read`: readable stream of the object's data. This has to be | |
77 | - drained before `objectSink` can read the next object. | |
78 | - | |
79 | -- `options.wantSink` | |
80 | - | |
81 | - Reader for wants received by client during a `git fetch`. | |
82 | - | |
83 | - - `want.type == "want"`: the client wants this object | |
84 | - - `want.type == "shallow"`: the client *has* this object but it is shallow. | |
85 | - TODO: put this somewhere else | |
86 | - - `want.hash`: SHA1 hash of the object | |
87 | - | |
88 | -- `options.hasObject`: `function (hash, cb(Boolean))` | |
89 | - | |
90 | - Query the remote if it has a specific git object. Used in `git fetch` to help | |
91 | - the remote decide what objects to send to the client. | |
92 | - | |
93 | -- `options.getObjects`: `function (id, cb(end, numObjects, readObject))` | |
94 | - | |
95 | - Get a stream of git objects to send to the client. These should include the | |
96 | - objects passed from the client as wants in `wantSink`, and their history | |
97 | - (ancestor commits and their objects), but don't have to go further back than | |
98 | - the common ancestor object `id`. | |
99 | - | |
100 | - - `id`: hash of a common ancestor of objects that the client and the remote | |
101 | - have. | |
102 | - - `end`: read error or `true` if the stream is done | |
103 | - - `numObjects`: number of objects that readObject will stream | |
104 | - - `readObject`: readable stream of git objects | |
105 | - | |
106 | 60 | ## TODO |
107 | 61 | |
108 | 62 | - Implement tree-walking to simplify `wantSink` and `getObjects` |
109 | 63 | - Handle shallow and unshallow fetch |
index.js | ||
---|---|---|
@@ -51,12 +51,14 @@ | ||
51 | 51 | } |
52 | 52 | } |
53 | 53 | |
54 | 54 | // upload-pack: fetch to client |
55 | -function uploadPack(read, hasObject, getObjects, refSource, wantSink, options) { | |
55 | +function uploadPack(read, repo, options) { | |
56 | + // getObjects, wantSink | |
56 | 57 | /* multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress |
57 | 58 | * include-tag multi_ack_detailed symref=HEAD:refs/heads/master |
58 | 59 | * agent=git/2.7.0 */ |
60 | + var refSource = repo.refs.bind(repo) | |
59 | 61 | var sendRefs = receivePackHeader([ |
60 | 62 | ], refSource, false) |
61 | 63 | |
62 | 64 | var lines = pktLine.decode(read, options) |
@@ -105,9 +107,10 @@ | ||
105 | 107 | cb(end) |
106 | 108 | else if (have.type != 'have') |
107 | 109 | cb(new Error('Unknown have' + JSON.stringify(have))) |
108 | 110 | else |
109 | - hasObject(have.hash, function (haveIt) { | |
111 | + repo.hasObject(have.hash, function (err, haveIt) { | |
112 | + if (err) return cb(err) | |
110 | 113 | if (!haveIt) |
111 | 114 | return readHave(null, next) |
112 | 115 | commonHash = haveIt |
113 | 116 | acked = true |
@@ -164,10 +167,11 @@ | ||
164 | 167 | } |
165 | 168 | } |
166 | 169 | |
167 | 170 | // receive-pack: push from client |
168 | -function receivePack(read, objectSink, refSource, updateSink, options) { | |
171 | +function receivePack(read, repo, options) { | |
169 | 172 | var ended |
173 | + var refSource = repo.refs.bind(repo) | |
170 | 174 | var sendRefs = receivePackHeader([ |
171 | 175 | 'delete-refs', |
172 | 176 | ], refSource, true) |
173 | 177 | |
@@ -181,18 +185,19 @@ | ||
181 | 185 | // receive their refs |
182 | 186 | var lines = pktLine.decode(read, options) |
183 | 187 | pull( |
184 | 188 | lines.updates, |
185 | - pull.through(null, updatesDone), | |
186 | - updateSink | |
189 | + pull.collect(function (err, updates) { | |
190 | + if (err) return cb(err) | |
191 | + repo.update(pull.values(updates), pull( | |
192 | + lines.passthrough, | |
193 | + pack.decode(onEnd) | |
194 | + ), onEnd) | |
195 | + }) | |
187 | 196 | ) |
188 | - function updatesDone(err) { | |
189 | - if (err) return cb(err) | |
190 | - pull( | |
191 | - lines.passthrough, | |
192 | - pack.decode(cb), | |
193 | - objectSink | |
194 | - ) | |
197 | + function onEnd(err) { | |
198 | + if (!ended) | |
199 | + cb(ended = err) | |
195 | 200 | } |
196 | 201 | }, |
197 | 202 | pull.once('unpack ok') |
198 | 203 | ]) |
@@ -210,19 +215,15 @@ | ||
210 | 215 | } |
211 | 216 | } |
212 | 217 | } |
213 | 218 | |
214 | -module.exports = function (opts) { | |
219 | +module.exports = function (repo) { | |
215 | 220 | var ended |
216 | - var objectSink = opts.objectSink || | |
217 | - function () { throw new Error('Missing object sink') } | |
218 | - var hasObject = opts.hasObject || function (hash, cb) { cb(false) } | |
221 | + /* | |
219 | 222 | var getObjects = opts.getObjects || function (id, cb) { |
220 | 223 | cb(null, 0, pull.empty()) |
221 | 224 | } |
222 | - var refSource = opts.refSource || pull.empty() | |
223 | - var updateSink = opts.updateSink || pull.drain() | |
224 | - var wantSink = opts.wantSink || pull.drain() | |
225 | + */ | |
225 | 226 | |
226 | 227 | var options = { |
227 | 228 | verbosity: 1, |
228 | 229 | progress: false |
@@ -231,13 +232,11 @@ | ||
231 | 232 | function handleConnect(cmd, read) { |
232 | 233 | var args = util.split2(cmd) |
233 | 234 | switch (args[0]) { |
234 | 235 | case 'git-upload-pack': |
235 | - return prepend('\n', uploadPack(read, hasObject, getObjects, refSource, | |
236 | - wantSink, options)) | |
236 | + return prepend('\n', uploadPack(read, repo, options)) | |
237 | 237 | case 'git-receive-pack': |
238 | - return prepend('\n', receivePack(read, objectSink, refSource, | |
239 | - updateSink, options)) | |
238 | + return prepend('\n', receivePack(read, repo, options)) | |
240 | 239 | default: |
241 | 240 | return pull.error(new Error('Unknown service ' + args[0])) |
242 | 241 | } |
243 | 242 | } |
package.json | ||
---|---|---|
@@ -11,8 +11,9 @@ | ||
11 | 11 | "url": "git://github.com/clehner/pull-git-remote-helper" |
12 | 12 | }, |
13 | 13 | "keywords": [ |
14 | 14 | "pull-stream", |
15 | + "pull-git-repo", | |
15 | 16 | "git", |
16 | 17 | "git-remote-helper" |
17 | 18 | ], |
18 | 19 | "author": "Charles Lehner (http://celehner.com/)", |
test/remote/git-remote-empty.js | ||
---|---|---|
@@ -13,10 +13,21 @@ | ||
13 | 13 | |
14 | 14 | pull( |
15 | 15 | toPull(process.stdin), |
16 | 16 | require('../../')({ |
17 | - objectSink: function (read) { | |
18 | - read(null, function next(end, object) { | |
17 | + refs: pull.empty(), | |
18 | + hasObject: function (hash, cb) { cb(null, false) }, | |
19 | + getObject: function (hash, cb) { cb(null, null) }, | |
20 | + update: function (readRefs, readObjects) { | |
21 | + pull( | |
22 | + readRefs, | |
23 | + pull.drain(function (update) { | |
24 | + process.send({update: update}) | |
25 | + }, function (err) { | |
26 | + if (err) throw err | |
27 | + }) | |
28 | + ) | |
29 | + readObjects(null, function next(end, object) { | |
19 | 30 | if (end === true) return |
20 | 31 | if (end) throw end |
21 | 32 | var hasher = util.createGitObjectHash(object.type, object.length) |
22 | 33 | pull( |
@@ -30,16 +41,13 @@ | ||
30 | 41 | data: buf.toString('ascii'), |
31 | 42 | length: object.length, |
32 | 43 | hash: hasher.digest('hex') |
33 | 44 | }}) |
34 | - read(null, next) | |
45 | + readObjects(null, next) | |
35 | 46 | }) |
36 | 47 | ) |
37 | 48 | }) |
38 | - }, | |
39 | - updateSink: pull.drain(function (update) { | |
40 | - process.send({update: update}) | |
41 | - }) | |
49 | + } | |
42 | 50 | }), |
43 | 51 | toPull(process.stdout, function (err) { |
44 | 52 | if (err) |
45 | 53 | throw err |
test/remote/git-remote-full.js | ||
---|---|---|
@@ -23,42 +23,30 @@ | ||
23 | 23 | {type: 'blob', object: repo.file} |
24 | 24 | ] |
25 | 25 | |
26 | 26 | var hashes = {} |
27 | -hashes[repo.commit.hash] = 1 | |
28 | -hashes[repo.tree.hash] = 1 | |
29 | -hashes[repo.file.hash] = 1 | |
27 | +hashes[repo.commit.hash] = objects[0] | |
28 | +hashes[repo.tree.hash] = objects[1] | |
29 | +hashes[repo.file.hash] = objects[2] | |
30 | 30 | |
31 | -function streamObject(read) { | |
32 | - var ended | |
33 | - return function readObject(abort, cb) { | |
34 | - read(abort, function (end, item) { | |
35 | - if (ended = end) return cb(end) | |
36 | - var data = item.object.data | |
37 | - cb(null, { | |
38 | - type: item.type, | |
39 | - length: data.length, | |
40 | - read: pull.once(data) | |
41 | - }) | |
42 | - }) | |
43 | - } | |
44 | -} | |
45 | - | |
46 | 31 | pull( |
47 | 32 | toPull(process.stdin), |
48 | 33 | require('../../')({ |
49 | - refSource: pull.values(refs), | |
34 | + refs: pull.values(refs), | |
50 | 35 | wantSink: pull.drain(function (want) { |
51 | 36 | process.send({want: want}) |
52 | 37 | }), |
53 | 38 | hasObject: function (hash, cb) { |
54 | - cb(hash in hashes) | |
39 | + cb(null, hash in hashes) | |
55 | 40 | }, |
56 | - getObjects: function (ancestorHash, cb) { | |
57 | - cb(null, objects.length, pull( | |
58 | - pull.values(objects), | |
59 | - streamObject | |
60 | - )) | |
41 | + getObject: function (hash, cb) { | |
42 | + var item = hashes[hash] | |
43 | + if (!item) return cb(null, null) | |
44 | + cb(null, { | |
45 | + type: item.type, | |
46 | + length: item.object.data.length, | |
47 | + read: pull.once(item.object.data) | |
48 | + }) | |
61 | 49 | } |
62 | 50 | }), |
63 | 51 | toPull(process.stdout, function (err) { |
64 | 52 | if (err) |
Built with git-ssb-web