UNPKG

ember-cli

Version:

Command line tool for developing ambitious ember.js apps

122 lines (98 loc) 3.02 kB
'use strict'; const chalk = require('chalk'); const spawn = require('child_process').spawn; const defaults = require('lodash/defaults'); const killCliProcess = require('./kill-cli-process'); const logOnFailure = require('./log-on-failure'); let debug = require('heimdalljs-logger')('run-command'); const { captureExit, onExit } = require('capture-exit'); // when running the full test suite, `process.exit` has already been captured // however, when running specific files (e.g. `mocha some/path/to/file.js`) // exit may not be captured before `runCommand` attempts to call `onExit` captureExit(); let RUNS = []; module.exports = function run(/* command, args, options */) { let command = arguments[0]; let args = Array.prototype.slice.call(arguments, 1); let options = {}; if (typeof args[args.length - 1] === 'object') { options = args.pop(); } options = defaults(options, { // If true, pass through stdout/stderr. // If false, only pass through stdout/stderr if the current test fails. verbose: false, onOutput(string) { options.log(string); }, onError(string) { options.log(chalk.red(string)); }, log(string) { debug.debug(string); if (options.verbose) { console.log(string); } else { logOnFailure(string); } }, }); let child; const promise = new Promise(function (resolve, reject) { options.log(` Running: ${command} ${args.join(' ')} in: ${process.cwd()}`); let opts = {}; args = [`--unhandled-rejections=strict`, `${command}`].concat(args); command = 'node'; if (process.platform === 'win32') { opts.windowsVerbatimArguments = true; opts.stdio = [null, null, null, 'ipc']; } if (options.env) { opts.env = defaults(options.env, process.env); } debug.info('runCommand: %s, args: %o', command, args); child = spawn(command, args, opts); RUNS.push(child); // ensure we tear down the child process on exit; onExit(() => killCliProcess(child)); let result = { output: [], errors: [], code: null, }; child.stdout.on('data', function (data) { let string = data.toString(); options.onOutput(string, child); result.output.push(string); }); child.stderr.on('data', function (data) { let string = data.toString(); options.onError(string, child); result.errors.push(string); }); child.on('close', function (code, signal) { result.code = code; result.signal = signal; if (code === 0) { resolve(result); } else { reject(result); } }); }); promise.kill = function () { killCliProcess(child); }; return promise; }; module.exports.killAll = function () { RUNS.forEach((run) => { try { killCliProcess(run); } catch (e) { console.error(e); // during teardown, issues can arise, but teardown must complete it's operation } }); RUNS.length = 0; };