Skip to content

Commit 7f07b5d

Browse files
lddubeauisaacs
authored andcommitted
fix(git): ensure stream failures are reported
Prior to the change, race conditions could cause errors on the stream to be lost. The symptom for npm users would be the infamous "cb() never called" error. PR-URL: #1 Close: #1 Reviewed-by: @isaacs
1 parent fcf6de3 commit 7f07b5d

File tree

2 files changed

+52
-10
lines changed

2 files changed

+52
-10
lines changed

extract.js

+11-10
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,22 @@ function extract (spec, dest, opts) {
5050
function tryExtract (spec, tarStream, dest, opts) {
5151
return new BB((resolve, reject) => {
5252
tarStream.on('error', reject)
53-
setImmediate(resolve)
53+
54+
rimraf(dest)
55+
.then(() => mkdirp(dest))
56+
.then(() => {
57+
const xtractor = extractStream(spec, dest, opts)
58+
xtractor.on('error', reject)
59+
xtractor.on('close', resolve)
60+
tarStream.pipe(xtractor)
61+
})
62+
.catch(reject)
5463
})
55-
.then(() => rimraf(dest))
56-
.then(() => mkdirp(dest))
57-
.then(() => new BB((resolve, reject) => {
58-
const xtractor = extractStream(spec, dest, opts)
59-
tarStream.on('error', reject)
60-
xtractor.on('error', reject)
61-
xtractor.on('close', resolve)
62-
tarStream.pipe(xtractor)
63-
}))
6464
.catch(err => {
6565
if (err.code === 'EINTEGRITY') {
6666
err.message = `Verification failed while extracting ${spec}:\n${err.message}`
6767
}
68+
6869
throw err
6970
})
7071
}

test/git.extract.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict'
2+
3+
const BB = require('bluebird')
4+
const fs = BB.promisifyAll(require('fs'))
5+
const mkdirp = BB.promisify(require('mkdirp'))
6+
const npmlog = require('npmlog')
7+
const path = require('path')
8+
const test = require('tap').test
9+
10+
const testDir = require('./util/test-dir')(__filename)
11+
12+
const extract = require('../extract.js')
13+
14+
npmlog.level = process.env.LOGLEVEL || 'silent'
15+
const OPTS = {
16+
git: 'git',
17+
cache: path.join(testDir, 'cache'),
18+
log: npmlog,
19+
registry: 'https://my.mock.registry/',
20+
retry: false
21+
}
22+
23+
test('extracting a git target reports failures', t => {
24+
const oldPath = process.env.PATH
25+
process.env.PATH = ''
26+
const dest = path.join(testDir, 'foo')
27+
return mkdirp(dest)
28+
.then(() => fs.writeFileAsync(path.join(dest, 'q'), 'foo'))
29+
.then(() => extract('github:zkat/pacote', dest,
30+
Object.assign({}, OPTS)))
31+
.finally(() => {
32+
process.env.PATH = oldPath
33+
})
34+
.then(() => {
35+
t.fail('the promise should not have resolved')
36+
}, (err) => {
37+
// We're not testing the specific text of the error message. We just check
38+
// that it is an execution error.
39+
t.equal(err.code, 'ENOENT')
40+
})
41+
})

0 commit comments

Comments
 (0)