UNPKG

cli-engine

Version:
195 lines (158 loc) 4.97 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); require('cli-engine-config'); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _yarn = require('./yarn'); var _yarn2 = _interopRequireDefault(_yarn); var _klawSync = require('klaw-sync'); var _klawSync2 = _interopRequireDefault(_klawSync); var _fsExtra = require('fs-extra'); var _fsExtra2 = _interopRequireDefault(_fsExtra); var _manager = require('./manager'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function touch(f) { _fsExtra2.default.utimesSync(f, new Date(), new Date()); } class LinkedPlugins extends _manager.Manager { constructor({ out, config, cache }) { super({ out, config, cache }); try { this._data = _fsExtra2.default.readJSONSync(this.file); this._data.updated_at = new Date(this._data.updated_at || 0); } catch (err) { if (err.code !== 'ENOENT') throw err; this._data = { version: '1', updated_at: new Date(), plugins: [] }; } } /** * adds a linked plugin * @param {string} p - path of plugin */ async add(p) { if (!this.config.debug) this.out.action.start(`Running prepare script for ${p}`); await this.prepare(p); let m = require(p); if (!m.commands) throw new Error(`${p} does not appear to be a CLI plugin`); this._data.plugins.push(p); this._save(); this.out.action.stop(); } /** * removes a linked plugin * @param {string} p - path of plugin */ remove(p) { this._data.plugins = this._data.plugins.filter(q => q !== p); this._save(); } /** * list linked plugins * @returns {PluginPath[]} */ async list() { try { await this.load(); return this._data.plugins.map(p => { return new _manager.PluginPath({ output: this.out, type: 'link', path: p }); }); } catch (err) { this.out.warn(err, 'Error loading linked plugins'); return []; } } async load() { if (this.loaded) return; await this.refresh(); this.loaded = true; } /** * runs prepare() on all linked plugins */ async refresh() { let paths = []; for (let plugin of this._data.plugins) { try { if (await this.prepare(plugin)) { paths.push(plugin); } } catch (err) { this.out.warn(`Error refreshing ${plugin}`); this.out.warn(err); } } if (paths.length > 0) { this.cache.deletePlugin(...paths); this._data.updated_at = new Date(); this._save(); } } /** * installs plugin dependencies and runs npm prepare if needed */ async prepare(p) { let pjson = this._pjson(p); await this._install(p); if (!pjson.main) throw new Error(`No main script specified in ${_path2.default.join(p, 'package.json')}`); let main = _path2.default.join(p, pjson.main); if (!this._needsPrepare(p, main)) return false; if (pjson.scripts && pjson.scripts.prepare) { if (!this.config.debug) this.out.action.start(`Running prepare script for ${p}`); let yarn = new _yarn2.default(this.out, p); await yarn.exec(['run', 'prepare']); this.out.action.stop(); } return true; } _save() { _fsExtra2.default.outputJsonSync(this.file, this._data, { spaces: 2 }); } _needsInstall(p) { let modules = _path2.default.join(p, 'node_modules'); if (!_fsExtra2.default.existsSync(modules)) return true; let modulesInfo = _fsExtra2.default.statSync(modules); let pjsonInfo = _fsExtra2.default.statSync(_path2.default.join(p, 'package.json')); return modulesInfo.mtime < pjsonInfo.mtime; } _needsPrepare(p, main) { if (!_fsExtra2.default.existsSync(main)) return true; return !!(0, _klawSync2.default)(p, { noRecurseOnFailedFilter: true, filter: f => !['.git', 'node_modules', 'flow-typed'].includes(_path2.default.basename(f.path)) }).filter(f => f.path.endsWith('.js')).find(f => f.stats.mtime > this._data.updated_at); } async _install(p, force = false) { if (!force && !this._needsInstall(p)) return; if (!this.config.debug) this.out.action.start(`Installing dependencies for ${p}`); let yarn = new _yarn2.default(this.out, p); await yarn.exec(); touch(_path2.default.join(p, 'node_modules')); this.out.action.stop(); } async handleNodeVersionChange() { for (let p of this._data.plugins) { try { await this._install(p, true); } catch (err) { this.out.warn(err); } } } checkLinked(p) { if (this._data.plugins.includes(p)) throw new Error(`${p} is already linked`); return this._pjson(p).name; } _pjson(p) { return require(_path2.default.join(p, 'package.json')); } get file() { return _path2.default.join(this.config.dataDir, 'linked_plugins.json'); } } exports.default = LinkedPlugins;