UNPKG

openframe

Version:

Openframe controller process which runs on the machine controlling the frame.

202 lines (183 loc) 6.18 kB
var debug = require('debug')('openframe:extensions_manager'), execFile = require('child_process').execFile, exec = require('child_process').exec, requireg = require('requireg'), config = require('./config'), ext_man = module.exports = {}; /** * Install extensions. * * TODO: since we're just running npm cli via exec(), any reason not to install * all extensions at once instead of one at a time? * * @param {object} extensions A hash of extensions to install * @param {Boolean} force Install the extensions even if it's already installed (skip the check) * @return {Promise} A promise resolved with all of the npmi results for each extensions */ ext_man.installExtensions = function(extensions, force) { debug('installExtensions'); var promises = [], key, _force = force === true ? true : false; // install each extensions for (key in extensions) { if (extensions.hasOwnProperty(key)) { promises.push(_installExtension(key, extensions[key], _force)); } } return Promise.all(promises); }; /** * Initialize extensions. * * @param {String} extensions * @param {Object} ofExtensionApi An interface to the frame provided to each extensions */ ext_man.initExtensions = function(extensions, ofExtensionApi) { debug('initExtensions', extensions); var promises = [], key; return new Promise((resolve, reject) => { // add each extensions to package.json for (key in extensions) { if (extensions.hasOwnProperty(key)) { promises.push(_initExtension(key, ofExtensionApi)); } } Promise.all(promises) .then(resolve) .catch(resolve); }); }; /** * Install a single extension via NPM * * Uses machine's npm as a child_process so that we don't have to depend on the npm package. * * @private * * @param {String} package_name NPM package name * @param {String} version NPM package version (or repo URL for extensions not in NPM) * @param {Boolean} force Install the extension even if it's already installed (skip the check) * @return {Promise} A promise resolving with the package_name */ function _installExtension(package_name, version, force) { debug('installExtension', package_name, version); var cmd = 'npm install -g ' + package_name; if (version) { cmd += '@'+version; } cmd += ' --save'; return new Promise((resolve, reject) => { if (force) { _runNpmCommand(cmd).then(function() { resolve(package_name); }); } else { _checkExtension(package_name, version).then(function(is_installed) { if (!is_installed) { // only install if it's not already installed. _runNpmCommand(cmd).then(function() { resolve(package_name); }).catch(function(err) { debug('Could not install', package_name, version); reject(err); }); } else { // otherwise just resolve resolve(package_name); } }); } }); } // public exposure ext_man.installExtension = _installExtension; /** * Removes a single extensions by removing it from the npm package. * * @param {String} package_name NPM package name * @return {Promise} A promise resolving with the package_name */ function _removeExtension(package_name) { debug('removeExtension', package_name); var cmd = 'npm remove -g ' + package_name; cmd += ' --save'; return new Promise((resolve, reject) => { _runNpmCommand(cmd).then(function() { resolve(package_name); }).catch(reject); }); } // public exposure ext_man.uninstallExtension = _removeExtension; /** * Check whether a extension is already installed. * * @param {String} package_name NPM package name * @param {String} version NPM package version (or repo URL for extensions not in NPM) * @return {Promise} A promise resolving with either true (extensions installed) or false (extensions not installed) */ function _checkExtension(package_name, version) { debug('checkExtension', package_name, version); var cmd = 'npm list -g ' + package_name; if (version) { cmd += '@'+version; } return new Promise((resolve, reject) => { _runNpmCommand(cmd) .then(function() { debug('extensions installed'); resolve(true); }).catch(function() { debug('extensions NOT installed'); resolve(false); }); }); } /** * Initialize a single extensions. * * If the extensions has an install.sh file, execute it. Then call the extensions's init method * passing in a reference to the frame controller. * * TODO: initialize extensions with sandboxed API? * - addFormat * - installDeps (?) * * TODO: should install.sh execute as part of NPM install? * * @private * * @param {String} extensions_name * @param {Object} ofExtensionApi An interface to the frame provided to each extensions * @return {Promise} */ function _initExtension(extensions_name, ofExtensionApi) { debug('_initExtension', extensions_name); var extensions; return new Promise((resolve, reject) => { try { extensions = requireg(extensions_name, true); // Make sure to check for installed extensions globally and skip local packages extensions._init(ofExtensionApi); resolve(extensions); } catch (e) { // problem trying to require extensions debug('ERROR - ', e); reject(e); } }); } function _runNpmCommand(cmd) { return new Promise((resolve, reject) => { exec(cmd, (err, stdout, stderr) => { debug(`stdout: ${stdout}`); debug(`stderr: ${err}`); if (err) { reject(err); } else { resolve(); } }); }); }