Comparing version 0.1.1 to 1.0.0
@@ -1,33 +0,47 @@ | ||
var cache = require('./lib/cache') | ||
var extractStream = require('./lib/util/extract-stream') | ||
var pipe = require('mississippi').pipe | ||
var optCheck = require('./lib/util/opt-check') | ||
var rps = require('realize-package-specifier') | ||
'use strict' | ||
const BB = require('bluebird') | ||
const cache = require('./lib/cache') | ||
const extractStream = require('./lib/extract-stream') | ||
const pipe = BB.promisify(require('mississippi').pipe) | ||
const optCheck = require('./lib/util/opt-check') | ||
const rps = BB.promisify(require('realize-package-specifier')) | ||
module.exports = extract | ||
function extract (spec, dest, opts, cb) { | ||
if (!cb) { | ||
cb = opts | ||
opts = null | ||
} | ||
function extract (spec, dest, opts) { | ||
opts = optCheck(opts) | ||
var xtractor = extractStream(dest, opts) | ||
var caStream = cache.get.stream.byDigest(opts.cache, opts.digest, opts) | ||
if (opts.digest) { | ||
opts.log.silly('extract', 'trying from digest:', opts.digest) | ||
opts.log.silly('extract', 'trying ', spec, ' digest:', opts.digest) | ||
return extractByDigest( | ||
dest, opts | ||
).catch(err => { | ||
if (err && err.code === 'ENOENT') { | ||
opts.log.silly('extract', 'digest for', spec, 'not present. Using manifest.') | ||
return extractByManifest(spec, dest, opts) | ||
} else { | ||
throw err | ||
} | ||
}) | ||
} else { | ||
opts.log.silly('extract', 'no digest provided for ', spec, '- extracting by manifest') | ||
return extractByManifest(spec, dest, opts) | ||
} | ||
caStream.on('error', function (err) { | ||
if (err && err.code !== 'ENOENT') { return cb(err) } | ||
rps(spec, function (err, res) { | ||
if (err) { return cb(err) } | ||
var tarball = require('./lib/handlers/' + res.type + '/tarball') | ||
pipe(tarball(res, opts), xtractor, function (err) { | ||
opts.log.silly('extract', 'extraction finished for', spec) | ||
cb(err) | ||
}) | ||
}) | ||
}).on('end', function () { | ||
opts.log.silly('extract', spec, 'extracted by digest') | ||
cb(null) | ||
}).pipe(xtractor) | ||
} | ||
function extractByDigest (dest, opts) { | ||
const xtractor = extractStream(dest, opts) | ||
const cached = cache.get.stream.byDigest(opts.cache, opts.digest, opts) | ||
return pipe(cached, xtractor) | ||
} | ||
function extractByManifest (spec, dest, opts) { | ||
const res = typeof spec === 'string' | ||
? rps(spec, opts.where) | ||
: BB.resolve(spec) | ||
const xtractor = extractStream(dest, opts) | ||
return res.then(res => { | ||
const tarball = require('./lib/handlers/' + res.type + '/tarball') | ||
return pipe(tarball(res, opts), xtractor) | ||
}) | ||
} |
@@ -0,4 +1,7 @@ | ||
'use strict' | ||
module.exports = { | ||
extract: require('./extract'), | ||
manifest: require('./manifest') | ||
manifest: require('./manifest'), | ||
prefetch: require('./prefetch') | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = cacheKey | ||
@@ -2,0 +4,0 @@ function cacheKey (type, identifier) { |
@@ -0,159 +1,7 @@ | ||
'use strict' | ||
var cacache = require('cacache') | ||
var cacheKey = require('./cache-key') | ||
var finished = require('mississippi').finished | ||
var through = require('mississippi').through | ||
var pipe = require('mississippi').pipe | ||
var pipeline = require('mississippi').pipeline | ||
var HASH = 'sha1' | ||
module.exports = cacache | ||
module.exports.key = cacheKey | ||
var MEMOIZED = {} | ||
module.exports._clearMemoized = clearMemoized | ||
function clearMemoized () { | ||
var old = MEMOIZED | ||
MEMOIZED = {} | ||
return old | ||
} | ||
module.exports.memoize = memoize | ||
function memoize (key, data) { | ||
MEMOIZED[key] = data | ||
} | ||
module.exports.readMemoized = readMemoized | ||
function readMemoized (key) { | ||
return MEMOIZED[key] | ||
} | ||
module.exports.put = putData | ||
function putData (cache, key, data, opts, cb) { | ||
if (!cb) { | ||
cb = opts | ||
opts = null | ||
} | ||
opts = opts || {} | ||
var put = putStream(cache, key, opts) | ||
var dummy = through() | ||
pipe(dummy, put, function (err) { | ||
cb(err) | ||
}) | ||
dummy.write(data) | ||
dummy.end() | ||
} | ||
module.exports.put.stream = putStream | ||
function putStream (cache, key, opts) { | ||
// This is the most ridiculous thing, but cacache | ||
// needs an API overhaul, and I need to think longer | ||
// about whether to emit the index entry... | ||
var dest = cacache.put.stream(cache, key, opts) | ||
var lol = through() | ||
var piped = pipeline(lol, dest) | ||
var meta | ||
dest.on('metadata', function (m) { | ||
meta = m.metadata | ||
piped.emit('metadata', m.metadata) | ||
}) | ||
dest.on('digest', function (d) { | ||
piped.emit('digest', d) | ||
}) | ||
dest.on('end', function () { | ||
opts.log.silly('cache.put', 'finished writing cache data for', key) | ||
}) | ||
if (opts.memoize) { | ||
opts.log.silly('cache.put', 'memoization of', key, 'requested') | ||
var data = '' | ||
lol.on('data', function (d) { | ||
data += d | ||
}) | ||
finished(piped, function (err) { | ||
if (err) { return } | ||
opts.log.silly('cache.put', key, 'memoized') | ||
MEMOIZED[cache + ':' + key] = { | ||
data: data, | ||
meta: meta || null | ||
} | ||
}) | ||
} | ||
return piped | ||
} | ||
module.exports.get = getData | ||
function getData (cache, key, opts, cb) { | ||
if (!cb) { | ||
cb = opts | ||
opts = null | ||
} | ||
opts = opts || {} | ||
var meta | ||
var data = '' | ||
var stream = getStream( | ||
false, cache, key, opts | ||
).on('metadata', function (m) { | ||
meta = m | ||
}).on('data', function (d) { | ||
data += d | ||
}) | ||
finished(stream, function (err) { | ||
cb(err, data, meta) | ||
}) | ||
} | ||
module.exports.get.stream = function (cache, key, opts) { | ||
return getStream(false, cache, key, opts) | ||
} | ||
module.exports.get.stream.byDigest = function (cache, digest, opts) { | ||
return getStream(true, cache, digest, opts) | ||
} | ||
function getStream (byDigest, cache, key, opts) { | ||
opts = opts || {} | ||
var stream | ||
if (!cache || !key) { | ||
stream = through() | ||
var err = new Error('no cache or key') | ||
err.code = 'ENOENT' | ||
setImmediate(function () { stream.emit('error', err) }) | ||
return stream | ||
} | ||
var memoed = MEMOIZED[cache + ':' + key] | ||
if (memoed) { | ||
opts.log && opts.log.silly('cache.get', key, 'already memoized.') | ||
stream = through() | ||
stream.on('newListener', function (ev, cb) { | ||
ev === 'metadata' && cb(memoed.meta) | ||
}) | ||
stream.write(memoed.data) | ||
stream.end() | ||
return stream | ||
} else { | ||
var dest = through() | ||
var meta | ||
var getter = byDigest ? cacache.get.stream.byDigest : cacache.get.stream | ||
var src = getter(cache, key, { | ||
hashAlgorithm: HASH | ||
}).on('metadata', function (m) { | ||
meta = m.metadata | ||
piped.emit('metadata', m.metadata) | ||
}).on('digest', function (d) { | ||
piped.emit('digest', d) | ||
}) | ||
var piped = pipeline(src, dest) | ||
if (opts.memoize) { | ||
var data = '' | ||
piped.on('data', function (d) { | ||
data += d | ||
}) | ||
finished(piped, function (err) { | ||
if (err) { return } | ||
MEMOIZED[cache + ':' + key] = { | ||
data: data, | ||
meta: meta || null | ||
} | ||
}) | ||
} | ||
return piped | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = require('../../registry/manifest') |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = require('../../registry/tarball') |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = require('../../registry/manifest') |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = require('../../registry/tarball') |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = require('../../registry/manifest') |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = require('../../registry/tarball') |
@@ -1,2 +0,3 @@ | ||
var extractShrinkwrap = require('../util/extract-shrinkwrap') | ||
'use strict' | ||
var optCheck = require('../util/opt-check') | ||
@@ -7,6 +8,5 @@ var pickManifest = require('./pick-manifest') | ||
var request = require('./request') | ||
var tarball = require('./tarball') | ||
module.exports = manifest | ||
function manifest (spec, opts, cb) { | ||
function manifest (spec, opts) { | ||
opts = optCheck(opts) | ||
@@ -22,18 +22,32 @@ opts.memoize = true | ||
) | ||
request(uri, registry, opts, function (err, metadata) { | ||
if (err) { return cb(err) } | ||
return request(uri, registry, opts).then(metadata => { | ||
opts.log.silly('registry.manifest', 'got metadata for', spec.name) | ||
pickManifest(metadata, spec, { | ||
return pickManifest(metadata, spec, { | ||
engineFilter: opts.engineFilter, | ||
defaultTag: opts.defaultTag | ||
}, function (err, manifest) { | ||
if (err) { return cb(err) } | ||
opts.log.silly( | ||
'registry.manifest', | ||
spec.name + '@' + spec.spec, | ||
'resolved to', | ||
manifest.name + '@' + manifest.version | ||
) | ||
ensureShrinkwrap(manifest, registry, opts, cb) | ||
}) | ||
}).then(manifest => { | ||
// Done here instead of ./finalize-manifest because these fields | ||
// have to be filled in differently depending on type. | ||
manifest._shasum = ( | ||
manifest.dist && manifest.dist.shasum | ||
) || manifest._shasum | ||
manifest._resolved = ( | ||
manifest.dist && manifest.dist.tarball | ||
) || url.resolve( | ||
registry, | ||
'/' + manifest.name + | ||
'/-/' + manifest.name + | ||
'-' + manifest.version + | ||
'.tgz' | ||
) | ||
return manifest | ||
}).catch({code: 'ETARGET'}, err => { | ||
if (!opts.cache || opts.maxAge < 0 || opts.offline) { | ||
throw err | ||
} else { | ||
opts.log.silly('registry.manifest', 'version missing from current metadata, forcing network check') | ||
opts.maxAge = -1 | ||
return manifest(spec, opts) | ||
} | ||
}) | ||
@@ -48,29 +62,1 @@ } | ||
} | ||
function ensureShrinkwrap (manifest, registry, opts, cb) { | ||
if (manifest._hasShrinkwrap === false || manifest._shrinkwrap || !manifest.dist) { | ||
opts.log.silly('registry.manifest', 'shrinkwrap extraction not needed') | ||
cb(null, manifest) | ||
} else { | ||
opts.log.silly('registry.manifest', 'extracting shrinkwrap') | ||
opts.memoize = false | ||
var shrinkwrap | ||
var tarstream = tarball.fromManifest(manifest, registry, opts) | ||
extractShrinkwrap(tarstream, opts, function (err, sr) { | ||
if (err) { return cb(err) } | ||
shrinkwrap = sr | ||
}) | ||
tarstream.on('data', function () {}) | ||
tarstream.on('error', cb) | ||
tarstream.on('end', function () { | ||
manifest._hasShrinkwrap = !!shrinkwrap | ||
manifest._shrinkwrap = shrinkwrap | ||
if (shrinkwrap) { | ||
opts.log.silly('registry.manifest', 'shrinkwrap found') | ||
} else { | ||
opts.log.silly('registry.manifest', 'no shrinkwrap') | ||
} | ||
cb(null, manifest) | ||
}) | ||
} | ||
} |
@@ -0,5 +1,9 @@ | ||
'use strict' | ||
var BB = require('bluebird') | ||
var semver = require('semver') | ||
module.exports = pickManifest | ||
function pickManifest (metadata, spec, opts, cb) { | ||
function pickManifest (metadata, spec, opts) { | ||
var distTags = metadata['dist-tags'] || {} | ||
@@ -9,57 +13,60 @@ var versions = Object.keys(metadata.versions || {}) | ||
var err | ||
return BB.fromNode(cb => { | ||
if (!versions.length) { | ||
err = new Error(`No valid versions available for ${metadata.name}`) | ||
err.code = 'ENOVERSIONS' | ||
err.name = metadata.name | ||
err.spec = spec | ||
return cb(err) | ||
} | ||
if (!versions.length) { | ||
err = new Error('Package has no valid versions.') | ||
err.code = 'ENOVERSIONS' | ||
err.name = metadata.name | ||
err.spec = spec | ||
return cb(err) | ||
} | ||
var target | ||
var target | ||
if (spec.type === 'tag') { | ||
target = distTags[spec.spec] | ||
} else if (spec.type === 'version') { | ||
target = spec.spec | ||
} else if (spec.type !== 'range') { | ||
return cb(new Error('Only tag, version, and range are supported')) | ||
} | ||
if (spec.type === 'tag') { | ||
target = distTags[spec.spec] | ||
} else if (spec.type === 'version') { | ||
target = spec.spec | ||
} else if (spec.type !== 'range') { | ||
return cb(new Error('Only tag, version, and range are supported')) | ||
} | ||
var tagVersion = distTags[opts.defaultTag || 'latest'] | ||
var tagVersion = distTags[opts.defaultTag || 'latest'] | ||
if (!target && | ||
if ( | ||
!target && | ||
tagVersion && | ||
metadata.versions[tagVersion] && | ||
semver.satisfies(tagVersion, spec.spec, true)) { | ||
target = tagVersion | ||
} | ||
semver.satisfies(tagVersion, spec.spec, true) | ||
) { | ||
target = tagVersion | ||
} | ||
if (!target) { | ||
target = semver.maxSatisfying(versions, spec.spec, true) | ||
} | ||
if (!target) { | ||
target = semver.maxSatisfying(versions, spec.spec, true) | ||
} | ||
if (!target && spec.spec === '*') { | ||
// npm hard-codes `latest` here, but it's likely intended | ||
// to be `defaultTag`. | ||
// | ||
// This specific corner is meant for the case where | ||
// someone is using `*` as a selector, but all versions | ||
// are pre-releases, which don't match ranges at all. | ||
target = tagVersion | ||
} | ||
if (!target && spec.spec === '*') { | ||
// npm hard-codes `latest` here, but it's likely intended | ||
// to be `defaultTag`. | ||
// | ||
// This specific corner is meant for the case where | ||
// someone is using `*` as a selector, but all versions | ||
// are pre-releases, which don't match ranges at all. | ||
target = tagVersion | ||
} | ||
var manifest = target && metadata.versions[target] | ||
if (!manifest) { | ||
err = new Error('No matching versions') | ||
err.code = 'ENOENT' | ||
err.name = metadata.name | ||
err.spec = spec | ||
err.versions = versions | ||
err.distTags = distTags | ||
err.defaultTag = opts.defaultTag | ||
return cb(err) | ||
} else { | ||
return cb(null, manifest) | ||
} | ||
var manifest = target && metadata.versions[target] | ||
if (!manifest) { | ||
err = new Error(`No matching version found for ${spec.name}@${spec.spec}`) | ||
err.code = 'ETARGET' | ||
err.name = metadata.name | ||
err.spec = spec | ||
err.versions = versions | ||
err.distTags = distTags | ||
err.defaultTag = opts.defaultTag | ||
return cb(err) | ||
} else { | ||
return cb(null, manifest) | ||
} | ||
}) | ||
} |
@@ -0,8 +1,10 @@ | ||
'use strict' | ||
module.exports = pickRegistry | ||
function pickRegistry (spec, opts) { | ||
var registry = spec.scope && opts[spec.scope + ':registry'] | ||
let registry = spec.scope && opts.scopeTargets[spec.scope] | ||
if (!registry && opts.scope) { | ||
var prefix = opts.scope[0] === '@' ? '' : '@' | ||
registry = opts[prefix + opts.scope + ':registry'] | ||
const prefix = opts.scope[0] === '@' ? '' : '@' | ||
registry = opts.scopeTargets[prefix + opts.scope] | ||
} | ||
@@ -9,0 +11,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
var url = require('url') | ||
@@ -2,0 +4,0 @@ |
@@ -0,4 +1,8 @@ | ||
'use strict' | ||
var BB = require('bluebird') | ||
var cache = require('../cache') | ||
var finished = require('mississippi').finished | ||
var inflight = require('inflight') | ||
var pinflight = require('promise-inflight') | ||
var gunzip = require('../util/gunzip-maybe') | ||
@@ -11,30 +15,20 @@ var pipe = require('mississippi').pipe | ||
module.exports = get | ||
function get (uri, registry, opts, cb) { | ||
function get (uri, registry, opts) { | ||
var key = cache.key('registry-request', uri) | ||
var memoed = cache.readMemoized(key) | ||
if (memoed) { | ||
opts.log.silly('registry.get', key, 'already memoized!') | ||
return cb(null, memoed.data, memoed.raw) | ||
} | ||
cb = inflight(key, cb) | ||
if (!cb) { | ||
opts.log.silly('registry.get', key, 'is already inflight') | ||
return | ||
} | ||
var raw = '' | ||
var stream = getStream(uri, registry, opts) | ||
stream.on('data', function (d) { raw += d }) | ||
stream.on('reset', function () { raw = '' }) | ||
finished(stream, function (err) { | ||
if (err) { return cb(err) } | ||
try { | ||
var parsed = JSON.parse(raw) | ||
} catch (e) { | ||
return cb(e) | ||
} | ||
cache.memoize(key, { | ||
data: parsed, | ||
raw: raw | ||
return pinflight(key, () => { | ||
return BB.fromNode(cb => { | ||
var raw = '' | ||
var stream = getStream(uri, registry, opts) | ||
stream.on('data', function (d) { raw += d }) | ||
stream.on('reset', function () { raw = '' }) | ||
finished(stream, function (err) { | ||
if (err) { return cb(err) } | ||
try { | ||
var parsed = JSON.parse(raw) | ||
} catch (e) { | ||
return cb(e) | ||
} | ||
return cb(null, parsed) | ||
}) | ||
}) | ||
return cb(null, parsed, raw) | ||
}) | ||
@@ -70,2 +64,5 @@ } | ||
var cs = cache.get.stream(opts.cache, key, opts) | ||
cs.once('data', function () { | ||
opts.log.silly('registry.get', 'got data for', key, 'from cache.') | ||
}) | ||
cs.on('metadata', function (meta) { | ||
@@ -77,3 +74,2 @@ if (isStale(meta, opts)) { | ||
) | ||
cs.pause() | ||
switchToRegistry(null, cs, meta) | ||
@@ -85,2 +81,3 @@ } else { | ||
) | ||
cs.pipe(stream) | ||
} | ||
@@ -96,3 +93,2 @@ }) | ||
}) | ||
cs.pipe(stream) | ||
stream.on('error', function (e) { cs.emit('error', e) }) | ||
@@ -110,4 +106,4 @@ stream.on('end', function () { cs.end() }) | ||
if (fallback) { | ||
opts.log.silly('registry.get', 'resuming stale cache stream for', key) | ||
fallback.resume() | ||
opts.log.silly('registry.get', 'reading stale cache stream for', key) | ||
fallback.pipe(stream) | ||
} else { | ||
@@ -122,2 +118,3 @@ if (!err) { | ||
if (fallback) { | ||
fallback.pause() | ||
stream.emit('reset') | ||
@@ -131,3 +128,3 @@ } | ||
opts.log.silly('registry.get', 'Got a 304. Switching back to cache.') | ||
fallback.resume() | ||
fallback.pipe(stream) | ||
}).once('error', function (err) { | ||
@@ -139,6 +136,5 @@ opts.log.silly('registry.get', 'request error: ', err) | ||
opts.log.silly('registry.get', 'using stale', key, 'from cache.') | ||
fallback.resume() | ||
stream.emit('reset') | ||
fallback.pipe(stream) | ||
} | ||
}).on('end', function () { | ||
stream.end() | ||
}).pipe(stream) | ||
@@ -155,3 +151,3 @@ } | ||
(meta.cacheControl && meta.cacheControl.toLowerCase() === 'immutable') || | ||
opts.preferOffline || | ||
(opts.preferOffline && opts.maxAge > 0) || | ||
opts.offline) { | ||
@@ -200,6 +196,7 @@ opts.log.silly('registry.get', 'skipping staleness check for') | ||
to(function (chunk, enc, cb) { | ||
cacheStream.write(chunk, enc, function () { | ||
stream.write(chunk, enc, cb) | ||
}) | ||
cacheStream.write(chunk, enc) | ||
stream.write(chunk, enc, cb) | ||
}, function (cb) { | ||
opts.log.silly('registry.get', 'request for', key, 'done.') | ||
cacheStream.on('error', cb) | ||
cacheStream.end(function () { | ||
@@ -210,3 +207,6 @@ opts.log.silly('registry.get', 'wrapped up cacheStream') | ||
}), | ||
function () {} | ||
function (err) { | ||
if (err) { return stream.emit('error', err) } | ||
opts.log.silly('registry.get', 'pipeline for', key, 'done') | ||
} | ||
) | ||
@@ -231,3 +231,4 @@ } else { | ||
log: opts.log, | ||
retry: opts.retry | ||
retry: opts.retry, | ||
maxSockets: opts.maxSockets | ||
} | ||
@@ -234,0 +235,0 @@ CLIENT = new RegistryClient(CLIENT_OPTS) |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
var manifest = require('./manifest') | ||
@@ -11,3 +13,2 @@ var optCheck = require('../util/opt-check') | ||
opts = optCheck(opts) | ||
var registry = pickRegistry(spec, opts) | ||
opts.log.verbose( | ||
@@ -18,4 +19,3 @@ 'registry.tarball', | ||
var stream = through() | ||
manifest(spec, opts, function (err, manifest) { | ||
if (err) { return stream.emit('error', err) } | ||
manifest(spec, opts).then(manifest => { | ||
opts.log.silly( | ||
@@ -26,6 +26,6 @@ 'registry.tarball', | ||
pipe( | ||
fromManifest(manifest, registry), | ||
fromManifest(manifest, spec, opts), | ||
stream | ||
) | ||
}) | ||
}, err => stream.emit('error', err)) | ||
return stream | ||
@@ -35,7 +35,8 @@ } | ||
module.exports.fromManifest = fromManifest | ||
function fromManifest (manifest, registry, opts) { | ||
function fromManifest (manifest, spec, opts) { | ||
opts = optCheck(opts) | ||
var uri = manifest.dist && manifest.dist.tarball | ||
opts.digest = manifest.dist && manifest.dist.shasum | ||
var registry = pickRegistry(spec, opts) | ||
var uri = manifest._resolved | ||
opts.digest = manifest._shasum | ||
return request.stream(uri, registry, opts) | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
var duplex = require('mississippi').duplex | ||
@@ -2,0 +4,0 @@ var through = require('mississippi').through |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
var silentlog = require('./silentlog') | ||
@@ -7,2 +9,3 @@ | ||
this.auth = opts.auth | ||
this.scopeTargets = opts.scopeTargets || {} | ||
this.defaultTag = opts.defaultTag || 'latest' | ||
@@ -17,2 +20,3 @@ this.cache = opts.cache | ||
this.maxAge = typeof opts.maxAge === 'undefined' ? 1000 : opts.maxAge | ||
this.maxSockets = opts.maxSockets || 10 | ||
this.memoize = !!opts.memoize | ||
@@ -25,3 +29,6 @@ this.offline = opts.offline | ||
this.scope = opts.scope | ||
this.where = opts.where | ||
this.gitPacker = opts.gitPacker || null | ||
this.uid = opts.uid | ||
@@ -33,8 +40,2 @@ this.gid = opts.gid | ||
this.umask = opts.umask | ||
for (var k in opts) { | ||
if (k.match(/:registry$/i)) { | ||
this[k] = opts[k] | ||
} | ||
} | ||
} | ||
@@ -41,0 +42,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
var noop = Function.prototype | ||
@@ -2,0 +4,0 @@ module.exports = { |
@@ -1,21 +0,31 @@ | ||
var optCheck = require('./lib/util/opt-check') | ||
var rps = require('realize-package-specifier') | ||
'use strict' | ||
var handlers = {} | ||
const BB = require('bluebird') | ||
const finalizeManifest = require('./lib/finalize-manifest') | ||
const optCheck = require('./lib/util/opt-check') | ||
const rps = BB.promisify(require('realize-package-specifier')) | ||
let handlers = {} | ||
module.exports = manifest | ||
function manifest (spec, opts, cb) { | ||
if (!cb) { | ||
cb = opts | ||
opts = null | ||
} | ||
function manifest (spec, opts) { | ||
opts = optCheck(opts) | ||
rps(spec, function (err, res) { | ||
if (err) { return cb(err) } | ||
var fetcher = handlers[res.type] || (handlers[res.type] = require('./lib/handlers/' + res.type + '/manifest')) | ||
fetcher(res, opts, function (err, mani) { | ||
cb(err, mani) | ||
const res = typeof spec === 'string' | ||
? rps(spec, opts.where) | ||
: BB.resolve(spec) | ||
return res.then(res => { | ||
const fetcher = ( | ||
handlers[res.type] || | ||
( | ||
handlers[res.type] = | ||
require('./lib/handlers/' + res.type + '/manifest') | ||
) | ||
) | ||
return fetcher(res, opts).then(manifest => { | ||
return finalizeManifest(manifest, res, opts) | ||
}) | ||
}) | ||
} |
{ | ||
"name": "pacote", | ||
"version": "0.1.1", | ||
"version": "1.0.0", | ||
"description": "JavaScript package downloader", | ||
@@ -11,6 +11,10 @@ "main": "index.js", | ||
"scripts": { | ||
"preversion": "npm t", | ||
"postversion": "npm publish && git push --follow-tags", | ||
"prerelease": "npm t", | ||
"release": "standard-version -s", | ||
"postrelease": "npm publish && git push --follow-tags", | ||
"pretest": "standard lib test *.js", | ||
"test": "nyc -- tap test/*.js" | ||
"test": "nyc --all -- tap -J test/*.js", | ||
"test-docker": "docker run -it --rm --name pacotest -v \"$PWD\":/tmp -w /tmp node:latest npm test", | ||
"update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'", | ||
"update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'" | ||
}, | ||
@@ -23,26 +27,57 @@ "repository": "https://github.com/zkat/pacote", | ||
], | ||
"author": "Kat Marchán <kzm@sykosomatic.org>", | ||
"author": { | ||
"name": "Kat Marchán", | ||
"email": "kzm@sykosomatic.org", | ||
"twitter": "maybekatz" | ||
}, | ||
"contributors": [ | ||
{ | ||
"name": "Charlotte Spencer", | ||
"email": "charlottelaspencer@gmail.com", | ||
"twitter": "charlotteis" | ||
}, | ||
{ | ||
"name": "Rebecca Turner", | ||
"email": "me@re-becca.org" | ||
} | ||
], | ||
"license": "CC0-1.0", | ||
"dependencies": { | ||
"cacache": "^5.0.0", | ||
"bluebird": "^3.5.0", | ||
"cacache": "^6.2.0", | ||
"checksum-stream": "^1.0.2", | ||
"dezalgo": "^1.0.3", | ||
"glob": "^7.1.1", | ||
"inflight": "^1.0.6", | ||
"lru-cache": "^4.0.2", | ||
"minimatch": "^3.0.3", | ||
"mississippi": "^1.2.0", | ||
"npm-registry-client": "^7.4.1", | ||
"normalize-git-url": "^3.0.2", | ||
"normalize-package-data": "^2.3.6", | ||
"npm-registry-client": "^7.4.6", | ||
"osenv": "^0.1.4", | ||
"promise-inflight": "^1.0.1", | ||
"realize-package-specifier": "^3.0.3", | ||
"request": "^2.79.0", | ||
"request": "^2.81.0", | ||
"semver": "^5.3.0", | ||
"slide": "^1.1.6", | ||
"tar-fs": "^1.15.0", | ||
"tar-stream": "^1.5.2" | ||
"tar-fs": "^1.15.1", | ||
"tar-stream": "^1.5.2", | ||
"unique-filename": "^1.1.0", | ||
"which": "^1.2.12" | ||
}, | ||
"devDependencies": { | ||
"mkdirp": "^0.5.1", | ||
"nock": "^8.2.1", | ||
"nock": "^9.0.6", | ||
"npmlog": "^4.0.1", | ||
"nyc": "^10.0.0", | ||
"require-inject": "^1.4.0", | ||
"rimraf": "^2.5.4", | ||
"standard": "^8.6.0", | ||
"tap": "^8.0.1" | ||
"standard": "^9.0.1", | ||
"standard-version": "^4.0.0", | ||
"tacks": "^1.2.6", | ||
"tap": "^10.2.0", | ||
"weallbehave": "^1.0.0", | ||
"weallcontribute": "^1.0.7" | ||
} | ||
} |
@@ -19,6 +19,7 @@ # pacote [![npm version](https://img.shields.io/npm/v/pacote.svg)](https://npm.im/pacote) [![license](https://img.shields.io/npm/l/pacote.svg)](https://npm.im/pacote) [![Travis](https://img.shields.io/travis/zkat/pacote.svg)](https://travis-ci.org/zkat/pacote) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/zkat/pacote?svg=true)](https://ci.appveyor.com/project/zkat/pacote) [![Coverage Status](https://coveralls.io/repos/github/zkat/pacote/badge.svg?branch=latest)](https://coveralls.io/github/zkat/pacote?branch=latest) | ||
* [Features](#features) | ||
* [Guide](#guide) | ||
* [Contributing](#contributing) | ||
* [API](#api) | ||
* [`manifest`](#manifest) | ||
* [`extract`](#extract) | ||
* [`prefetch`](#prefetch) | ||
* [`options`](#options) | ||
@@ -31,3 +32,3 @@ | ||
pacote.manifest('pacote@^1', function (err, pkg) { | ||
pacote.manifest('pacote@^1').then(pkg => { | ||
console.log('package manifest for registry pkg:', pkg) | ||
@@ -37,3 +38,3 @@ // { "name": "pacote", "version": "1.0.0", ... } | ||
pacote.extract('http://hi.com/pkg.tgz', './here', function (err) { | ||
pacote.extract('http://hi.com/pkg.tgz', './here').then(() => { | ||
console.log('remote tarball contents extracted to ./here') | ||
@@ -45,22 +46,38 @@ }) | ||
* simple interface to common package-related actions. | ||
* supports all package types npm does. | ||
* fast cache | ||
* Handles all package types [npm](https://npm.im/npm) does | ||
* [high-performance, reliable, verified local cache](https://npm.im/cacache) | ||
* offline mode | ||
* authentication support (private git, private npm registries, etc) | ||
* npm-compatible for all relevant operations | ||
* github, gitlab, and bitbucket-aware | ||
* version/tag aware when fetching from git repositories. | ||
* caches git repositories | ||
* semver range support for git dependencies | ||
### Guide | ||
### Contributing | ||
#### Introduction | ||
The pacote team enthusiastically welcomes contributions and project participation! There's a bunch of things you can do if you want to contribute! The [Contributor Guide](CONTRIBUTING.md) has all the information you need for everything from reporting bugs to contributing entire new features. Please don't hesitate to jump in if you'd like to, or even ask us questions if something isn't clear. | ||
### API | ||
#### <a name="manifest"></a> `> pacote.manifest(spec, [opts], cb)` | ||
#### <a name="manifest"></a> `> pacote.manifest(spec, [opts])` | ||
Fetches the *manifest* for a package, aka `package.json`. | ||
Fetches the *manifest* for a package. Manifest objects are similar and based | ||
on the `package.json` for that package, but with pre-processed and limited | ||
fields. The object has the following shape: | ||
```javascript | ||
{ | ||
"name": PkgName, | ||
"version": SemverString, | ||
"dependencies": { PkgName: SemverString }, | ||
"optionalDependencies": { PkgName: SemverString }, | ||
"devDependencies": { PkgName: SemverString }, | ||
"peerDependencies": { PkgName: SemverString }, | ||
"bundleDependencies": false || [PkgName], | ||
"bin": { BinName: Path }, | ||
"_resolved": TarballSource, // different for each package type | ||
"_shasum": TarballSha1Sum, | ||
"_sha512sum": TarballSha512Sum, | ||
"_shrinkwrap": null || ShrinkwrapJsonObj | ||
} | ||
``` | ||
Note that depending on the spec type, some additional fields might be present. | ||
@@ -73,8 +90,8 @@ For example, packages from `registry.npmjs.org` have additional metadata | ||
```javascript | ||
pacote.manifest('pacote@1.0.0', function (err, pkgJson) { | ||
// fetched `package.json` data from the registry (or cache, if cached) | ||
pacote.manifest('pacote@1.0.0').then(pkgJson => { | ||
// fetched `package.json` data from the registry | ||
}) | ||
``` | ||
#### <a name="extract"></a> `> pacote.extract(spec, destination, [opts], cb)` | ||
#### <a name="extract"></a> `> pacote.extract(spec, destination, [opts])` | ||
@@ -93,3 +110,3 @@ Extracts package data identified by `<spec>` into a directory named | ||
digest: 'deadbeef' | ||
}, function (err) { | ||
}).then(() => { | ||
// Succeeds as long as `pacote@1.0.0` still exists somewhere. Network and | ||
@@ -100,2 +117,15 @@ // other operations are bypassed entirely if `digest` is present in the cache. | ||
#### <a name="prefetch"></a> `> pacote.prefetch(spec, [opts])` | ||
Fetches package data identified by `<spec>`, usually for the purpose of warming | ||
up the local package cache (with `opts.cache`). It does not return anything. | ||
##### Example | ||
```javascript | ||
pacote.prefetch('pacote@1.0.0', { cache: './my-cache' }).then(() => { | ||
// ./my-cache now has both the manifest and tarball for `pacote@1.0.0`. | ||
}) | ||
``` | ||
#### <a name="options"></a> `> options` | ||
@@ -102,0 +132,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
53368
38
1345
1
148
22
12
1
80
9
2
+ Addedbluebird@^3.5.0
+ Addedchecksum-stream@^1.0.2
+ Addedglob@^7.1.1
+ Addedlru-cache@^4.0.2
+ Addedminimatch@^3.0.3
+ Addednormalize-git-url@^3.0.2
+ Addedosenv@^0.1.4
+ Addedpromise-inflight@^1.0.1
+ Addedunique-filename@^1.1.0
+ Addedwhich@^1.2.12
+ Addedbluebird@3.7.2(transitive)
+ Addedcacache@6.3.0(transitive)
+ Addedcopy-concurrently@1.0.5(transitive)
+ Addedfs-write-stream-atomic@1.0.10(transitive)
+ Addediferr@0.1.5(transitive)
+ Addedisexe@2.0.0(transitive)
+ Addedlru-cache@4.1.5(transitive)
+ Addedmove-concurrently@1.0.1(transitive)
+ Addednormalize-git-url@3.0.2(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedos-tmpdir@1.0.2(transitive)
+ Addedosenv@0.1.5(transitive)
+ Addedpromise-inflight@1.0.1(transitive)
+ Addedpseudomap@1.0.2(transitive)
+ Addedrun-queue@1.0.3(transitive)
+ Addedwhich@1.3.1(transitive)
+ Addedyallist@2.1.2(transitive)
- Removedcacache@5.0.3(transitive)
- Removedlockfile@1.0.4(transitive)
- Removedsplit@1.0.1(transitive)
- Removedthrough@2.3.8(transitive)
Updatedcacache@^6.2.0
Updatednpm-registry-client@^7.4.6
Updatedrequest@^2.81.0
Updatedtar-fs@^1.15.1