diff options
Diffstat (limited to 'deps/npm/node_modules/pacote/lib')
14 files changed, 397 insertions, 163 deletions
diff --git a/deps/npm/node_modules/pacote/lib/extract-stream.js b/deps/npm/node_modules/pacote/lib/extract-stream.js index b3c720b07f..d7e8fd5a18 100644 --- a/deps/npm/node_modules/pacote/lib/extract-stream.js +++ b/deps/npm/node_modules/pacote/lib/extract-stream.js @@ -1,16 +1,53 @@ 'use strict' +const Minipass = require('minipass') const path = require('path') const tar = require('tar') module.exports = extractStream module.exports._computeMode = computeMode +class Transformer extends Minipass { + constructor (spec, opts) { + super() + this.spec = spec + this.opts = opts + this.str = '' + } + write (data) { + this.str += data + return true + } + end () { + const replaced = this.str.replace( + /}\s*$/, + `\n,"_resolved": ${ + JSON.stringify(this.opts.resolved || '') + }\n,"_integrity": ${ + JSON.stringify(this.opts.integrity || '') + }\n,"_from": ${ + JSON.stringify(this.spec.toString()) + }\n}` + ) + super.write(replaced) + return super.end() + } +} + function computeMode (fileMode, optMode, umask) { return (fileMode | optMode) & ~(umask || 0) } -function extractStream (dest, opts) { +function pkgJsonTransform (spec, opts) { + return entry => { + if (entry.path === 'package.json') { + const transformed = new Transformer(spec, opts) + return transformed + } + } +} + +function extractStream (spec, dest, opts) { opts = opts || {} const sawIgnores = new Set() return tar.x({ @@ -20,6 +57,7 @@ function extractStream (dest, opts) { onwarn: msg => opts.log && opts.log.warn('tar', msg), uid: opts.uid, gid: opts.gid, + transform: opts.resolved && pkgJsonTransform(spec, opts), onentry (entry) { if (entry.type.toLowerCase() === 'file') { entry.mode = computeMode(entry.mode, opts.fmode, opts.umask) diff --git a/deps/npm/node_modules/pacote/lib/fetchers/directory.js b/deps/npm/node_modules/pacote/lib/fetchers/directory.js index 4f7f8847a7..f6e680f660 100644 --- a/deps/npm/node_modules/pacote/lib/fetchers/directory.js +++ b/deps/npm/node_modules/pacote/lib/fetchers/directory.js @@ -29,6 +29,7 @@ Fetcher.impl(fetchDirectory, { pkg._hasShrinkwrap = !!sr pkg._resolved = spec.fetchSpec pkg._integrity = false // Don't auto-calculate integrity + pkg._shasum = false // Don't auto-calculate shasum either return pkg } ).then(pkg => { diff --git a/deps/npm/node_modules/pacote/lib/fetchers/file.js b/deps/npm/node_modules/pacote/lib/fetchers/file.js index 48bec0c2d8..5688cd1bdd 100644 --- a/deps/npm/node_modules/pacote/lib/fetchers/file.js +++ b/deps/npm/node_modules/pacote/lib/fetchers/file.js @@ -52,13 +52,13 @@ Fetcher.impl(fetchFile, { } else { let integrity const cacheWriter = !opts.cache - ? BB.resolve(null) - : (pipe( - fs.createReadStream(src), - cacache.put.stream(opts.cache, `pacote:tarball:${src}`, { - integrity: opts.integrity - }).on('integrity', d => { integrity = d }) - )) + ? BB.resolve(null) + : (pipe( + fs.createReadStream(src), + cacache.put.stream(opts.cache, `pacote:tarball:${src}`, { + integrity: opts.integrity + }).on('integrity', d => { integrity = d }) + )) return cacheWriter.then(() => { if (integrity) { stream.emit('integrity', integrity) } return pipe(fs.createReadStream(src), stream) diff --git a/deps/npm/node_modules/pacote/lib/fetchers/git.js b/deps/npm/node_modules/pacote/lib/fetchers/git.js index 11b5695255..66a2093ee3 100644 --- a/deps/npm/node_modules/pacote/lib/fetchers/git.js +++ b/deps/npm/node_modules/pacote/lib/fetchers/git.js @@ -112,7 +112,8 @@ function plainManifest (repo, spec, opts) { _ref: ref, _rawRef: spec.gitCommittish || spec.gitRange, _uniqueResolved: resolved, - _integrity: false + _integrity: false, + _shasum: false } } else { // We're SOL and need a full clone :( @@ -125,7 +126,8 @@ function plainManifest (repo, spec, opts) { _rawRef: rawRef, _resolved: rawRef && rawRef.match(/^[a-f0-9]{40}$/) && resolved, _uniqueResolved: rawRef && rawRef.match(/^[a-f0-9]{40}$/) && resolved, - _integrity: false + _integrity: false, + _shasum: false } } }) @@ -135,16 +137,16 @@ function resolve (url, spec, name, opts) { const isSemver = !!spec.gitRange return git.revs(url, opts).then(remoteRefs => { return isSemver - ? pickManifest({ - versions: remoteRefs.versions, - 'dist-tags': remoteRefs['dist-tags'], - name: name - }, spec.gitRange, opts) - : remoteRefs - ? BB.resolve( - remoteRefs.refs[spec.gitCommittish] || remoteRefs.refs[remoteRefs.shas[spec.gitCommittish]] - ) - : null + ? pickManifest({ + versions: remoteRefs.versions, + 'dist-tags': remoteRefs['dist-tags'], + name: name + }, spec.gitRange, opts) + : remoteRefs + ? BB.resolve( + remoteRefs.refs[spec.gitCommittish] || remoteRefs.refs[remoteRefs.shas[spec.gitCommittish]] + ) + : null }) } diff --git a/deps/npm/node_modules/pacote/lib/fetchers/registry/fetch.js b/deps/npm/node_modules/pacote/lib/fetchers/registry/fetch.js index a947ccea55..3a2a4a5a77 100644 --- a/deps/npm/node_modules/pacote/lib/fetchers/registry/fetch.js +++ b/deps/npm/node_modules/pacote/lib/fetchers/registry/fetch.js @@ -68,12 +68,12 @@ function logRequest (uri, res, startTime, opts) { function getCacheMode (opts) { return opts.offline - ? 'only-if-cached' - : opts.preferOffline - ? 'force-cache' - : opts.preferOnline - ? 'no-cache' - : 'default' + ? 'only-if-cached' + : opts.preferOffline + ? 'force-cache' + : opts.preferOnline + ? 'no-cache' + : 'default' } function getHeaders (uri, registry, opts) { diff --git a/deps/npm/node_modules/pacote/lib/fetchers/registry/manifest.js b/deps/npm/node_modules/pacote/lib/fetchers/registry/manifest.js index 4488ddb4c7..4e5a8010e2 100644 --- a/deps/npm/node_modules/pacote/lib/fetchers/registry/manifest.js +++ b/deps/npm/node_modules/pacote/lib/fetchers/registry/manifest.js @@ -28,8 +28,8 @@ function manifest (spec, opts) { function metadataUrl (registry, name) { const normalized = registry.slice(-1) !== '/' - ? registry + '/' - : registry + ? registry + '/' + : registry return url.resolve(normalized, name) } diff --git a/deps/npm/node_modules/pacote/lib/fetchers/registry/tarball.js b/deps/npm/node_modules/pacote/lib/fetchers/registry/tarball.js index 2c63872e7f..7239981279 100644 --- a/deps/npm/node_modules/pacote/lib/fetchers/registry/tarball.js +++ b/deps/npm/node_modules/pacote/lib/fetchers/registry/tarball.js @@ -7,22 +7,41 @@ const manifest = require('./manifest') const optCheck = require('../../util/opt-check') const PassThrough = require('stream').PassThrough const pickRegistry = require('./pick-registry') -const pipe = BB.promisify(require('mississippi').pipe) const ssri = require('ssri') const url = require('url') module.exports = tarball function tarball (spec, opts) { opts = optCheck(opts) + const registry = pickRegistry(spec, opts) const stream = new PassThrough() - manifest(spec, opts).then(manifest => { - stream.emit('manifest', manifest) - return pipe( - fromManifest(manifest, spec, opts).on( - 'integrity', i => stream.emit('integrity', i) - ), - stream + let mani + if ( + opts.resolved && + // spec.type === 'version' && + opts.resolved.indexOf(registry) === 0 + ) { + // fakeChild is a shortcut to avoid looking up a manifest! + mani = BB.resolve({ + name: spec.name, + version: spec.fetchSpec, + _integrity: opts.integrity, + _resolved: opts.resolved, + _fakeChild: true + }) + } else { + // We can't trust opts.resolved if it's going to a separate host. + mani = manifest(spec, opts) + } + + mani.then(mani => { + !mani._fakeChild && stream.emit('manifest', mani) + const fetchStream = fromManifest(mani, spec, opts).on( + 'integrity', i => stream.emit('integrity', i) ) + fetchStream.on('error', err => stream.emit('error', err)) + fetchStream.pipe(stream) + return null }).catch(err => stream.emit('error', err)) return stream } @@ -33,45 +52,44 @@ function fromManifest (manifest, spec, opts) { opts.scope = spec.scope || opts.scope const stream = new PassThrough() const registry = pickRegistry(spec, opts) - const uri = getTarballUrl(registry, manifest) + const uri = getTarballUrl(spec, registry, manifest, opts) fetch(uri, registry, Object.assign({ headers: { 'pacote-req-type': 'tarball', - 'pacote-pkg-id': `registry:${ - spec.type === 'remote' - ? spec - : `${manifest.name}@${manifest.version}` - }` + 'pacote-pkg-id': `registry:${manifest.name}@${uri}` }, integrity: manifest._integrity, algorithms: [ manifest._integrity - ? ssri.parse(manifest._integrity).pickAlgorithm() - : 'sha1' + ? ssri.parse(manifest._integrity).pickAlgorithm() + : 'sha1' ], spec - }, opts)).then(res => { - const hash = res.headers.get('x-local-cache-hash') - if (hash) { - stream.emit('integrity', decodeURIComponent(hash)) - } - res.body.on('error', err => stream.emit('error', err)) - res.body.pipe(stream) - }).catch(err => stream.emit('error', err)) + }, opts)) + .then(res => { + const hash = res.headers.get('x-local-cache-hash') + if (hash) { + stream.emit('integrity', decodeURIComponent(hash)) + } + res.body.on('error', err => stream.emit('error', err)) + res.body.pipe(stream) + return null + }) + .catch(err => stream.emit('error', err)) return stream } -function getTarballUrl (registry, manifest) { +function getTarballUrl (spec, registry, mani, opts) { + const reg = url.parse(registry) + const tarball = url.parse(mani._resolved) // https://github.com/npm/npm/pull/9471 // - // TL;DR: Some alternative registries host tarballs on http and packuments on - // https, and vice-versa. There's also a case where people who can't use SSL - // to access the npm registry, for example, might use - // `--registry=http://registry.npmjs.org/`. In this case, we need to rewrite - // `tarball` to match the protocol. + // TL;DR: Some alternative registries host tarballs on http and packuments + // on https, and vice-versa. There's also a case where people who can't use + // SSL to access the npm registry, for example, might use + // `--registry=http://registry.npmjs.org/`. In this case, we need to + // rewrite `tarball` to match the protocol. // - const reg = url.parse(registry) - const tarball = url.parse(manifest._resolved) if (reg.hostname === tarball.hostname && reg.protocol !== tarball.protocol) { tarball.protocol = reg.protocol // Ports might be same host different protocol! diff --git a/deps/npm/node_modules/pacote/lib/finalize-manifest.js b/deps/npm/node_modules/pacote/lib/finalize-manifest.js index 86b273b215..0f309ed6da 100644 --- a/deps/npm/node_modules/pacote/lib/finalize-manifest.js +++ b/deps/npm/node_modules/pacote/lib/finalize-manifest.js @@ -5,7 +5,7 @@ const BB = require('bluebird') const cacache = require('cacache') const cacheKey = require('./util/cache-key') const fetchFromManifest = require('./fetch').fromManifest -const finished = BB.promisify(require('mississippi').finished) +const finished = require('./util/finished') const minimatch = require('minimatch') const normalize = require('normalize-package-data') const optCheck = require('./util/opt-check') @@ -38,8 +38,8 @@ function finalizeManifest (pkg, spec, opts) { opts = optCheck(opts) const cachedManifest = (opts.cache && key && !opts.preferOnline && !opts.fullMetadata) - ? cacache.get.info(opts.cache, key, opts) - : BB.resolve(null) + ? cacache.get.info(opts.cache, key, opts) + : BB.resolve(null) return cachedManifest.then(cached => { if (cached && cached.metadata.manifest) { @@ -47,8 +47,8 @@ function finalizeManifest (pkg, spec, opts) { } else { return tarballedProps(pkg, spec, opts).then(props => { return pkg && pkg.name - ? new Manifest(pkg, props, opts.fullMetadata) - : new Manifest(props, null, opts.fullMetadata) + ? new Manifest(pkg, props, opts.fullMetadata) + : new Manifest(props, null, opts.fullMetadata) }).then(manifest => { const cacheKey = key || finalKey(manifest, spec) if (!opts.cache || !cacheKey) { @@ -98,7 +98,7 @@ function Manifest (pkg, fromTarball, fullMetadata) { // and if they don't, we need to extract and read the tarball ourselves. // These are details required by the installer. this._integrity = pkg._integrity || fromTarball._integrity || null - this._shasum = pkg._shasum || null + this._shasum = pkg._shasum || fromTarball._shasum || null this._shrinkwrap = pkg._shrinkwrap || fromTarball._shrinkwrap || null this.bin = pkg.bin || fromTarball.bin || null @@ -140,7 +140,9 @@ function tarballedProps (pkg, spec, opts) { pkg.directories && pkg.directories.bin )) - const needsHash = !pkg || (!pkg._integrity && pkg._integrity !== false) + const needsIntegrity = !pkg || (!pkg._integrity && pkg._integrity !== false) + const needsShasum = !pkg || (!pkg._shasum && pkg._shasum !== false) + const needsHash = needsIntegrity || needsShasum const needsManifest = !pkg || !pkg.name const needsExtract = needsShrinkwrap || needsBin || needsManifest if (!needsShrinkwrap && !needsBin && !needsHash && !needsManifest) { @@ -153,7 +155,7 @@ function tarballedProps (pkg, spec, opts) { needsShrinkwrap && jsonFromStream('npm-shrinkwrap.json', extracted), needsManifest && jsonFromStream('package.json', extracted), needsBin && getPaths(extracted), - needsHash && ssri.fromStream(tarStream), + needsHash && ssri.fromStream(tarStream, {algorithms: ['sha1', 'sha512']}), needsExtract && pipe(tarStream, extracted), (sr, mani, paths, hash) => { if (needsManifest && !mani) { @@ -169,8 +171,8 @@ function tarballedProps (pkg, spec, opts) { // to add to bin if (paths && paths.length) { const dirBin = mani - ? (mani && mani.directories && mani.directories.bin) - : (pkg && pkg.directories && pkg.directories.bin) + ? (mani && mani.directories && mani.directories.bin) + : (pkg && pkg.directories && pkg.directories.bin) if (dirBin) { extraProps.bin = {} paths.forEach(filePath => { @@ -188,7 +190,8 @@ function tarballedProps (pkg, spec, opts) { _resolved: (mani && mani._resolved) || (pkg && pkg._resolved) || spec.fetchSpec, - _integrity: hash && hash.toString() + _integrity: needsIntegrity && hash && hash.sha512 && hash.sha512[0].toString(), + _shasum: needsShasum && hash && hash.sha1 && hash.sha1[0].hexDigest() }) } ) @@ -205,7 +208,6 @@ function jsonFromStream (filename, dataStream) { entry.resume() } else { let data = '' - entry.on('data', d => { data += d }) entry.on('error', cb) finished(entry).then(() => { try { @@ -216,6 +218,7 @@ function jsonFromStream (filename, dataStream) { }, err => { cb(err) }) + entry.on('data', d => { data += d }) } }) }) diff --git a/deps/npm/node_modules/pacote/lib/util/finished.js b/deps/npm/node_modules/pacote/lib/util/finished.js new file mode 100644 index 0000000000..6dadc8b5b3 --- /dev/null +++ b/deps/npm/node_modules/pacote/lib/util/finished.js @@ -0,0 +1,17 @@ +'use strict' + +const BB = require('bluebird') + +module.exports = function (child, hasExitCode = false) { + return BB.fromNode(function (cb) { + child.on('error', cb) + child.on(hasExitCode ? 'close' : 'end', function (exitCode) { + if (exitCode === undefined || exitCode === 0) { + cb() + } else { + let err = new Error('exited with error code: ' + exitCode) + cb(err) + } + }) + }) +} diff --git a/deps/npm/node_modules/pacote/lib/util/git.js b/deps/npm/node_modules/pacote/lib/util/git.js index a6162ceeba..9196212278 100644 --- a/deps/npm/node_modules/pacote/lib/util/git.js +++ b/deps/npm/node_modules/pacote/lib/util/git.js @@ -6,14 +6,16 @@ const cp = require('child_process') const execFileAsync = BB.promisify(cp.execFile, { multiArgs: true }) -const finished = BB.promisify(require('mississippi').finished) +const finished = require('./finished') const LRU = require('lru-cache') const optCheck = require('./opt-check') const osenv = require('osenv') const path = require('path') const pinflight = require('promise-inflight') +const promiseRetry = require('promise-retry') const uniqueFilename = require('unique-filename') const which = BB.promisify(require('which')) +const semver = require('semver') const GOOD_ENV_VARS = new Set([ 'GIT_ASKPASS', @@ -25,6 +27,23 @@ const GOOD_ENV_VARS = new Set([ 'GIT_SSL_NO_VERIFY' ]) +const GIT_TRANSIENT_ERRORS = [ + 'remote error: Internal Server Error', + 'The remote end hung up unexpectedly', + 'Connection timed out', + 'Operation timed out', + 'Failed to connect to .* Timed out', + 'Connection reset by peer', + 'SSL_ERROR_SYSCALL', + 'The requested URL returned error: 503' +].join('|') + +const GIT_TRANSIENT_ERROR_RE = new RegExp(GIT_TRANSIENT_ERRORS) + +function shouldRetry (error) { + return GIT_TRANSIENT_ERROR_RE.test(error) +} + const GIT_ = 'GIT_' let GITENV function gitEnv () { @@ -51,16 +70,14 @@ try { module.exports.clone = fullClone function fullClone (repo, committish, target, opts) { opts = optCheck(opts) - const gitArgs = ['clone', '-q', repo, target] + const gitArgs = ['clone', '--mirror', '-q', repo, path.join(target, '.git')] if (process.platform === 'win32') { gitArgs.push('--config', 'core.longpaths=true') } - return execGit(gitArgs, { - cwd: path.dirname(target) - }, opts).then(() => { - return committish && execGit(['checkout', committish], { - cwd: target - }) + return execGit(gitArgs, {cwd: target}).then(() => { + return execGit(['init'], {cwd: target}) + }).then(() => { + return execGit(['checkout', committish || 'HEAD'], {cwd: target}) }).then(() => { return updateSubmodules(target, opts) }).then(() => headSha(target, opts)) @@ -113,57 +130,51 @@ function revs (repo, opts) { return pinflight(`ls-remote:${repo}`, () => { return spawnGit(['ls-remote', '-h', '-t', repo], { env: gitEnv() - }, opts).then(child => { - let stdout = '' - let stderr = '' - child.stdout.on('data', d => { stdout += d }) - child.stderr.on('data', d => { stderr += d }) - return finished(child).catch(err => { - err.message = `Error while executing:\n${GITPATH} ls-remote -h -t ${repo}\n\n${stderr}\n${err.message}` - throw err - }).then(() => { - return stdout.split('\n').reduce((revs, line) => { - const split = line.split(/\s+/, 2) - if (split.length < 2) { return revs } - const sha = split[0].trim() - const ref = split[1].trim().match(/(?:refs\/[^/]+\/)?(.*)/)[1] - if (!ref) { return revs } // ??? - if (ref.endsWith(CARET_BRACES)) { return revs } // refs/tags/x^{} crap - const type = refType(line) - const doc = {sha, ref, type} - - revs.refs[ref] = doc - // We can check out shallow clones on specific SHAs if we have a ref - if (revs.shas[sha]) { - revs.shas[sha].push(ref) - } else { - revs.shas[sha] = [ref] - } + }, opts).then((stdout) => { + return stdout.split('\n').reduce((revs, line) => { + const split = line.split(/\s+/, 2) + if (split.length < 2) { return revs } + const sha = split[0].trim() + const ref = split[1].trim().match(/(?:refs\/[^/]+\/)?(.*)/)[1] + if (!ref) { return revs } // ??? + if (ref.endsWith(CARET_BRACES)) { return revs } // refs/tags/x^{} crap + const type = refType(line) + const doc = {sha, ref, type} - if (type === 'tag') { - const match = ref.match(/v?(\d+\.\d+\.\d+)$/) - if (match) { - revs.versions[match[1]] = doc - } - } + revs.refs[ref] = doc + // We can check out shallow clones on specific SHAs if we have a ref + if (revs.shas[sha]) { + revs.shas[sha].push(ref) + } else { + revs.shas[sha] = [ref] + } - return revs - }, {versions: {}, 'dist-tags': {}, refs: {}, shas: {}}) - }).then(revs => { - if (revs.refs.HEAD) { - const HEAD = revs.refs.HEAD - Object.keys(revs.versions).forEach(v => { - if (v.sha === HEAD.sha) { - revs['dist-tags'].HEAD = v - if (!revs.refs.latest) { - revs['dist-tags'].latest = revs.refs.HEAD - } - } - }) + if (type === 'tag') { + const match = ref.match(/v?(\d+\.\d+\.\d+(?:[-+].+)?)$/) + if (match && semver.valid(match[1], true)) { + revs.versions[semver.clean(match[1], true)] = doc + } } - REVS.set(repo, revs) + return revs - }) + }, {versions: {}, 'dist-tags': {}, refs: {}, shas: {}}) + }, err => { + err.message = `Error while executing:\n${GITPATH} ls-remote -h -t ${repo}\n\n${err.stderr}\n${err.message}` + throw err + }).then(revs => { + if (revs.refs.HEAD) { + const HEAD = revs.refs.HEAD + Object.keys(revs.versions).forEach(v => { + if (v.sha === HEAD.sha) { + revs['dist-tags'].HEAD = v + if (!revs.refs.latest) { + revs['dist-tags'].latest = revs.refs.HEAD + } + } + }) + } + REVS.set(repo, revs) + return revs }) }) } @@ -172,7 +183,18 @@ module.exports._exec = execGit function execGit (gitArgs, gitOpts, opts) { opts = optCheck(opts) return checkGit().then(gitPath => { - return execFileAsync(gitPath, gitArgs, mkOpts(gitOpts, opts)) + return promiseRetry((retry, number) => { + if (number !== 1) { + opts.log.silly('pacote', 'Retrying git command: ' + gitArgs.join(' ') + ' attempt # ' + number) + } + return execFileAsync(gitPath, gitArgs, mkOpts(gitOpts, opts)).catch((err) => { + if (shouldRetry(err)) { + retry(err) + } else { + throw err + } + }) + }, opts.retry) }) } @@ -180,7 +202,28 @@ module.exports._spawn = spawnGit function spawnGit (gitArgs, gitOpts, opts) { opts = optCheck(opts) return checkGit().then(gitPath => { - return cp.spawn(gitPath, gitArgs, mkOpts(gitOpts, opts)) + return promiseRetry((retry, number) => { + if (number !== 1) { + opts.log.silly('pacote', 'Retrying git command: ' + gitArgs.join(' ') + ' attempt # ' + number) + } + const child = cp.spawn(gitPath, gitArgs, mkOpts(gitOpts, opts)) + + let stdout = '' + let stderr = '' + child.stdout.on('data', d => { stdout += d }) + child.stderr.on('data', d => { stderr += d }) + + return finished(child, true).catch(err => { + if (shouldRetry(stderr)) { + retry(err) + } else { + err.stderr = stderr + throw err + } + }).then(() => { + return stdout + }) + }, opts.retry) }) } @@ -213,10 +256,10 @@ const REFS_HEADS = 'refs/heads/' const HEAD = 'HEAD' function refType (ref) { return ref.indexOf(REFS_TAGS) !== -1 - ? 'tag' - : ref.indexOf(REFS_HEADS) !== -1 - ? 'branch' - : ref.endsWith(HEAD) - ? 'head' - : 'other' + ? 'tag' + : ref.indexOf(REFS_HEADS) !== -1 + ? 'branch' + : ref.endsWith(HEAD) + ? 'head' + : 'other' } diff --git a/deps/npm/node_modules/pacote/lib/util/gunzip-maybe.js b/deps/npm/node_modules/pacote/lib/util/gunzip-maybe.js deleted file mode 100644 index 055de2921a..0000000000 --- a/deps/npm/node_modules/pacote/lib/util/gunzip-maybe.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict' - -const duplex = require('mississippi').duplex -const through = require('mississippi').through -const zlib = require('zlib') - -function hasGzipHeader (c) { - return c[0] === 0x1F && c[1] === 0x8B && c[2] === 0x08 -} - -module.exports = gunzip -function gunzip () { - const stream = duplex() - const peeker = through((chunk, enc, cb) => { - const newStream = hasGzipHeader(chunk) - ? zlib.createGunzip() - : through() - stream.setReadable(newStream) - stream.setWritable(newStream) - stream.write(chunk) - }) - stream.setWritable(peeker) - return stream -} diff --git a/deps/npm/node_modules/pacote/lib/util/opt-check.js b/deps/npm/node_modules/pacote/lib/util/opt-check.js index 711f46c91a..d13a69e4dc 100644 --- a/deps/npm/node_modules/pacote/lib/util/opt-check.js +++ b/deps/npm/node_modules/pacote/lib/util/opt-check.js @@ -25,6 +25,7 @@ function PacoteOptions (opts) { this.proxy = opts.proxy this.noProxy = opts.noProxy this.registry = opts.registry || 'https://registry.npmjs.org' + this.resolved = opts.resolved this.retry = opts.retry // for npm-registry-client this.scope = opts.scope this.userAgent = opts.userAgent || `${pkg.name}@${pkg.version}/node@${process.version}+${process.arch} (${process.platform})` @@ -44,8 +45,8 @@ function PacoteOptions (opts) { this.fullMetadata = opts.fullMetadata this.alwaysAuth = opts.alwaysAuth this.includeDeprecated = opts.includeDeprecated == null - ? true - : opts.includeDeprecated + ? true + : opts.includeDeprecated this.dirPacker = opts.dirPacker || null diff --git a/deps/npm/node_modules/pacote/lib/util/pack-dir.js b/deps/npm/node_modules/pacote/lib/util/pack-dir.js index 7625f4faf8..62776692e1 100644 --- a/deps/npm/node_modules/pacote/lib/util/pack-dir.js +++ b/deps/npm/node_modules/pacote/lib/util/pack-dir.js @@ -14,8 +14,8 @@ function packDir (manifest, label, dir, target, opts) { opts = optCheck(opts) const packer = opts.dirPacker - ? BB.resolve(opts.dirPacker(manifest, dir)) - : mkPacker(dir) + ? BB.resolve(opts.dirPacker(manifest, dir)) + : mkPacker(dir) if (!opts.cache) { return packer.then(packer => pipe(packer, target)) diff --git a/deps/npm/node_modules/pacote/lib/with-tarball-stream.js b/deps/npm/node_modules/pacote/lib/with-tarball-stream.js new file mode 100644 index 0000000000..653a4a688a --- /dev/null +++ b/deps/npm/node_modules/pacote/lib/with-tarball-stream.js @@ -0,0 +1,135 @@ +'use strict' + +const BB = require('bluebird') + +const cacache = require('cacache') +const fetch = require('./fetch.js') +const fs = require('fs') +const npa = require('npm-package-arg') +const optCheck = require('./util/opt-check.js') +const path = require('path') +const ssri = require('ssri') +const retry = require('promise-retry') + +const statAsync = BB.promisify(fs.stat) + +const RETRIABLE_ERRORS = new Set(['ENOENT', 'EINTEGRITY', 'Z_DATA_ERROR']) + +module.exports = withTarballStream +function withTarballStream (spec, opts, streamHandler) { + opts = optCheck(opts) + spec = npa(spec, opts.where) + + // First, we check for a file: resolved shortcut + const tryFile = ( + !opts.preferOnline && + opts.integrity && + opts.resolved && + opts.resolved.startsWith('file:') + ) + ? BB.try(() => { + // NOTE - this is a special shortcut! Packages installed as files do not + // have a `resolved` field -- this specific case only occurs when you have, + // say, a git dependency or a registry dependency that you've packaged into + // a local file, and put that file: spec in the `resolved` field. + opts.log.silly('pacote', `trying ${spec} by local file: ${opts.resolved}`) + const file = path.resolve(opts.where || '.', opts.resolved.substr(5)) + return statAsync(file) + .then(() => { + const verifier = ssri.integrityStream({integrity: opts.integrity}) + const stream = fs.createReadStream(file) + .on('error', err => verifier.emit('error', err)) + .pipe(verifier) + return streamHandler(stream) + }) + .catch(err => { + if (err.code === 'EINTEGRITY') { + opts.log.warn('pacote', `EINTEGRITY while extracting ${spec} from ${file}.You will have to recreate the file.`) + opts.log.verbose('pacote', `EINTEGRITY for ${spec}: ${err.message}`) + } + throw err + }) + }) + : BB.reject(Object.assign(new Error('no file!'), {code: 'ENOENT'})) + + const tryDigest = tryFile + .catch(err => { + if ( + opts.preferOnline || + !opts.cache || + !opts.integrity || + !RETRIABLE_ERRORS.has(err.code) + ) { + throw err + } else { + opts.log.silly('tarball', `trying ${spec} by hash: ${opts.integrity}`) + const stream = cacache.get.stream.byDigest( + opts.cache, opts.integrity, opts + ) + stream.once('error', err => stream.on('newListener', (ev, l) => { + if (ev === 'error') { l(err) } + })) + return streamHandler(stream) + .catch(err => { + if (err.code === 'EINTEGRITY' || err.code === 'Z_DATA_ERROR') { + opts.log.warn('tarball', `cached data for ${spec} (${opts.integrity}) seems to be corrupted. Refreshing cache.`) + return cleanUpCached(opts.cache, opts.integrity, opts) + .then(() => { throw err }) + } else { + throw err + } + }) + } + }) + + const trySpec = tryDigest + .catch(err => { + if (!RETRIABLE_ERRORS.has(err.code)) { + // If it's not one of our retriable errors, bail out and give up. + throw err + } else { + opts.log.silly( + 'tarball', + `no local data for ${spec}. Extracting by manifest.` + ) + return BB.resolve(retry((tryAgain, attemptNum) => { + const tardata = fetch.tarball(spec, opts) + if (!opts.resolved) { + tardata.on('manifest', m => { + opts.resolved = m._resolved + }) + tardata.on('integrity', i => { + opts.integrity = i + }) + } + return BB.try(() => streamHandler(tardata)) + .catch(err => { + // Retry once if we have a cache, to clear up any weird conditions. + // Don't retry network errors, though -- make-fetch-happen has already + // taken care of making sure we're all set on that front. + if (opts.cache && err.code && !err.code.match(/^E\d{3}$/)) { + if (err.code === 'EINTEGRITY' || err.code === 'Z_DATA_ERROR') { + opts.log.warn('tarball', `tarball data for ${spec} (${opts.integrity}) seems to be corrupted. Trying one more time.`) + } + return cleanUpCached(opts.cache, err.sri, opts) + .then(() => tryAgain(err)) + } else { + throw err + } + }) + }, {retries: 1})) + } + }) + + return trySpec + .catch(err => { + if (err.code === 'EINTEGRITY') { + err.message = `Verification failed while extracting ${spec}:\n${err.message}` + } + throw err + }) +} + +function cleanUpCached (cachePath, integrity, opts) { + return cacache.rm.content(cachePath, integrity, opts) +} |