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
664 lines (521 loc) • 20.2 kB
JavaScript
"use strict";
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 _defineProperty2() {
const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
_defineProperty2 = function () {
return data;
};
return data;
}
function _ramda() {
const data = _interopRequireDefault(require("ramda"));
_ramda = function () {
return data;
};
return data;
}
function _execa() {
const data = _interopRequireDefault(require("execa"));
_execa = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("path"));
path = function () {
return data;
};
return data;
}
function _semver() {
const data = _interopRequireDefault(require("semver"));
_semver = function () {
return data;
};
return data;
}
function _pMapSeries() {
const data = _interopRequireDefault(require("p-map-series"));
_pMapSeries = function () {
return data;
};
return data;
}
function _capsuleFactory() {
const data = _interopRequireDefault(require("./capsule-factory"));
_capsuleFactory = function () {
return data;
};
return data;
}
function _manyComponentsWriter() {
const data = _interopRequireDefault(require("../consumer/component-ops/many-components-writer"));
_manyComponentsWriter = function () {
return data;
};
return data;
}
function _logger() {
const data = _interopRequireDefault(require("../logger/logger"));
_logger = function () {
return data;
};
return data;
}
function _loadFlattenedDependencies() {
const data = _interopRequireDefault(require("../consumer/component-ops/load-flattened-dependencies"));
_loadFlattenedDependencies = function () {
return data;
};
return data;
}
function _packageJsonUtils() {
const data = require("../consumer/component/package-json-utils");
_packageJsonUtils = function () {
return data;
};
return data;
}
function _componentIdToPackageName() {
const data = _interopRequireDefault(require("../utils/bit/component-id-to-package-name"));
_componentIdToPackageName = function () {
return data;
};
return data;
}
function _constants() {
const data = require("../constants");
_constants = function () {
return data;
};
return data;
}
function _npmClient() {
const data = _interopRequireDefault(require("../npm-client"));
_npmClient = function () {
return data;
};
return data;
}
function _componentsGraph() {
const data = require("../scope/graph/components-graph");
_componentsGraph = function () {
return data;
};
return data;
}
function _dataToPersist() {
const data = _interopRequireDefault(require("../consumer/component/sources/data-to-persist"));
_dataToPersist = function () {
return data;
};
return data;
}
function _manipulateDir() {
const data = require("../consumer/component-ops/manipulate-dir");
_manipulateDir = function () {
return data;
};
return data;
}
function _generalError() {
const data = _interopRequireDefault(require("../error/general-error"));
_generalError = function () {
return data;
};
return data;
}
function _loader() {
const data = _interopRequireDefault(require("../cli/loader"));
_loader = function () {
return data;
};
return data;
}
class Isolator {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// this is the same packageJson of the main component as it located on the root
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
constructor(capsule, scope, consumer, dir) {
(0, _defineProperty2().default)(this, "capsule", void 0);
(0, _defineProperty2().default)(this, "consumer", void 0);
(0, _defineProperty2().default)(this, "scope", void 0);
(0, _defineProperty2().default)(this, "capsuleBitMap", void 0);
(0, _defineProperty2().default)(this, "capsulePackageJson", void 0);
(0, _defineProperty2().default)(this, "componentWithDependencies", void 0);
(0, _defineProperty2().default)(this, "manyComponentsWriter", void 0);
(0, _defineProperty2().default)(this, "_npmVersionHasValidated", false);
(0, _defineProperty2().default)(this, "componentRootDir", void 0);
(0, _defineProperty2().default)(this, "dir", void 0);
this.capsule = capsule;
this.scope = scope;
this.consumer = consumer;
this.dir = dir;
}
static getInstance(containerType = 'fs', scope, consumer, dir) {
return (0, _bluebird().coroutine)(function* () {
_logger().default.debug(`Isolator.getInstance, creating a capsule with an ${containerType} container, dir ${dir || 'N/A'}`);
const capsule = yield (0, _capsuleFactory().default)(containerType, dir);
return new Isolator(capsule, scope, consumer, dir);
})();
}
isolate(componentId, opts) {
var _this = this;
return (0, _bluebird().coroutine)(function* () {
const loaderPrefix = `isolating component - ${componentId.name}`;
_loader().default.setText(loaderPrefix);
const componentWithDependencies = yield _this._loadComponent(componentId);
if (opts.shouldBuildDependencies) {
(0, _componentsGraph().topologicalSortComponentDependencies)(componentWithDependencies);
yield (0, _pMapSeries().default)(componentWithDependencies.dependencies.reverse(), /*#__PURE__*/function () {
var _ref = (0, _bluebird().coroutine)(function* (dep) {
if (!dep.dists || dep.dists.isEmpty()) {
yield dep.build({
scope: _this.scope,
consumer: _this.consumer
});
dep.dists.stripOriginallySharedDir(dep.originallySharedDir);
} else {
// needed for cases when a component is isolated as an individual first, then as a dependency.
// because when it is isolated in the first time, the 'writeDistsFiles' is manually set to false
dep.dists.writeDistsFiles = true;
}
});
return function (_x) {
return _ref.apply(this, arguments);
};
}());
}
const writeToPath = opts.writeToPath; // default should be true
const installNpmPackages = typeof opts.installNpmPackages === 'undefined' ? true : opts.installNpmPackages;
const concreteOpts = {
componentsWithDependencies: [componentWithDependencies],
writeToPath,
override: opts.override,
writePackageJson: opts.writePackageJson,
writeConfig: opts.writeConfig,
writeBitDependencies: opts.writeBitDependencies,
createNpmLinkFiles: opts.createNpmLinkFiles,
saveDependenciesAsComponents: opts.saveDependenciesAsComponents !== false,
writeDists: opts.writeDists,
installNpmPackages,
installPeerDependencies: !!opts.installPeerDependencies,
// convert to boolean
addToRootPackageJson: false,
verbose: opts.verbose,
excludeRegistryPrefix: !!opts.excludeRegistryPrefix,
silentPackageManagerResult: opts.silentPackageManagerResult,
applyExtensionsAddedConfig: opts.applyExtensionsAddedConfig,
isolated: true
};
_this.componentWithDependencies = componentWithDependencies;
_this.manyComponentsWriter = new (_manyComponentsWriter().default)(concreteOpts);
yield _this.writeComponentsAndDependencies({
keepExistingCapsule: !!opts.keepExistingCapsule
});
yield _this.installComponentPackages({
installNpmPackages,
keepExistingCapsule: !!opts.keepExistingCapsule
});
yield _this.writeLinks({
keepExistingCapsule: !!opts.keepExistingCapsule
});
_this.capsuleBitMap = _this.manyComponentsWriter.bitMap;
return componentWithDependencies;
})();
}
writeComponentsAndDependencies(opts = {
keepExistingCapsule: false
}) {
var _this2 = this;
return (0, _bluebird().coroutine)(function* () {
_logger().default.debug('ManyComponentsWriter, writeAllToIsolatedCapsule');
_this2._manipulateDir();
yield _this2.manyComponentsWriter._populateComponentsFilesToWrite();
yield _this2.manyComponentsWriter._populateComponentsDependenciesToWrite();
yield _this2._persistComponentsDataToCapsule({
keepExistingCapsule: !!opts.keepExistingCapsule
});
})();
}
installComponentPackages(opts = {
installNpmPackages: true,
keepExistingCapsule: false
}) {
var _this3 = this;
return (0, _bluebird().coroutine)(function* () {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
_this3.capsulePackageJson = _this3.componentWithDependencies.component.packageJsonFile; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
_this3.componentRootDir = _this3.componentWithDependencies.component.writtenPath;
yield _this3._addComponentsToRoot({
keepExistingCapsule: !!opts.keepExistingCapsule
});
_logger().default.debug('ManyComponentsWriter, install packages on capsule');
if (opts.installNpmPackages) {
yield _this3._installWithPeerOption();
}
})();
}
writeLinks(opts = {
keepExistingCapsule: false
}) {
var _this4 = this;
return (0, _bluebird().coroutine)(function* () {
const links = yield _this4.manyComponentsWriter._getAllLinks(); // links is a DataToPersist instance
yield links.persistAllToCapsule(_this4.capsule, {
keepExistingCapsule: !!opts.keepExistingCapsule
});
})();
}
/**
* used by compilers that create capsule.
* when installing packages on the capsule, the links generated on node_modules may be deleted
*/
writeLinksOnNodeModules() {
var _this5 = this;
return (0, _bluebird().coroutine)(function* () {
const links = yield _this5.manyComponentsWriter._getAllLinks();
const nodeModulesLinks = links.filterByPath(filePath => filePath.startsWith('node_modules'));
yield nodeModulesLinks.persistAllToCapsule(_this5.capsule);
})();
}
_manipulateDir() {
const allComponents = [this.componentWithDependencies.component, ...this.componentWithDependencies.allDependencies];
const manipulateDirData = (0, _manipulateDir().getManipulateDirForComponentWithDependencies)(this.componentWithDependencies);
allComponents.forEach(component => {
component.stripOriginallySharedDir(manipulateDirData);
});
}
/**
* To write a component into an isolated environment, we need not only its dependencies, but
* also the dependencies of its dependencies and so on.
* When loading a component from the model, it's easy to get them all from the
* flattenedDependencies. However, when loading from the consumer, we have only the dependencies
* loaded, not the flattened. To get the flattened, we have to load the dependencies and each one
* of the dependency we need to load its dependencies as well until we got them all.
* Also, we have to clone each component we load, because when writing them into the capsule, we
* strip their shared-dir and we don't want these changed paths to affect the workspace
*/
_loadComponent(id) {
var _this6 = this;
return (0, _bluebird().coroutine)(function* () {
if (_this6.consumer) {
return _this6._loadComponentFromConsumer(id);
}
throw new Error('loading components from scope is not implemented yet');
})();
}
_loadComponentFromConsumer(id) {
var _this7 = this;
return (0, _bluebird().coroutine)(function* () {
const consumer = _this7.consumer;
if (!consumer) throw new Error('missing consumer');
const component = yield consumer.loadComponentForCapsule(id);
return (0, _loadFlattenedDependencies().default)(consumer, component);
})();
}
_persistComponentsDataToCapsule(opts = {
keepExistingCapsule: false
}) {
var _this8 = this;
return (0, _bluebird().coroutine)(function* () {
const dataToPersist = new (_dataToPersist().default)();
const allComponents = [_this8.componentWithDependencies.component, ..._this8.componentWithDependencies.allDependencies];
allComponents.forEach(component => dataToPersist.merge(component.dataToPersist));
yield dataToPersist.persistAllToCapsule(_this8.capsule, {
keepExistingCapsule: !!opts.keepExistingCapsule
});
})();
} // amit - here we need to add a map of all the capsules so we can link the components
_addComponentsToRoot(opts = {
keepExistingCapsule: false
}) {
var _this9 = this;
return (0, _bluebird().coroutine)(function* () {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const capsulePath = _this9.capsule.container.getPath(); // the capsulePath hack only works for the fs-capsule
// for other capsule types, we would need to do this
// (and other things) inside the capsule itself
// rather than fetching its folder and using it
const rootPathInCapsule = path().join(capsulePath, _this9.componentRootDir);
const componentsToAdd = _this9.componentWithDependencies.allDependencies.reduce((acc, component) => {
// $FlowFixMe - writtenPath is defined
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const componentPathInCapsule = path().join(capsulePath, component.writtenPath);
const relativeDepLocation = path().relative(rootPathInCapsule, componentPathInCapsule);
const locationAsUnixFormat = (0, _packageJsonUtils().convertToValidPathForPackageManager)(relativeDepLocation);
const packageName = (0, _componentIdToPackageName().default)(component.id, component.bindingPrefix, component.defaultScope);
acc[packageName] = locationAsUnixFormat;
return acc;
}, {});
if (_ramda().default.isEmpty(componentsToAdd)) return;
_this9.capsulePackageJson.addDependencies(componentsToAdd);
yield _this9._writeCapsulePackageJson({
keepExistingCapsule: !!opts.keepExistingCapsule
});
})();
}
_writeCapsulePackageJson(opts = {
keepExistingCapsule: false
}) {
var _this10 = this;
return (0, _bluebird().coroutine)(function* () {
const dataToPersist = new (_dataToPersist().default)();
dataToPersist.addFile(_this10.capsulePackageJson.toVinylFile());
return dataToPersist.persistAllToCapsule(_this10.capsule, {
keepExistingCapsule: !!opts.keepExistingCapsule
});
})();
}
_getNpmVersion() {
var _this11 = this;
return (0, _bluebird().coroutine)(function* () {
const {
stdout: versionString
} = yield _this11.capsuleExecUsingExeca('npm', ['--version']);
const validVersion = _semver().default.coerce(versionString);
return validVersion ? validVersion.raw : null;
})();
}
installPackagesOnRoot(modules = []) {
var _this12 = this;
return (0, _bluebird().coroutine)(function* () {
yield _this12._throwForOldNpmVersion();
const args = ['install', ...modules, '--no-save'];
return _this12.capsuleExecUsingExeca('npm', args, _this12.componentRootDir);
})();
}
_throwForOldNpmVersion() {
var _this13 = this;
return (0, _bluebird().coroutine)(function* () {
if (_this13._npmVersionHasValidated) {
return;
}
const npmVersion = yield _this13._getNpmVersion();
if (!npmVersion) {
throw new Error('Failed to isolate component: unable to run npm');
}
if (!_semver().default.satisfies(npmVersion, _constants().ACCEPTABLE_NPM_VERSIONS)) {
throw new (_generalError().default)(`Failed to isolate component: found an old version of npm (${npmVersion}). ` + `To get rid of this error, please upgrade to npm ${_constants().ACCEPTABLE_NPM_VERSIONS}`);
}
_this13._npmVersionHasValidated = true;
})();
}
capsuleExecUsingExeca(pkgManager, args, dir = '') {
var _this14 = this;
return (0, _bluebird().coroutine)(function* () {
const cwd = path().join(_this14.capsule.wrkDir, dir);
return (0, _execa().default)(pkgManager, args, {
cwd
});
})();
}
capsuleExec(cmd, options) {
var _this15 = this;
return (0, _bluebird().coroutine)(function* () {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const execResults = yield _this15.capsule.exec({
command: cmd.split(' '),
options
});
let stdout = '';
let stderr = '';
return new Promise((resolve, reject) => {
execResults.stdout.on('data', data => {
stdout += data;
});
execResults.stdout.on('error', error => {
return reject(error);
}); // @ts-ignore
execResults.on('close', () => {
return resolve({
stdout,
stderr
});
});
execResults.stderr.on('error', error => {
return reject(error);
});
execResults.stderr.on('data', data => {
stderr += data;
});
});
})();
}
/**
* it must be done in this order. first, `npm install`, then, `npm list -j` shows the missing
* peer dependencies, then, add these peerDependencies into devDependencies and run `npm install`
* again. The reason for adding the missing peer into devDependencies is to not get them deleted
* once `npm install` is running along the road.
*/
_installWithPeerOption(installPeerDependencies = true) {
var _this16 = this;
return (0, _bluebird().coroutine)(function* () {
yield _this16.installPackagesOnRoot();
if (installPeerDependencies) {
const peers = yield _this16._getPeerDependencies();
if (!_ramda().default.isEmpty(peers)) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
_this16.capsulePackageJson.packageJsonObject.devDependencies = Object.assign( // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
_this16.capsulePackageJson.packageJsonObject.devDependencies || {}, peers);
yield _this16._writeCapsulePackageJson();
yield _this16.installPackagesOnRoot();
}
}
})();
}
_getPeerDependencies() {
var _this17 = this;
return (0, _bluebird().coroutine)(function* () {
const packageManager = 'npm';
let npmList;
try {
npmList = yield _this17._getNpmListOutput(packageManager);
} catch (err) {
_logger().default.error(`failed running "${packageManager} list -j"`, err);
throw new Error(`failed running "${packageManager} list -j" to find the peer dependencies due to an error: ${err}`);
}
return _npmClient().default.getPeerDepsFromNpmList(npmList, packageManager);
})();
}
_getNpmListOutput(packageManager) {
var _this18 = this;
return (0, _bluebird().coroutine)(function* () {
const args = ['list', '-j'];
try {
const {
stdout,
stderr
} = yield _this18.capsuleExecUsingExeca(packageManager, args, _this18.componentRootDir);
if (stderr && stderr.startsWith('{')) return stderr;
return stdout;
} catch (err) {
if (err.stdout && err.stdout.startsWith('{')) {
// it's probably a valid json with errors, that's fine, parse it.
return err.stdout;
}
_logger().default.error('npm-client got an error', err);
throw new Error(`failed running ${err.cmd} to find the peer dependencies due to an error: ${err.message}`);
}
})();
}
}
exports.default = Isolator;