UNPKG

@dependabot/yarn-lib

Version:

📦🐈 Fast, reliable, and secure dependency management.

297 lines (228 loc) 10.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.LocalTarballFetcher = undefined; var _asyncToGenerator2; function _load_asyncToGenerator() { return _asyncToGenerator2 = _interopRequireDefault(require('babel-runtime/helpers/asyncToGenerator')); } var _http; function _load_http() { return _http = _interopRequireDefault(require('http')); } var _errors; function _load_errors() { return _errors = require('../errors.js'); } var _constants; function _load_constants() { return _constants = _interopRequireWildcard(require('../constants.js')); } var _crypto; function _load_crypto() { return _crypto = _interopRequireWildcard(require('../util/crypto.js')); } var _baseFetcher; function _load_baseFetcher() { return _baseFetcher = _interopRequireDefault(require('./base-fetcher.js')); } var _fs; function _load_fs() { return _fs = _interopRequireWildcard(require('../util/fs.js')); } var _misc; function _load_misc() { return _misc = require('../util/misc.js'); } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const path = require('path'); const tarFs = require('tar-fs'); const url = require('url'); const fs = require('fs'); const stream = require('stream'); const gunzip = require('gunzip-maybe'); const invariant = require('invariant'); const RE_URL_NAME_MATCH = /\/(?:(@[^/]+)\/)?[^/]+\/-\/(?:@[^/]+\/)?([^/]+)$/; class TarballFetcher extends (_baseFetcher || _load_baseFetcher()).default { setupMirrorFromCache() { var _this = this; return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { const tarballMirrorPath = _this.getTarballMirrorPath(); const tarballCachePath = _this.getTarballCachePath(); if (tarballMirrorPath == null) { return; } if (!(yield (_fs || _load_fs()).exists(tarballMirrorPath)) && (yield (_fs || _load_fs()).exists(tarballCachePath))) { // The tarball doesn't exists in the offline cache but does in the cache; we import it to the mirror yield (_fs || _load_fs()).mkdirp(path.dirname(tarballMirrorPath)); yield (_fs || _load_fs()).copy(tarballCachePath, tarballMirrorPath, _this.reporter); } })(); } getTarballCachePath() { return path.join(this.dest, (_constants || _load_constants()).TARBALL_FILENAME); } getTarballMirrorPath() { var _url$parse = url.parse(this.reference); const pathname = _url$parse.pathname; if (pathname == null) { return null; } const match = pathname.match(RE_URL_NAME_MATCH); let packageFilename; if (match) { const scope = match[1], tarballBasename = match[2]; packageFilename = scope ? `${scope}-${tarballBasename}` : tarballBasename; } else { // fallback to base name packageFilename = path.basename(pathname); } return this.config.getOfflineMirrorPath(packageFilename); } createExtractor(resolve, reject, tarballPath) { var _this2 = this; const validateStream = new (_crypto || _load_crypto()).HashStream(); const extractorStream = gunzip(); const untarStream = tarFs.extract(this.dest, { strip: 1, dmode: 0o755, // all dirs should be readable fmode: 0o644, // all files should be readable chown: false // don't chown. just leave as it is }); extractorStream.pipe(untarStream).on('error', error => { error.message = `${error.message}${tarballPath ? ` (${tarballPath})` : ''}`; reject(error); }).on('finish', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { const expectHash = _this2.hash; const actualHash = validateStream.getHash(); if (!expectHash || expectHash === actualHash) { resolve({ hash: actualHash }); } else if (_this2.config.updateChecksums) { // checksums differ and should be updated // update hash, destination and cached package const destUpdatedHash = _this2.dest.replace(_this2.hash || '', actualHash); yield (_fs || _load_fs()).unlink(destUpdatedHash); yield (_fs || _load_fs()).rename(_this2.dest, destUpdatedHash); _this2.dest = _this2.dest.replace(_this2.hash || '', actualHash); _this2.hash = actualHash; resolve({ hash: actualHash }); } else { reject(new (_errors || _load_errors()).SecurityError(_this2.config.reporter.lang('fetchBadHashWithPath', _this2.packageName, _this2.remote.reference, actualHash, expectHash))); } })); return { validateStream, extractorStream }; } *getLocalPaths(override) { if (override) { yield path.resolve(this.config.cwd, override); } yield this.getTarballMirrorPath(); yield this.getTarballCachePath(); } fetchFromLocal(override) { var _this3 = this; return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { var _ref2 = yield (_fs || _load_fs()).readFirstAvailableStream(_this3.getLocalPaths(override)); const stream = _ref2.stream, triedPaths = _ref2.triedPaths; return new Promise(function (resolve, reject) { if (!stream) { reject(new (_errors || _load_errors()).MessageError(_this3.reporter.lang('tarballNotInNetworkOrCache', _this3.reference, triedPaths))); return; } invariant(stream, 'stream should be available at this point'); // $FlowFixMe - This is available https://nodejs.org/api/fs.html#fs_readstream_path const tarballPath = stream.path; var _createExtractor = _this3.createExtractor(resolve, reject, tarballPath); const validateStream = _createExtractor.validateStream, extractorStream = _createExtractor.extractorStream; stream.pipe(validateStream).pipe(extractorStream).on('error', function (err) { reject(new (_errors || _load_errors()).MessageError(_this3.config.reporter.lang('fetchErrorCorrupt', err.message, tarballPath))); }); }); })(); } fetchFromExternal() { var _this4 = this; return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { const registry = _this4.config.registries[_this4.registry]; let retriesRemaining = 2; do { try { return yield registry.request(_this4.reference, { headers: { 'Accept-Encoding': 'gzip' }, buffer: true, process: function process(req, resolve, reject) { // should we save this to the offline cache? const reporter = _this4.config.reporter; const tarballMirrorPath = _this4.getTarballMirrorPath(); const tarballCachePath = _this4.getTarballCachePath(); var _createExtractor2 = _this4.createExtractor(resolve, reject); const validateStream = _createExtractor2.validateStream, extractorStream = _createExtractor2.extractorStream; req.on('response', function (res) { if (res.statusCode >= 400) { const statusDescription = (_http || _load_http()).default.STATUS_CODES[res.statusCode]; reject(new (_errors || _load_errors()).ResponseError(reporter.lang('requestFailed', `${res.statusCode} ${statusDescription}`), res.statusCode)); } }); req.pipe(validateStream); if (tarballMirrorPath) { validateStream.pipe(fs.createWriteStream(tarballMirrorPath)).on('error', reject); } if (tarballCachePath) { validateStream.pipe(fs.createWriteStream(tarballCachePath)).on('error', reject); } validateStream.pipe(extractorStream).on('error', reject); } }, _this4.packageName); } catch (err) { if (err instanceof (_errors || _load_errors()).ResponseError && err.responseCode >= 500 && retriesRemaining > 1) { retriesRemaining--; _this4.reporter.warn(_this4.reporter.lang('retryOnInternalServerError')); yield (0, (_misc || _load_misc()).sleep)(3000); } else { const tarballMirrorPath = _this4.getTarballMirrorPath(); const tarballCachePath = _this4.getTarballCachePath(); if (tarballMirrorPath && (yield (_fs || _load_fs()).exists(tarballMirrorPath))) { yield (_fs || _load_fs()).unlink(tarballMirrorPath); } if (tarballCachePath && (yield (_fs || _load_fs()).exists(tarballCachePath))) { yield (_fs || _load_fs()).unlink(tarballCachePath); } throw err; } } } while (retriesRemaining > 0); // Unreachable code, this is just to make Flow happy throw new Error('Ran out of retries!'); })(); } _fetch() { const isFilePath = this.reference.startsWith('file:'); this.reference = (0, (_misc || _load_misc()).removePrefix)(this.reference, 'file:'); const urlParse = url.parse(this.reference); // legacy support for local paths in yarn.lock entries const isRelativePath = urlParse.protocol ? urlParse.protocol.match(/^[a-z]:$/i) : urlParse.pathname ? urlParse.pathname.match(/^(?:\.{1,2})?[\\\/]/) : false; if (isFilePath || isRelativePath) { return this.fetchFromLocal(this.reference); } return this.fetchFromLocal().catch(err => this.fetchFromExternal()); } } exports.default = TarballFetcher; class LocalTarballFetcher extends TarballFetcher { _fetch() { return this.fetchFromLocal(this.reference); } } exports.LocalTarballFetcher = LocalTarballFetcher;