| 35 | // Invokes `$ git-upload-pack --strict <dir>`, communicates haves and wants and |
| 36 | // emits 'ready' when stdout becomes a pack file stream. |
| 37 | function upload_pack (dir, want, have) { |
| 38 | // reference: |
| 39 | // https://github.com/git/git/blob/b594c975c7e865be23477989d7f36157ad437dc7/Documentation/technical/pack-protocol.txt#L346-L393 |
| 40 | var upload = spawn('git-upload-pack', ['--strict', dir]) |
| 41 | writeln('want ' + want) |
| 42 | writeln() |
| 43 | if (have) { |
| 44 | writeln('have ' + have) |
| 45 | writeln() |
| 46 | } |
| 47 | writeln('done') |
| 48 | |
| 49 | // We want to read git's output one line at a time, and not read any more |
| 50 | // than we have to. That way, when we finish discussing wants and haves, we |
| 51 | // can pipe the rest of the output to a stream. |
| 52 | // |
| 53 | // We use `mode` to keep track of state and formulate responses. It returns |
| 54 | // `false` when we should stop reading. |
| 55 | var mode = list |
| 56 | upload.stdout.on('readable', function () { |
| 57 | while (true) { |
| 58 | var line = getline() |
| 59 | if (line === null) { |
| 60 | return // to wait for more output |
| 61 | } |
| 62 | if (!mode(line)) { |
| 63 | upload.stdout.removeAllListeners('readable') |
| 64 | upload.emit('ready') |
| 65 | return |
| 66 | } |
| 67 | } |
| 68 | }) |
| 69 | |
| 70 | var getline_len = null |
| 71 | // Extracts exactly one line from the stream. Uses `getline_len` in case the |
| 72 | // whole line could not be read. |
| 73 | function getline () { |
| 74 | // Format: '####line' where '####' represents the length of 'line' in hex. |
| 75 | if (!getline_len) { |
| 76 | getline_len = upload.stdout.read(4) |
| 77 | if (getline_len === null) { |
| 78 | return null |
| 79 | } |
| 80 | getline_len = parseInt(getline_len, 16) |
| 81 | } |
| 82 | |
| 83 | if (getline_len === 0) { |
| 84 | return '' |
| 85 | } |
| 86 | |
| 87 | // Subtract by the four we just read, and the terminating newline. |
| 88 | var line = upload.stdout.read(getline_len - 4 - 1) |
| 89 | if (!line) { |
| 90 | return null |
| 91 | } |
| 92 | getline_len = null |
| 93 | upload.stdout.read(1) // And discard the newline. |
| 94 | return line.toString() |