bit-bin
Version:
<a href="https://opensource.org/licenses/Apache-2.0"><img alt="apache" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a> <a href="https://github.com/teambit/bit/blob/master/CONTRIBUTING.md"><img alt="prs" src="https://img.shields.io/b
625 lines (506 loc) • 18.6 kB
JavaScript
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _bluebird() {
const data = require("bluebird");
_bluebird = function () {
return data;
};
return data;
}
function _execa() {
const data = _interopRequireDefault(require("execa"));
_execa = function () {
return data;
};
return data;
}
function _child_process() {
const data = require("child_process");
_child_process = function () {
return data;
};
return data;
}
function _pMapSeries() {
const data = _interopRequireDefault(require("p-map-series"));
_pMapSeries = function () {
return data;
};
return data;
}
function _semver() {
const data = _interopRequireDefault(require("semver"));
_semver = function () {
return data;
};
return data;
}
function _ramda() {
const data = _interopRequireWildcard(require("ramda"));
_ramda = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _fsExtra() {
const data = _interopRequireDefault(require("fs-extra"));
_fsExtra = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("path"));
path = function () {
return data;
};
return data;
}
function _logger() {
const data = _interopRequireDefault(require("../logger/logger"));
_logger = function () {
return data;
};
return data;
}
function _constants() {
const data = require("../constants");
_constants = function () {
return data;
};
return data;
}
function _analytics() {
const data = require("../analytics/analytics");
_analytics = function () {
return data;
};
return data;
}
function _showDoctorError() {
const data = _interopRequireDefault(require("../error/show-doctor-error"));
_showDoctorError = function () {
return data;
};
return data;
}
const objectToArray = obj => (0, _ramda().map)((0, _ramda().join)('@'), (0, _ramda().toPairs)(obj));
const rejectNils = _ramda().default.reject(_ramda().isNil);
const defaultNpmArgs = [];
const defaultYarnArgs = [];
const defaultPnpmArgs = [];
const defaultPackageManagerArgs = {
npm: defaultNpmArgs,
yarn: defaultYarnArgs,
pnpm: defaultPnpmArgs
};
const defaultPackageManagerProcessOptions = {
cwd: process.cwd
};
const warningPrefix = packageManager => {
return packageManager === 'npm' ? 'npm WARN' : 'warning';
};
const errorPrefix = packageManager => {
return packageManager === 'npm' ? 'npm ERR!' : 'error';
};
const peerDependenciesMissing = packageManager => {
return packageManager === 'npm' ? 'requires a peer' : 'unmet peer';
};
const stripNonNpmErrors = (errors, packageManager) => {
// a workaround to remove all 'npm warn' and 'npm notice'.
// NPM itself returns them even when --loglevel = error or when --silent/--quiet flags are set
const prefix = errorPrefix(packageManager);
return errors.split('\n').filter(error => error.startsWith(prefix)).join('\n');
};
const stripNonPeerDependenciesWarnings = (errors, packageManager) => {
const prefix = warningPrefix(packageManager);
const peer = peerDependenciesMissing(packageManager);
return errors.split('\n').filter(error => error.startsWith(prefix) && error.includes(peer)).join('\n');
};
/**
* Pick only allowed to be overridden options
* @param {Object} userOptions
*/
const getAllowdPackageManagerProcessOptions = userOptions => {
const allowdOptions = ['shell', 'env', 'extendEnv', 'uid', 'gid', 'preferLocal', 'localDir', 'timeout'];
return _ramda().default.pick(allowdOptions, userOptions);
};
/**
* Install packages in specific directory
*/
const _installInOneDirectory = ({
modules = [],
packageManager = _constants().DEFAULT_PACKAGE_MANAGER,
packageManagerArgs = [],
packageManagerProcessOptions = {},
dir,
installProdPackagesOnly = false,
verbose = false
}) => {
// Handle process options
const allowedPackageManagerProcessOptions = getAllowdPackageManagerProcessOptions(packageManagerProcessOptions);
const concretePackageManagerProcessOptions = (0, _ramda().merge)(defaultPackageManagerProcessOptions, allowedPackageManagerProcessOptions);
concretePackageManagerProcessOptions.cwd = dir || concretePackageManagerProcessOptions.cwd;
const cwd = concretePackageManagerProcessOptions.cwd; // taking care of object case
const processedModules = (0, _ramda().is)(Object, modules) && !Array.isArray(modules) ? objectToArray(modules) : modules; // Handle process args
const concretePackageManagerDefaultArgs = ['install', ...processedModules, ...defaultPackageManagerArgs[packageManager]];
const concretePackageManagerArgs = rejectNils(_ramda().default.concat(concretePackageManagerDefaultArgs, packageManagerArgs)); // Add npm verbose flag
if (verbose && packageManager === 'npm') {// we may want to use it later. For now, it print too much information
// concretePackageManagerArgs.push('--verbose');
}
if (installProdPackagesOnly) {
concretePackageManagerArgs.push('--production');
}
_fsExtra().default.ensureDirSync(path().join(cwd, 'node_modules'));
_logger().default.debug(`installing npm packages using ${packageManager} at ${cwd} with args: ${concretePackageManagerArgs} and options:`, concretePackageManagerProcessOptions); // Set the shell to true to prevent problems with post install scripts when running as root
const packageManagerClientName = packageManager;
const childProcess = (0, _execa().default)(packageManagerClientName, concretePackageManagerArgs, concretePackageManagerProcessOptions); // Remove the install from args since it's always there
const printArgs = concretePackageManagerArgs.filter(arg => arg !== 'install');
const argsString = printArgs && printArgs.length > 0 ? `with args: ${printArgs}` : '';
return childProcess.then(({
stdout,
stderr
}) => {
const successMessage = `\nsuccessfully ran ${packageManager} install at ${cwd} ${argsString}`;
const peerWarnings = stripNonPeerDependenciesWarnings(stderr, packageManager);
stdout = verbose ? stdout + successMessage : _chalk().default.white(peerWarnings) + successMessage;
stderr = verbose ? stderr : '';
return {
stdout,
stderr
};
}).catch(err => {
let stderr = `failed running ${packageManager} install at ${cwd} ${argsString} \n`;
stderr += verbose ? err.stderr : stripNonNpmErrors(err.stderr, packageManager);
throw new (_showDoctorError().default)(`${stderr}\n\n${_chalk().default.yellow(`see troubleshooting at https://${_constants().BASE_DOCS_DOMAIN}/docs/installing-components`)}`);
});
};
const _getNpmList = /*#__PURE__*/function () {
var _ref = (0, _bluebird().coroutine)(function* (packageManager, dir) {
// We don't use here execa since there is a bug with execa (2.*) with some node versions
// execa uses util.getSystemErrorName which not available in some node versions
// see more here - https://github.com/sindresorhus/execa/issues/318
// We also use spwan instead of exec since the output might be very long and exec is limited with
// handling such long outputs
// once we stop support node < 10 we can replace it with something like
// npmList = await execa(packageManager, ['list', '-j'], { cwd: dir });
return new Promise(resolve => {
let stdout = '';
let stderr = '';
const shell = _constants().IS_WINDOWS;
const ls = (0, _child_process().spawn)(packageManager, ['list', '-j'], {
cwd: dir,
shell
});
ls.stdout.on('data', data => {
stdout += data;
});
ls.stderr.on('data', data => {
stderr += data;
});
ls.on('error', err => {
stderr += err;
});
ls.on('close', code => {
const res = {
stdout,
stderr,
code
};
resolve(res);
});
});
});
return function _getNpmList(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
/**
* Get peer dependencies for directory
* you should run this after you run npm install
* internally it uses npm list -j
*/
const _getPeerDeps = /*#__PURE__*/function () {
var _ref2 = (0, _bluebird().coroutine)(function* (dir) {
const packageManager = _constants().DEFAULT_PACKAGE_MANAGER;
const npmList = yield _getNpmList(packageManager, dir); // If the npmList.stdout starts with '{' it's probably a valid json so no throw an error
if (npmList.stderr && !npmList.stdout.startsWith('{')) {
_logger().default.error('npm-client got an error', npmList.stderr);
throw new Error(`failed running ${packageManager} list on folder ${dir} to find the peer dependencies due to an error: ${npmList.stderr}`);
}
const peerDepsObject = yield getPeerDepsFromNpmList(npmList.stdout, packageManager);
return objectToArray(peerDepsObject);
});
return function _getPeerDeps(_x3) {
return _ref2.apply(this, arguments);
};
}();
function getPeerDepsFromNpmList(_x4, _x5) {
return _getPeerDepsFromNpmList.apply(this, arguments);
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
function _getPeerDepsFromNpmList() {
_getPeerDepsFromNpmList = (0, _bluebird().coroutine)(function* (npmList, packageManager) {
const parsePeers = deps => {
const result = {};
_ramda().default.forEachObjIndexed(dep => {
if (dep.peerMissing) {
const name = dep.required.name;
const version = dep.required.version;
result[name] = version;
}
}, deps);
return result;
};
const npmListObject = yield parseNpmListJsonGracefully(npmList, packageManager); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return parsePeers(npmListObject.dependencies);
});
return _getPeerDepsFromNpmList.apply(this, arguments);
}
function parseNpmListJsonGracefully(_x6, _x7) {
return _parseNpmListJsonGracefully.apply(this, arguments);
}
/**
* A wrapper function to call the install
* then get the peers
* then install the peers
*/
function _parseNpmListJsonGracefully() {
_parseNpmListJsonGracefully = (0, _bluebird().coroutine)(function* (str, packageManager) {
try {
const json = JSON.parse(str);
return json;
} catch (err) {
_logger().default.error('npm-client got an error', err);
if (packageManager === 'npm') {
const version = yield getNpmVersion();
_analytics().Analytics.setExtraData('npmVersion', version);
if (version && _semver().default.gte(version, '5.0.0') && _semver().default.lt(version, '5.1.0')) {
// see here for more info about this issue with npm 5.0.0
// https://github.com/npm/npm/issues/17331
throw new Error(`error: your npm version "${version}" has issues returning json, please upgrade to 5.1.0 or above (npm install -g npm@5.1.0)`);
}
}
throw new Error(`failed parsing the output of npm list due to an error: ${err.message}`);
}
});
return _parseNpmListJsonGracefully.apply(this, arguments);
}
const _installInOneDirectoryWithPeerOption = /*#__PURE__*/function () {
var _ref3 = (0, _bluebird().coroutine)(function* ({
modules = [],
packageManager = _constants().DEFAULT_PACKAGE_MANAGER,
packageManagerArgs = [],
packageManagerProcessOptions = {},
dir,
installPeerDependencies = false,
installProdPackagesOnly = false,
verbose = false
}) {
const rootDirResults = yield _installInOneDirectory({
modules,
packageManager,
packageManagerArgs,
packageManagerProcessOptions,
dir,
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
installPeerDependencies,
installProdPackagesOnly,
verbose
});
if (installPeerDependencies) {
const peers = yield _getPeerDeps(dir);
const peerResults = yield _installInOneDirectory({
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
modules: peers,
packageManager,
packageManagerArgs,
packageManagerProcessOptions,
dir,
installProdPackagesOnly,
verbose
});
return [rootDirResults, peerResults];
}
return rootDirResults;
});
return function _installInOneDirectoryWithPeerOption(_x8) {
return _ref3.apply(this, arguments);
};
}();
/**
* when modules is empty, it runs 'npm install' without any package, which installs according to package.json file
*/
const installAction = /*#__PURE__*/function () {
var _ref4 = (0, _bluebird().coroutine)(function* ({
modules,
packageManager = _constants().DEFAULT_PACKAGE_MANAGER,
packageManagerArgs = [],
packageManagerProcessOptions = {},
useWorkspaces = false,
dirs = [],
rootDir,
installRootPackageJson = false,
installPeerDependencies = false,
installProdPackagesOnly = false,
verbose = false
}) {
if (useWorkspaces && packageManager === 'yarn') {
yield _installInOneDirectoryWithPeerOption({
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
modules,
packageManager,
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
packageManagerArgs,
packageManagerProcessOptions,
dir: rootDir,
installPeerDependencies,
installProdPackagesOnly,
verbose
});
}
const results = [];
if (installRootPackageJson) {
// installation of the root package.json has to be completed before installing the sub-directories package.json.
const rootDirResults = yield _installInOneDirectoryWithPeerOption({
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
modules,
packageManager,
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
packageManagerArgs,
packageManagerProcessOptions,
dir: rootDir,
installPeerDependencies,
installProdPackagesOnly,
verbose
});
if (Array.isArray(rootDirResults)) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
results.concat(rootDirResults);
} else {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
results.push(rootDirResults);
}
}
const installInDir = dir => _installInOneDirectoryWithPeerOption({
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
modules,
packageManager,
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
packageManagerArgs,
packageManagerProcessOptions,
dir,
installPeerDependencies,
installProdPackagesOnly,
verbose
}); // run npm install for each one of the directories serially, not in parallel. Don’t use Promise.all() here.
// running them in parallel result in race condition and random NPM errors. (see https://github.com/teambit/bit/issues/1617)
const promisesResults = yield (0, _pMapSeries().default)(dirs, installInDir);
return results.concat(_ramda().default.flatten(promisesResults));
});
return function installAction(_x9) {
return _ref4.apply(this, arguments);
};
}();
const printResults = ({
stdout,
stderr
}) => {
_logger().default.console(_chalk().default.yellow(stdout)); // eslint-disable-line
_logger().default.console(_chalk().default.yellow(stderr)); // eslint-disable-line
};
function getNpmVersion() {
return _getNpmVersion.apply(this, arguments);
}
function _getNpmVersion() {
_getNpmVersion = (0, _bluebird().coroutine)(function* () {
try {
const {
stdout,
stderr
} = yield (0, _execa().default)('npm', ['--version']);
if (stdout && !stderr) return stdout;
} catch (err) {
_logger().default.debugAndAddBreadCrumb('npm-client', `got an error when executing "npm --version". ${err.message}`);
}
return null;
});
return _getNpmVersion.apply(this, arguments);
}
function getYarnVersion() {
return _getYarnVersion.apply(this, arguments);
}
/**
* a situation where rootDir and subDir have package.json, some of the packages may be shared
* and some may be conflicted. And the "npm/yarn install" is done from the root dir.
* package managers install the shared packages only once in the rootDir.
* however, as to the conflicted packages, only npm@5 and above install it in the subDir.
* others, install it in the root, which, result in an incorrect package resolution for the subDir.
*/
function _getYarnVersion() {
_getYarnVersion = (0, _bluebird().coroutine)(function* () {
try {
const {
stdout
} = yield (0, _execa().default)('yarn', ['-v']);
return stdout;
} catch (e) {
_logger().default.debugAndAddBreadCrumb('npm-client', `can't find yarn version by running yarn -v. ${e.message}`);
}
return null;
});
return _getYarnVersion.apply(this, arguments);
}
function isSupportedInstallationOfSubDirFromRoot(_x10) {
return _isSupportedInstallationOfSubDirFromRoot.apply(this, arguments);
}
function _isSupportedInstallationOfSubDirFromRoot() {
_isSupportedInstallationOfSubDirFromRoot = (0, _bluebird().coroutine)(function* (packageManager) {
if (packageManager === 'npm') {
const version = yield getNpmVersion();
if (version && _semver().default.gte(version, '5.0.0')) {
return true;
}
}
return false;
});
return _isSupportedInstallationOfSubDirFromRoot.apply(this, arguments);
}
function getPackageLatestVersion(_x11) {
return _getPackageLatestVersion.apply(this, arguments);
}
function _getPackageLatestVersion() {
_getPackageLatestVersion = (0, _bluebird().coroutine)(function* (packageName) {
try {
const {
stdout
} = yield (0, _execa().default)('npm', ['show', packageName, 'version']);
return stdout;
} catch (e) {
_logger().default.debugAndAddBreadCrumb('npm-client', `can't find ${packageName} version by running npm show ${packageName} version. ${e.message}`);
}
return null;
});
return _getPackageLatestVersion.apply(this, arguments);
}
var _default = {
install: installAction,
printResults,
isSupportedInstallationOfSubDirFromRoot,
getNpmVersion,
getYarnVersion,
getPeerDepsFromNpmList,
getPackageLatestVersion
};
exports.default = _default;
;