UNPKG

@atomist/automation-client

Version:
150 lines 5.92 kB
"use strict"; /* * Copyright © 2018 Atomist, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const spawn = require("cross-spawn"); const path = require("path"); const sprintf_js_1 = require("sprintf-js"); const strip_ansi = require("strip-ansi"); const logger_1 = require("../internal/util/logger"); /** * Default ErrorFinder that regards return code 0 as success * @param {number} code * @return {boolean} * @constructor */ exports.SuccessIsReturn0ErrorFinder = code => code !== 0; /** * Spawn a process and watch * @param {SpawnCommand} spawnCommand * @param options options * @param {ProgressLog} log * @param {Partial<SpawnWatchOptions>} spOpts * @return {Promise<ChildProcessResult>} */ function spawnAndWatch(spawnCommand, options, log, spOpts = {}) { return __awaiter(this, void 0, void 0, function* () { const childProcess = spawn(spawnCommand.command, spawnCommand.args || [], options); if (spOpts.logCommand === false) { logger_1.logger.debug(`${options.cwd || path.resolve(".")} > ${stringifySpawnCommand(spawnCommand)} (pid '${childProcess.pid}')`); } else { log.write(`/--\n`); log.write(`${options.cwd || path.resolve(".")} > ${stringifySpawnCommand(spawnCommand)} (pid '${childProcess.pid}')\n`); log.write(`\\--\n`); } return watchSpawned(childProcess, log, spOpts); }); } exports.spawnAndWatch = spawnAndWatch; /** * Handle the result of a spawned process, streaming back * output to log * @param childProcess * @param {ProgressLog} log to write stdout and stderr to * @param opts: Options for error parsing, ANSI code stripping etc. * @return {Promise<ChildProcessResult>} */ function watchSpawned(childProcess, log, opts = {}) { let timer; let running = true; if (opts.timeout) { timer = setTimeout(() => { if (running) { logger_1.logger.warn("Spawn timeout expired. Killing command with pid '%s'", childProcess.pid); childProcess.kill(); } }, opts.timeout); } return new Promise((resolve, reject) => { const optsToUse = Object.assign({ errorFinder: exports.SuccessIsReturn0ErrorFinder, stripAnsi: false }, opts); if (!optsToUse.errorFinder) { // The caller specified undefined, which is an error. Ignore them, for they know not what they do. optsToUse.errorFinder = exports.SuccessIsReturn0ErrorFinder; } function sendToLog(data) { const formatted = optsToUse.stripAnsi ? strip_ansi(data.toString()) : data.toString(); return log.write(formatted); } childProcess.stdout.on("data", sendToLog); childProcess.stderr.on("data", sendToLog); childProcess.addListener("exit", (code, signal) => { running = false; logger_1.logger.info("Spawn exit with pid '%d': code '%d', signal '%d'", childProcess.pid, code, signal); clearTimeout(timer); resolve({ error: optsToUse.errorFinder(code, signal, log), code, childProcess, }); }); childProcess.addListener("error", err => { running = false; // Process could not be spawned or killed logger_1.logger.warn("Spawn failure: %s", err); clearTimeout(timer); reject(err); }); }); } /** * toString for a SpawnCommand. Used for logging. * @param {SpawnCommand} sc * @return {string} */ function stringifySpawnCommand(sc) { return sprintf_js_1.sprintf("%s %s", sc.command, !!sc.args ? sc.args.join(" ") : ""); } exports.stringifySpawnCommand = stringifySpawnCommand; /** * Convenient function to create a spawn command from a sentence such as "npm run compile" * Does not respect quoted arguments * @param {string} sentence * @param options * @return {SpawnCommand} */ function asSpawnCommand(sentence, options = {}) { const split = sentence.split(" "); return { command: split[0], args: split.slice(1), options, }; } exports.asSpawnCommand = asSpawnCommand; /** * Kill the child process and wait for it to shut down. This can take a while as child processes * may have shut down hooks. * @param {module:child_process.ChildProcess} childProcess * @return {Promise<any>} */ function poisonAndWait(childProcess) { childProcess.kill(); return new Promise((resolve, reject) => childProcess.on("close", () => { resolve(); })); } exports.poisonAndWait = poisonAndWait; //# sourceMappingURL=spawned.js.map