123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- // Licensed to the Software Freedom Conservancy (SFC) under one
- // or more contributor license agreements. See the NOTICE file
- // distributed with this work for additional information
- // regarding copyright ownership. The SFC licenses this file
- // to you under the Apache License, Version 2.0 (the
- // "License"); you may not use this file except in compliance
- // with the License. You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing,
- // software distributed under the License is distributed on an
- // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- // KIND, either express or implied. See the License for the
- // specific language governing permissions and limitations
- // under the License.
- 'use strict';
- const childProcess = require('child_process');
- /**
- * A hash with configuration options for an executed command.
- *
- * - `args` - Command line arguments.
- * - `env` - Command environment; will inherit from the current process if
- * missing.
- * - `stdio` - IO configuration for the spawned server process. For more
- * information, refer to the documentation of `child_process.spawn`.
- *
- * @typedef {{
- * args: (!Array<string>|undefined),
- * env: (!Object<string, string>|undefined),
- * stdio: (string|!Array<string|number|!stream.Stream|null|undefined>|
- * undefined)
- * }}
- */
- var Options;
- /**
- * Describes a command's termination conditions.
- */
- class Result {
- /**
- * @param {?number} code The exit code, or {@code null} if the command did not
- * exit normally.
- * @param {?string} signal The signal used to kill the command, or
- * {@code null}.
- */
- constructor(code, signal) {
- /** @type {?number} */
- this.code = code;
- /** @type {?string} */
- this.signal = signal;
- }
- /** @override */
- toString() {
- return `Result(code=${this.code}, signal=${this.signal})`;
- }
- }
- const COMMAND_RESULT = /** !WeakMap<!Command, !Promise<!Result>> */new WeakMap;
- const KILL_HOOK = /** !WeakMap<!Command, function(string)> */new WeakMap;
- /**
- * Represents a command running in a sub-process.
- */
- class Command {
- /**
- * @param {!Promise<!Result>} result The command result.
- * @param {function(string)} onKill The function to call when {@link #kill()}
- * is called.
- */
- constructor(result, onKill) {
- COMMAND_RESULT.set(this, result);
- KILL_HOOK.set(this, onKill);
- }
- /**
- * @return {!Promise<!Result>} A promise for the result of this
- * command.
- */
- result() {
- return /** @type {!Promise<!Result>} */(COMMAND_RESULT.get(this));
- }
- /**
- * Sends a signal to the underlying process.
- * @param {string=} opt_signal The signal to send; defaults to `SIGTERM`.
- */
- kill(opt_signal) {
- KILL_HOOK.get(this)(opt_signal || 'SIGTERM');
- }
- }
- // PUBLIC API
- /**
- * Spawns a child process. The returned {@link Command} may be used to wait
- * for the process result or to send signals to the process.
- *
- * @param {string} command The executable to spawn.
- * @param {Options=} opt_options The command options.
- * @return {!Command} The launched command.
- */
- module.exports = function exec(command, opt_options) {
- var options = opt_options || {};
- var proc = childProcess.spawn(command, options.args || [], {
- env: options.env || process.env,
- stdio: options.stdio || 'ignore'
- });
- // This process should not wait on the spawned child, however, we do
- // want to ensure the child is killed when this process exits.
- proc.unref();
- process.once('exit', onProcessExit);
- let result = new Promise(resolve => {
- proc.once('exit', (code, signal) => {
- proc = null;
- process.removeListener('exit', onProcessExit);
- resolve(new Result(code, signal));
- });
- });
- return new Command(result, killCommand);
- function onProcessExit() {
- killCommand('SIGTERM');
- }
- function killCommand(signal) {
- process.removeListener('exit', onProcessExit);
- if (proc) {
- proc.kill(signal);
- proc = null;
- }
- }
- };
- // Exported to improve generated API documentation.
- module.exports.Command = Command;
- /** @typedef {!Options} */
- module.exports.Options = Options;
- module.exports.Result = Result;
|