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