UNPKG

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
"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;