@dependabot/yarn-lib
Version:
📦🐈 Fast, reliable, and secure dependency management.
297 lines (228 loc) • 10.1 kB
JavaScript
;
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;