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

666 lines (534 loc) 21.1 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 _constants() { const data = require("../../constants"); _constants = function () { return data; }; return data; } function _exceptions() { const data = require("../exceptions"); _exceptions = function () { return data; }; return data; } function _models() { const data = require("../models"); _models = function () { return data; }; return data; } function globalConfig() { const data = _interopRequireWildcard(require("../../api/consumer/lib/global-config")); globalConfig = function () { return data; }; return data; } function _logger() { const data = _interopRequireDefault(require("../../logger/logger")); _logger = function () { return data; }; return data; } function _path() { const data = require("../../utils/path"); _path = function () { return data; }; return data; } function _manipulateDir() { const data = require("../../consumer/component-ops/manipulate-dir"); _manipulateDir = function () { return data; }; return data; } function _artifact() { const data = require("../../consumer/component/sources/artifact"); _artifact = function () { return data; }; return data; } class SourceRepository { constructor(scope) { (0, _defineProperty2().default)(this, "scope", void 0); this.scope = scope; } objects() { return this.scope.objects; } getMany(ids) { _logger().default.debug(`sources.getMany, Ids: ${ids.join(', ')}`); return Promise.all(ids.map(id => { return this.get(id).then(component => { return { id, component }; }); })); } get(bitId) { var _this = this; return (0, _bluebird().coroutine)(function* () { const component = _models().ModelComponent.fromBitId(bitId); const foundComponent = yield _this._findComponent(component); if (foundComponent && bitId.hasVersion()) { const msg = `found ${bitId.toStringWithoutVersion()}, however version ${bitId.getVersion().versionNum}`; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! if (!foundComponent.versions[bitId.version]) { _logger().default.debugAndAddBreadCrumb('sources.get', `${msg} is not in the component versions array`); return undefined; } // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const version = yield _this.objects().load(foundComponent.versions[bitId.version]); if (!version) { _logger().default.debugAndAddBreadCrumb('sources.get', `${msg} object was not found on the filesystem`); return undefined; } } return foundComponent; })(); } _findComponent(component) { var _this2 = this; return (0, _bluebird().coroutine)(function* () { try { const foundComponent = yield _this2.objects().load(component.hash()); if (foundComponent instanceof _models().Symlink) { return _this2._findComponentBySymlink(foundComponent); } // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! if (foundComponent) return foundComponent; } catch (err) { _logger().default.error(`findComponent got an error ${err}`); } _logger().default.debug(`failed finding a component ${component.id()} with hash: ${component.hash().toString()}`); return undefined; })(); } _findComponentBySymlink(symlink) { var _this3 = this; return (0, _bluebird().coroutine)(function* () { const realComponentId = symlink.getRealComponentId(); const realModelComponent = _models().ModelComponent.fromBitId(realComponentId); const foundComponent = yield _this3.objects().load(realModelComponent.hash()); if (!foundComponent) { throw new Error(`error: found a symlink object "${symlink.id()}" that references to a non-exist component "${realComponentId.toString()}". if you have the steps to reproduce the issue, please open a Github issue with the details. to quickly fix the issue, please delete the object at "${_this3.objects().objectPath(symlink.hash())}"`); } // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! return foundComponent; })(); } getObjects(id) { return this.get(id).then(component => { if (!component) throw new (_exceptions().ComponentNotFound)(id.toString()); return component.collectObjects(this.objects()); }); } findOrAddComponent(props) { const comp = _models().ModelComponent.from(props); return this._findComponent(comp).then(component => { if (!component) return comp; return component; }); } modifyCIProps({ source, ciProps }) { const objectRepo = this.objects(); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! return this.findOrAddComponent(source).then(component => { return component.loadVersion(component.latest(), objectRepo).then(version => { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! version.setCIProps(ciProps); return objectRepo._writeOne(version); }); }); } modifySpecsResults({ source, specsResults }) { const objectRepo = this.objects(); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! return this.findOrAddComponent(source).then(component => { return component.loadVersion(component.latest(), objectRepo).then(version => { version.setSpecsResults(specsResults); return objectRepo._writeOne(version); }); }); } // TODO: This should treat dist as an array updateDist({ source }) { const objectRepo = this.objects(); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! return this.findOrAddComponent(source).then(component => { return component.loadVersion(component.latest(), objectRepo).then(version => { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const dist = source.dist ? _models().Source.from(Buffer.from(source.dist.toString())) : undefined; version.setDist(dist); objectRepo.add(dist).add(version); return objectRepo.persist(); }); }); } /** * given a consumer-component object, returns the Version representation. * useful for saving into the model or calculation the hash for comparing with other Version object. * among other things, it reverts the path manipulation that was done when a component was loaded * from the filesystem. it adds the originallySharedDir and strip the wrapDir. * * warning: Do not change anything on the consumerComponent instance! Only use its clone. * * @see model-components.toConsumerComponent() for the opposite action. (converting Version to * ConsumerComponent). */ consumerComponentToVersion({ consumerComponent, consumer, message, flattenedDependencies, flattenedDevDependencies, specsResults }) { return (0, _bluebird().coroutine)(function* () { const clonedComponent = consumerComponent.clone(); const setEol = files => { if (!files) return null; const result = files.map(file => { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! file.file = file.toSourceAsLinuxEOL(); return file; }); return result; }; const manipulateDirs = pathStr => { return (0, _manipulateDir().revertDirManipulationForPath)(pathStr, clonedComponent.originallySharedDir, clonedComponent.wrapDir); }; const files = consumerComponent.files.map(file => { return { name: file.basename, relativePath: manipulateDirs(file.relative), file: file.toSourceAsLinuxEOL(), test: file.test }; }); // @todo: is this the best way to find out whether a compiler is set? const isCompileSet = Boolean(consumerComponent.compiler || clonedComponent.extensions.some(e => e.name === 'compile' || e.name === 'bit.core/compile' || e.name === '@teambit/envs')); const { dists, mainDistFile } = clonedComponent.dists.toDistFilesModel(consumer, consumerComponent.originallySharedDir, isCompileSet); const artifacts = []; const extensions = clonedComponent.extensions.clone(); extensions.forEach(extensionDataEntry => { const artifactsSource = extensionDataEntry.artifacts.map(artifact => { if (!(artifact instanceof _artifact().Artifact)) { throw new Error(`sources: expect artifact to by Vinyl at this point, got ${artifact}`); } return { relativePath: (0, _path().pathNormalizeToLinux)(artifact.relative), file: artifact.toSourceAsLinuxEOL() }; }); artifacts.push(...artifactsSource); extensionDataEntry.artifacts = artifactsSource; }); const compilerFiles = setEol(_ramda().default.path(['compiler', 'files'], consumerComponent)); const testerFiles = setEol(_ramda().default.path(['tester', 'files'], consumerComponent)); const [username, email] = yield Promise.all([globalConfig().get(_constants().CFG_USER_NAME_KEY), globalConfig().get(_constants().CFG_USER_EMAIL_KEY)]); clonedComponent.mainFile = manipulateDirs(clonedComponent.mainFile); clonedComponent.getAllDependencies().forEach(dependency => { // ignoreVersion because when persisting the tag is higher than currently exist in .bitmap const depFromBitMap = consumer.bitMap.getComponentIfExist(dependency.id, { ignoreVersion: true }); dependency.relativePaths.forEach(relativePath => { if (!relativePath.isCustomResolveUsed) { // for isCustomResolveUsed it was never stripped relativePath.sourceRelativePath = manipulateDirs(relativePath.sourceRelativePath); } if (depFromBitMap && depFromBitMap.origin !== _constants().COMPONENT_ORIGINS.AUTHORED) { // when a dependency is not authored, we need to also change the // destinationRelativePath, which is the path written in the link file, however, the // dir manipulation should be according to this dependency component, not the // consumerComponent passed to this function relativePath.destinationRelativePath = (0, _manipulateDir().revertDirManipulationForPath)(relativePath.destinationRelativePath, depFromBitMap.originallySharedDir, depFromBitMap.wrapDir); } }); }); clonedComponent.overrides.addOriginallySharedDir(clonedComponent.originallySharedDir); const version = _models().Version.fromComponent({ component: clonedComponent, files: files, dists, // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! mainDistFile, // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! flattenedDependencies, // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! flattenedDevDependencies, specsResults, extensions, // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! message, username, email }); // $FlowFixMe it's ok to override the pendingVersion attribute consumerComponent.pendingVersion = version; // helps to validate the version against the consumer-component return { version, files, dists, compilerFiles, testerFiles, artifacts }; })(); } addSource({ source, consumer, flattenedDependencies, flattenedDevDependencies, message, specsResults }) { var _this4 = this; return (0, _bluebird().coroutine)(function* () { const objectRepo = _this4.objects(); // if a component exists in the model, add a new version. Otherwise, create a new component on the model // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const component = yield _this4.findOrAddComponent(source); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! const { version, files, dists, compilerFiles, testerFiles, artifacts } = yield _this4.consumerComponentToVersion({ consumerComponent: source, consumer, message, flattenedDependencies, flattenedDevDependencies, specsResults }); if (source.version) { component.addVersion(version, source.version); } objectRepo.add(version).add(component); files.forEach(file => objectRepo.add(file.file)); if (dists) dists.forEach(dist => objectRepo.add(dist.file)); if (compilerFiles) compilerFiles.forEach(file => objectRepo.add(file.file)); if (testerFiles) testerFiles.forEach(file => objectRepo.add(file.file)); if (artifacts) artifacts.forEach(file => objectRepo.add(file.file)); return component; })(); } putAdditionalVersion(component, version, message, versionToAdd) { var _this5 = this; return (0, _bluebird().coroutine)(function* () { const [username, email] = yield Promise.all([globalConfig().get(_constants().CFG_USER_NAME_KEY), globalConfig().get(_constants().CFG_USER_EMAIL_KEY)]); version.log = { message, username, email, date: Date.now().toString() }; component.addVersion(version, versionToAdd); return _this5.put({ component, objects: [version] }); })(); } put({ component, objects }) { _logger().default.debug(`sources.put, id: ${component.id()}, versions: ${component.listVersions().join(', ')}`); const repo = this.objects(); repo.add(component); const isObjectShouldBeAdded = obj => { // don't add a component if it's already exist locally with more versions if (obj instanceof _models().ModelComponent) { const loaded = repo.loadSync(obj.hash(), false); if (loaded) { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! if (Object.keys(loaded.versions) > Object.keys(obj.versions)) { return false; } } } return true; }; objects.forEach(obj => { if (isObjectShouldBeAdded(obj)) repo.add(obj); }); return component; } /** * remove specified component versions from component. * if all versions of a component were deleted, delete also the component. * it doesn't persist anything to the filesystem. * (repository.persist() needs to be called at the end of the operation) */ removeComponentVersions(component, versions) { _logger().default.debug(`removeComponentVersion, component ${component.id()}, versions ${versions.join(', ')}`); const objectRepo = this.objects(); versions.forEach(version => { const ref = component.removeVersion(version); objectRepo.removeObject(ref); }); if (component.versionArray.length) { objectRepo.add(component); // add the modified component object } else { // if all versions were deleted, delete also the component itself from the model objectRepo.removeObject(component.hash()); } } /** * @see this.removeComponent() * */ removeComponentById(bitId) { var _this6 = this; return (0, _bluebird().coroutine)(function* () { _logger().default.debug(`sources.removeComponentById: ${bitId.toString()}`); const component = yield _this6.get(bitId); if (!component) return; _this6.removeComponent(component); })(); } /** * remove all versions objects of the component from local scope. * if deepRemove is true, it removes also the refs associated with the removed versions. * finally, it removes the component object itself * it doesn't physically delete from the filesystem. * the actual delete is done at a later phase, once Repository.persist() is called. * * @param {ModelComponent} component * @param {boolean} [deepRemove=false] - whether remove all the refs or only the version array */ removeComponent(component) { const repo = this.objects(); _logger().default.debug(`sources.removeComponent: removing a component ${component.id()} from a local scope`); const objectRefs = component.versionArray; objectRefs.push(component.hash()); repo.removeManyObjects(objectRefs); } /** * merge the existing component with the data from the incoming component * here, we assume that there is no conflict between the two, otherwise, this.merge() would throw * a MergeConflict exception. */ mergeTwoComponentsObjects(existingComponent, incomingComponent) { // the base component to save is the existingComponent because it might contain local data that // is not available in the remote component, such as the "state" property. const mergedComponent = existingComponent; const mergedVersions = []; // in case the existing version hash is different than incoming version hash, use the incoming // version because we hold the incoming component from a remote as the source of truth Object.keys(existingComponent.versions).forEach(existingVersion => { if (incomingComponent.versions[existingVersion] && existingComponent.versions[existingVersion].toString() !== incomingComponent.versions[existingVersion].toString()) { mergedComponent.versions[existingVersion] = incomingComponent.versions[existingVersion]; mergedVersions.push(existingVersion); } }); // in case the incoming component has versions that are not in the existing component, copy them Object.keys(incomingComponent.versions).forEach(incomingVersion => { if (!existingComponent.versions[incomingVersion]) { mergedComponent.versions[incomingVersion] = incomingComponent.versions[incomingVersion]; mergedVersions.push(incomingVersion); } }); return { mergedComponent, mergedVersions }; } /** * Adds the objects into scope.object array, in-memory. It doesn't save anything to the file-system. * * When this function gets called originally from import command, the 'local' parameter is true. Otherwise, if it was * originated from export command, it'll be false. * If the 'local' is true and the existing component wasn't changed locally, it doesn't check for * discrepancies, but simply override the existing component. * In this context, "discrepancy" means, same version but different hashes. * When using import command, it makes sense to override a component in case of discrepancies because the source of * truth should be the remote scope from where the import fetches the component. * When the same component has different versions in the remote and the local, it merges the two * by calling this.mergeTwoComponentsObjects(). */ merge({ component, objects }, inScope = false, local = true) { var _this7 = this; return (0, _bluebird().coroutine)(function* () { if (inScope) component.scope = _this7.scope.name; const existingComponent = yield _this7._findComponent(component); if (!existingComponent) { _this7.put({ component, objects }); return { mergedComponent: component, mergedVersions: component.listVersions() }; } const locallyChanged = existingComponent.isLocallyChanged(); if (local && !locallyChanged || component.compatibleWith(existingComponent, local)) { _logger().default.debug(`sources.merge component ${component.id()}`); const { mergedComponent, mergedVersions } = _this7.mergeTwoComponentsObjects(existingComponent, component); _this7.put({ component: mergedComponent, objects }); return { mergedComponent, mergedVersions }; } const conflictVersions = component.diffWith(existingComponent, local); throw new (_exceptions().MergeConflict)(component.id(), conflictVersions); })(); } } exports.default = SourceRepository;