UNPKG

runas-core

Version:

The adhesive orchestrator

185 lines (157 loc) 4.76 kB
'use strict'; const spawn = require('child_process').spawn; const spawnSync = require('child_process').spawnSync; const stream = require('stream'); const logger = require('../logger'); const async = require('async'); const chalk = require('chalk'); const _ = require('lodash'); const launcher = { isWin() { return process.env.OS && process.env.OS.indexOf('Windows') >= 0; }, sh: function(cmdsh, reject, loud) { let result; if (launcher.isWin()) { result = launcher.executeSync('cmd', ['/c', cmdsh], reject, loud); } else { result = launcher.executeSync('sh', ['-c', cmdsh], reject, loud); } return result; }, sudo: function(cmdsh) { let args = ['sh', '-c', cmdsh]; let cmd = 'sudo'; if (launcher.isWin()) { args = ['/c', cmdsh]; cmd = 'cmd'; } return launcher.executeStreamed(cmd, args); }, executeSync: function(cmd, args, reject, loud) { if (cmd !== 'cmd' && cmd !== 'sh') { const patch = launcher._windowsPatch(cmd, args); cmd = patch.cmd; args = patch.args; } logger.trace('#cyan', 'executing', cmd, args); let result; if (loud) { result = spawnSync(cmd, args, { stdio: ['ignore', process.stdout, process.stderr] }); const message = 'WARNING!! Use \'loud=false\' if you want to use stdout or stderr'; result.stdout = message; result.stderr = message; } else { result = spawnSync(cmd, args); } if ((result.error || result.status !== 0) && reject) { reject({ error: result.error, stderr: result.stderr.toString() }); } return result; }, /** * Because of this: https://github.com/nodejs/node-v0.x-archive/issues/2318 * * Fast fix for windows environments * */ _windowsPatch: function(cmd, args) { if (launcher.isWin()) { return { cmd: 'cmd', args: ['/c', cmd].concat(args) }; } return { cmd: cmd, args: args }; }, executeStreamed: function(cmd, args, options) { const patch = launcher._windowsPatch(cmd, args); const _cmd = patch.cmd; const _args = patch.args; if (!options) { options = {}; } if (!options.stdio) { options.stdio = [ process.stdin ]; } let child = spawn(_cmd, _args, options); logger.trace('#cyan', 'executing async', cmd, args, options); return child; }, execute: function(cmd, args, options) { let child = launcher.executeStreamed(cmd, args, options || {}); let error; let command = cmd; let output = ''; const mute = options && options.mute; if (args) { args.forEach((item)=> command += ' ' + item); } child.on('disconnect', () => { logger.info('Child process disconnected!', arguments); }); if (child.stdout) { child.stdout.on('data', (data) => { if (!mute) { logger.out(data.toString()); } output += data.toString(); }); } if (child.stderr) { child.stderr.on('data', (data) => { if (!mute) { logger.err(chalk.red(data.toString())); } error = error ? error : ''; error += data.toString(); }); } child.on('error', (e) => { if (!mute) { logger.error('#red', 'Child process error!', command); } error = e.code; }); child.on('exit', () => { logger.trace('#cyan', command, 'executed'); }); return new Promise((resolve, reject) => { child.on('close', (code) => { logger.trace(command, 'close with code ', code); if (code !== 0) { logger.info('#cyan', command, 'executed:', '#red', 'KO'); reject({cmd: cmd, args: args, options: options, status: code, error: error, output: output}); } else { logger.info('#cyan', command, 'executed:', '#green', 'OK'); resolve({cmd: cmd, args: args, options: options, status: code, output: output, stderr: error}); } }); }); }, executeParallel: function(multiple) { let promises = []; multiple.forEach((exec) => { if (!exec.skip) { promises.push(launcher.execute(exec.cmd, exec.args, exec.options)); } }); return Promise.all(promises); }, executeMassive: function(descriptors, jobs) { return new Promise((ok, ko) => { const errors = []; const process = (pd, cb) => { return launcher.execute(pd.cmd, pd.args, pd.options) .then(() => cb()) .catch(err => { errors.push(err); cb(); }); }; const callback = () => errors.length > 0 ? ko(errors) : ok(); async.eachLimit(descriptors, jobs, process, callback); }); } }; module.exports = launcher;