UNPKG

@intuit/judo

Version:

Test command line interfaces.

131 lines (105 loc) 6.53 kB
"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.execute = exports.executePrerequisites = void 0; var _logger = require("./logger"); var _child_process = require("child_process"); var _path = _interopRequireDefault(require("path"));function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };}function ownKeys(object, enumerableOnly) {var keys = Object.keys(object);if (Object.getOwnPropertySymbols) {var symbols = Object.getOwnPropertySymbols(object);if (enumerableOnly) symbols = symbols.filter(function (sym) {return Object.getOwnPropertyDescriptor(object, sym).enumerable;});keys.push.apply(keys, symbols);}return keys;}function _objectSpread(target) {for (var i = 1; i < arguments.length; i++) {var source = arguments[i] != null ? arguments[i] : {};if (i % 2) {ownKeys(Object(source), true).forEach(function (key) {_defineProperty(target, key, source[key]);});} else if (Object.getOwnPropertyDescriptors) {Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));} else {ownKeys(Object(source)).forEach(function (key) {Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));});}}return target;}function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;}function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {reject(error);return;}if (info.done) {resolve(value);} else {Promise.resolve(value).then(_next, _throw);}}function _asyncToGenerator(fn) {return function () {var self = this,args = arguments;return new Promise(function (resolve, reject) {var gen = fn.apply(self, args);function _next(value) {asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);}function _throw(err) {asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);}_next(undefined);});};} /** * Spawns a new process to execute all of the prerequisite commands provided. * @param {Object} params * @param {Array.<String>} params.prerequisites strings of commands to run * @param {String} params.cwd directory to run the prereqs process in */ const executePrerequisites = ({ prerequisites, cwd }) => { return new Promise((resolve, reject) => { _logger.logger.info(`Running prerequisite commands in: ${_path.default.resolve(cwd)}`); const commandsChained = prerequisites.join(' && '); const child = (0, _child_process.exec)(commandsChained, { cwd }); child.stdout.on('data', data => { _logger.logger.logOutput(data.toString()); }); child.stderr.on('data', data => { _logger.logger.logOutput(data.toString()); }); child.on('close', code => { _logger.logger.info('Prerequisites complete'); if (code !== 0) { return reject( new Error(`Failed to run prerequisites, exit code: ${code}`)); } return resolve(); }); }); }; // timeout to cancel execution if no command output is found within time limit exports.executePrerequisites = executePrerequisites;const startNoOutputTimeout = (timeout, commandStr, reject) => setTimeout( () => reject(new Error(`Timeout of ${timeout}ms reached without any command output when running: "${commandStr}"`)), timeout); /** * Spawns a new process to execute a command. Responds to any "when" responses specified in the opts by * sending the response to the new process' stdin. If every "when" is not found, rejects an error, otherwise * resolves. * @param {String} command command to be run * @param {Array.<String>} args args for the command * @param {Object} opts node-pty spawn options, as well as "when" assertions and "timeout" */ const execute = (command, args = [], opts = {}) => { return new Promise( /*#__PURE__*/function () {var _ref = _asyncToGenerator(function* (resolve, reject) { // argString? const commandArgs = opts.argsString || args.join(' '); const commandStr = `${command} ${commandArgs}`; const cwdStr = opts.cwd ? ` in ${_path.default.resolve(opts.cwd)}` : ''; const child = (0, _child_process.spawn)(command, args, _objectSpread(_objectSpread({}, opts), {}, { stdio: ['pipe', 'pipe', 'pipe'] })); _logger.logger.info(`Executing: ${commandStr}${cwdStr}`); let timeoutControl = startNoOutputTimeout(opts.timeout, commandStr, reject); let output = ''; let childInputWrite; const processOutput = data => { clearTimeout(timeoutControl); timeoutControl = startNoOutputTimeout(opts.timeout, commandStr, reject); output += data; if (opts.when) { opts.when.forEach(whenStep => { if ( !childInputWrite && data.indexOf(whenStep.output) !== -1 && !whenStep.done) { whenStep.done = true; // store response to send back to child stdin childInputWrite = whenStep.response + '\r'; } }); } }; child.stdout.on('data', data => { const childData = data.toString(); _logger.logger.logStdout(childData); processOutput(childData); }); child.stderr.on('data', data => { const childData = data.toString(); _logger.logger.logStderr(childData); processOutput(childData); }); // write inputs to child process on an interval, avoids immediate execution race condition const interval = setInterval(() => { if (childInputWrite) { _logger.logger.info(`responding with: ${childInputWrite}`); child.stdin.write(childInputWrite); childInputWrite = ''; } }, 500); // listen for end of process child.on('exit', code => { const numWhenAssertionsComplete = opts.when.filter(w => w.done).length; clearInterval(interval); _logger.logger.info(`exited: ${code}`); if (opts.when && numWhenAssertionsComplete < opts.when.length) { return reject(new Error(`Expected ${opts.when.length} different strings in output from run step "when", encountered ${numWhenAssertionsComplete} expected outputs`)); } return resolve({ output, code }); }); });return function (_x, _x2) {return _ref.apply(this, arguments);};}()); };exports.execute = execute;