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
656 lines (486 loc) • 17.5 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 _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 _lodash() {
const data = _interopRequireDefault(require("lodash.uniqby"));
_lodash = function () {
return data;
};
return data;
}
function _object() {
const data = _interopRequireDefault(require("./object"));
_object = function () {
return data;
};
return data;
}
function _rawObject() {
const data = _interopRequireDefault(require("./raw-object"));
_rawObject = function () {
return data;
};
return data;
}
function _ref3() {
const data = _interopRequireDefault(require("./ref"));
_ref3 = 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 _utils() {
const data = require("../../utils");
_utils = function () {
return data;
};
return data;
}
function _fsRemoveFile() {
const data = _interopRequireDefault(require("../../utils/fs-remove-file"));
_fsRemoveFile = function () {
return data;
};
return data;
}
function _scopeMeta() {
const data = _interopRequireDefault(require("../models/scopeMeta"));
_scopeMeta = function () {
return data;
};
return data;
}
function _logger() {
const data = _interopRequireDefault(require("../../logger/logger"));
_logger = function () {
return data;
};
return data;
}
function _componentsIndex() {
const data = _interopRequireDefault(require("./components-index"));
_componentsIndex = function () {
return data;
};
return data;
}
function _objectRegistrar() {
const data = require("../object-registrar");
_objectRegistrar = function () {
return data;
};
return data;
}
function _repositoryHooks() {
const data = require("./repository-hooks");
_repositoryHooks = function () {
return data;
};
return data;
}
const OBJECTS_BACKUP_DIR = `${_constants().OBJECTS_DIR}.bak`;
class Repository {
// @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!
// @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!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
constructor(scopePath, scopeJson, types = _objectRegistrar().typesObj) {
(0, _defineProperty2().default)(this, "objects", {});
(0, _defineProperty2().default)(this, "objectsToRemove", []);
(0, _defineProperty2().default)(this, "scopeJson", void 0);
(0, _defineProperty2().default)(this, "onRead", void 0);
(0, _defineProperty2().default)(this, "onPersist", void 0);
(0, _defineProperty2().default)(this, "scopePath", void 0);
(0, _defineProperty2().default)(this, "types", void 0);
(0, _defineProperty2().default)(this, "componentsIndex", void 0);
(0, _defineProperty2().default)(this, "_cache", {});
this.scopePath = scopePath;
this.scopeJson = scopeJson;
this.types = types;
this.onRead = (0, _repositoryHooks().onRead)(scopePath, scopeJson);
this.onPersist = (0, _repositoryHooks().onPersist)(scopePath, scopeJson);
}
static load({
scopePath,
scopeJson
}) {
return (0, _bluebird().coroutine)(function* () {
const repository = new Repository(scopePath, scopeJson, _objectRegistrar().typesObj);
const componentsIndex = yield repository.loadOptionallyCreateComponentsIndex();
repository.componentsIndex = componentsIndex;
return repository;
})();
}
static create({
scopePath,
scopeJson
}) {
const repository = new Repository(scopePath, scopeJson, _objectRegistrar().typesObj);
const componentsIndex = _componentsIndex().default.create(scopePath);
repository.componentsIndex = componentsIndex;
return repository;
}
static reset(scopePath) {
return _componentsIndex().default.reset(scopePath);
}
static getPathByScopePath(scopePath) {
return path().join(scopePath, _constants().OBJECTS_DIR);
}
ensureDir() {
return _fsExtra().default.ensureDir(this.getPath());
}
getPath() {
return Repository.getPathByScopePath(this.scopePath);
}
getBackupPath(dirName) {
const backupPath = path().join(this.scopePath, OBJECTS_BACKUP_DIR);
return dirName ? path().join(backupPath, dirName) : backupPath;
}
getLicense() {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return this.scopeJson.getPopulatedLicense();
}
getScopeMetaObject() {
return this.getLicense().then(license => _scopeMeta().default.fromObject({
license,
name: this.scopeJson.name
}).compress());
}
objectPath(ref) {
const hash = ref.toString();
return path().join(this.getPath(), hash.slice(0, 2), hash.slice(2));
}
load(ref, throws = false) {
if (this.getCache(ref)) return Promise.resolve(this.getCache(ref)); // @ts-ignore @todo: fix! it should return BitObject | null.
return _fsExtra().default.readFile(this.objectPath(ref)).then(fileContents => {
return this.onRead(fileContents);
}).then(fileContents => {
return _object().default.parseObject(fileContents, this.types);
}).then(parsedObject => {
this.setCache(parsedObject);
return parsedObject;
}).catch(err => {
if (err.code !== 'ENOENT') {
_logger().default.error(`Failed reading a ref file ${this.objectPath(ref)}. Error: ${err.message}`);
throw err;
}
_logger().default.silly(`Failed finding a ref file ${this.objectPath(ref)}.`);
if (throws) throw err;
return null;
});
}
list() {
var _this = this;
return (0, _bluebird().coroutine)(function* () {
const refs = yield _this.listRefs();
return Promise.all(refs.map(ref => _this.load(ref)));
})();
}
listRefs() {
var _this2 = this;
return (0, _bluebird().coroutine)(function* () {
const matches = yield (0, _utils().glob)(path().join('*', '*'), {
cwd: _this2.getPath()
});
const refs = matches.map(str => {
const hash = str.replace(path().sep, '');
return new (_ref3().default)(hash);
});
return refs;
})();
}
listRawObjects() {
var _this3 = this;
return (0, _bluebird().coroutine)(function* () {
const refs = yield _this3.listRefs();
return Promise.all(refs.map( /*#__PURE__*/function () {
var _ref = (0, _bluebird().coroutine)(function* (ref) {
try {
const buffer = yield _this3.loadRaw(ref);
const bitRawObject = yield _rawObject().default.fromDeflatedBuffer(buffer, ref.hash, _this3.types);
return bitRawObject;
} catch (err) {
_logger().default.error(`Couldn't load the ref ${ref} this object is probably corrupted and should be delete`);
return null;
}
});
return function (_x) {
return _ref.apply(this, arguments);
};
}()));
})();
}
listComponentsIncludeSymlinks() {
var _this4 = this;
return (0, _bluebird().coroutine)(function* () {
const hashes = _this4.componentsIndex.getHashesIncludeSymlinks();
return _this4._getBitObjectsByHashes(hashes);
})();
}
listComponents() {
var _this5 = this;
return (0, _bluebird().coroutine)(function* () {
const hashes = _this5.componentsIndex.getHashes();
return _this5._getBitObjectsByHashes(hashes);
})();
}
_getBitObjectsByHashes(hashes) {
var _this6 = this;
return (0, _bluebird().coroutine)(function* () {
const bitObjects = yield Promise.all(hashes.map( /*#__PURE__*/function () {
var _ref2 = (0, _bluebird().coroutine)(function* (hash) {
const bitObject = yield _this6.load(new (_ref3().default)(hash));
if (!bitObject) {
const componentId = _this6.componentsIndex.getIdByHash(hash);
const indexJsonPath = _this6.componentsIndex.getPath();
if (_this6.componentsIndex.isFileOnBitHub()) {
_logger().default.error(`repository._getBitObjectsByHashes, indexJson at "${indexJsonPath}" is outdated and needs to be deleted`);
return null;
}
yield _this6.componentsIndex.deleteFile(); // $FlowFixMe componentId must be set as it was retrieved from indexPath before
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
throw new (_exceptions().OutdatedIndexJson)(componentId, indexJsonPath);
}
return bitObject;
});
return function (_x2) {
return _ref2.apply(this, arguments);
};
}())); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return bitObjects.filter(b => b); // remove nulls;
})();
}
loadOptionallyCreateComponentsIndex() {
var _this7 = this;
return (0, _bluebird().coroutine)(function* () {
try {
const componentsIndex = yield _componentsIndex().default.load(_this7.scopePath);
return componentsIndex;
} catch (err) {
if (err.code === 'ENOENT') {
const bitObjects = yield _this7.list();
const componentsIndex = _componentsIndex().default.create(_this7.scopePath);
componentsIndex.addMany(bitObjects);
yield componentsIndex.write();
return componentsIndex;
}
throw err;
}
})();
}
loadRaw(ref) {
var _this8 = this;
return (0, _bluebird().coroutine)(function* () {
const raw = yield _fsExtra().default.readFile(_this8.objectPath(ref)); // Run hook to transform content pre reading
const transformedContent = _this8.onRead(raw);
return transformedContent;
})();
}
loadRawObject(ref) {
var _this9 = this;
return (0, _bluebird().coroutine)(function* () {
const buffer = yield _this9.loadRaw(ref);
const bitRawObject = yield _rawObject().default.fromDeflatedBuffer(buffer, ref.hash, _this9.types);
return bitRawObject;
})();
}
/**
* prefer using `this.load()` for an async version, which also writes to the cache
*/
loadSync(ref, throws = true) {
try {
const objectFile = _fsExtra().default.readFileSync(this.objectPath(ref)); // Run hook to transform content pre reading
const transformedContent = this.onRead(objectFile);
return _object().default.parseSync(transformedContent, this.types);
} catch (err) {
if (throws) {
throw new (_exceptions().HashNotFound)(ref.toString());
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return null;
}
}
setCache(object) {
this._cache[object.hash().toString()] = object;
return this;
}
getCache(ref) {
return this._cache[ref.toString()];
}
removeFromCache(ref) {
delete this._cache[ref.toString()];
}
backup(dirName) {
const backupDir = this.getBackupPath(dirName);
const objectsDir = this.getPath();
_logger().default.debug(`making a backup of all objects from ${objectsDir} to ${backupDir}`);
_fsExtra().default.emptyDirSync(backupDir);
_fsExtra().default.copySync(objectsDir, backupDir);
}
add(object) {
if (!object) return this; // leave the following commented log message, it is very useful for debugging but too verbose when not needed.
// logger.debug(`repository: adding object ${object.hash().toString()} which consist of the following id: ${object.id()}`);
this.objects[object.hash().toString()] = object;
this.setCache(object);
return this;
}
addMany(objects) {
if (!objects || !objects.length) return this;
objects.forEach(obj => this.add(obj));
return this;
}
removeObject(ref) {
this.objectsToRemove.push(ref);
}
removeManyObjects(refs) {
if (!refs || !refs.length) return;
refs.forEach(ref => this.removeObject(ref));
}
findMany(refs) {
return Promise.all(refs.map(ref => this.load(ref)));
}
/**
* persist objects changes (added and removed) into the filesystem
* do not call this function multiple times in parallel, otherwise, it'll damage the index.json file.
* call this function only once after you added and removed all applicable objects.
*/
persist(validate = true) {
var _this10 = this;
return (0, _bluebird().coroutine)(function* () {
_logger().default.debug(`Repository.persist, validate = ${validate.toString()}`);
yield _this10._deleteMany();
_this10._validateObjects(validate);
yield _this10._writeMany();
})();
}
/**
* normally, the validation step takes place just before the acutal writing of the file.
* however, this can be an issue where a component has an invalid version. the component could
* be saved before validating the version (see #1727). that's why we validate here before writing
* anything to the filesystem.
* the open question here is whether should we validate again before the actual writing or it
* should be enough to validate here?
* for now, it does validate again before saving, only to be 100% sure nothing happens in a few
* lines of code until the actual writing. however, if the performance penalty is noticeable, we
* can easily revert it by changing `bitObject.validateBeforePersist = false` line run regardless
* the `validate` argument.
*/
_validateObjects(validate) {
Object.keys(this.objects).forEach(hash => {
const bitObject = this.objects[hash]; // @ts-ignore some BitObject classes have validate() method
if (validate && bitObject.validate) {
// @ts-ignore
bitObject.validate();
}
if (!validate) {
bitObject.validateBeforePersist = false;
}
});
}
_deleteMany() {
var _this11 = this;
return (0, _bluebird().coroutine)(function* () {
if (!_this11.objectsToRemove.length) return;
const uniqRefs = (0, _lodash().default)(_this11.objectsToRemove, 'hash');
_logger().default.debug(`Repository._deleteMany: deleting ${uniqRefs.length} objects`);
yield Promise.all(uniqRefs.map(ref => _this11._deleteOne(ref)));
const removed = _this11.componentsIndex.removeMany(uniqRefs);
if (removed) yield _this11.componentsIndex.write();
})();
}
_writeMany() {
var _this12 = this;
return (0, _bluebird().coroutine)(function* () {
if (_ramda().default.isEmpty(_this12.objects)) return;
_logger().default.debug(`Repository._writeMany: writing ${Object.keys(_this12.objects).length} objects`); // @TODO handle failures
yield Promise.all(Object.keys(_this12.objects).map(hash => _this12._writeOne(_this12.objects[hash])));
const added = _this12.componentsIndex.addMany(_ramda().default.values(_this12.objects));
if (added) yield _this12.componentsIndex.write();
})();
}
/**
* do not call this method directly. always call this.removeObject() and once done with all objects,
* call this.persist()
*/
_deleteOne(ref) {
this.removeFromCache(ref);
const pathToDelete = this.objectPath(ref);
_logger().default.silly(`repository._deleteOne: deleting ${pathToDelete}`);
return (0, _fsRemoveFile().default)(pathToDelete, true);
}
/**
* always prefer this.persist().
* this method doesn't write to componentsIndex. so using this method for ModelComponent or
* Symlink makes the index outdated.
*/
_writeOne(object) {
var _this13 = this;
return (0, _bluebird().coroutine)(function* () {
const contents = yield object.compress();
const options = {}; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (_this13.scopeJson.groupName) options.gid = yield (0, _utils().resolveGroupId)(_this13.scopeJson.groupName);
const objectPath = _this13.objectPath(object.hash());
_logger().default.silly(`repository._writeOne: ${objectPath}`); // Run hook to transform content pre persisting
const transformedContent = _this13.onPersist(contents); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return (0, _utils().writeFile)(objectPath, transformedContent, options);
})();
}
}
exports.default = Repository;
;