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

656 lines (486 loc) 17.5 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 _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;