UNPKG

npcache

Version:

Manipulate cache of npm packages

196 lines (162 loc) 4.41 kB
'use strict'; const {join} = require('path'); const {Readable, Writable} = require('stream'); const {stat} = require('fs').promises; const npmCachePath = require('npm-cache-path'); const rejectUnsatisfiedNpmVersion = require('reject-unsatisfied-npm-version'); const resolveFromNpm = require('resolve-from-npm'); const MINIMUM_REQUIRED_NPM_VERSION = '6.9.0'; const MODULE_NAME = 'cacache'; const STREAM_EVENTS = new Set(['error', 'integrity', 'metadata']); const readableAsyncIterator = Readable.prototype[Symbol.asyncIterator]; let promiseCache; class NpcachePutStream extends Writable { #promise; constructor(...args) { super(); this.cork(); this.#promise = (async () => { try { const [cacache, cachePath] = await prepare(); this.internalStream = cacache.put.stream(cachePath, ...args); this.uncork(); } catch (err) { this.destroy(err); } })(); } _write(chunk, encoding, cb) { this.internalStream.write(chunk, encoding, cb); } async _final(cb) { await this.#promise; this.internalStream.end(cb); } } async function prepare() { if (promiseCache) { return promiseCache; } let error; const results = await Promise.all([ (async () => { try { return require(await resolveFromNpm(MODULE_NAME)); } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { err.message = `'${ MODULE_NAME }' module is not bundled in your npm CLI. Run the command \`npm install --global npm\` to reinstall a valid npm CLI.`; } error = err; return null; } })(), (async () => { let parentDir; try { parentDir = await npmCachePath(); } catch (err) { error = err; return null; } const cachePath = join(parentDir, '_cacache'); await Promise.all([ { path: cachePath, place: 'there' }, { path: parentDir, place: `at its parent path ${parentDir}` } ].map(async ({path, place}) => { let isFile; try { isFile = (await stat(parentDir)).isFile(); } catch { return; } if (isFile) { const enotdirError = new Error(`The current npm CLI setting indicates ${cachePath} is used as a cache directory for npm packages, but a file exists ${place}.`); enotdirError.code = 'ENOTDIR'; enotdirError.path = path; error = enotdirError; } })); return cachePath; })(), rejectUnsatisfiedNpmVersion(MINIMUM_REQUIRED_NPM_VERSION) ]); if (error) { throw error; } promiseCache = results; return results; } function toAsyncIterable(stream) { if (stream.constructor.prototype[Symbol.asyncIterator] === undefined) { stream.constructor.prototype[Symbol.asyncIterator] = readableAsyncIterator; } return stream; } exports.rm = {}; exports.tmp = {}; for (const method of [ 'ls', ['ls', 'stream'], 'get', ['get', 'byDigest'], ['get', 'stream'], ['get', 'info'], ['get', 'hasContent'], 'put', ['put', 'stream'], ['rm', 'all'], ['rm', 'entry'], ['rm', 'content'], 'clearMemoized', ['tmp', 'mkdir'], ['tmp', 'fix'], ['tmp', 'withTmp'], 'verify', ['verify', 'lastRun'] ]) { if (Array.isArray(method)) { if (method[1] === 'stream') { if (method[0] === 'put') { exports.put.stream = (...args) => new NpcachePutStream(...args); } else { exports[method[0]][method[1]] = (...args) => { const stream = Readable.from((async function *() { const [cacache, cachePath] = await prepare(); const internalStream = toAsyncIterable(cacache[method[0]][method[1]](cachePath, ...args)); for (const eventName of STREAM_EVENTS) { internalStream.once(eventName, value => stream.emit(eventName, value)); } yield *internalStream; })()); return stream; }; } } else { exports[method[0]][method[1]] = async (...args) => { const [cacache, cachePath] = await prepare(); return cacache[method[0]][method[1]](cachePath, ...args); }; } continue; } exports[method] = async (...args) => { const [cacache, cachePath] = await prepare(); return cacache[method](cachePath, ...args); }; } exports.get.stream.byDigest = (...args) => Readable.from((async function *() { const [cacache, cachePath] = await prepare(); yield *toAsyncIterable(cacache.get.stream.byDigest(cachePath, ...args)); })()); Object.defineProperty(exports, 'MINIMUM_REQUIRED_NPM_VERSION', { enumerable: true, value: MINIMUM_REQUIRED_NPM_VERSION });