UNPKG

@cloud-cli/exec

Version:

Promise wrapper for child_process.spawn

67 lines (66 loc) 2.4 kB
import { EventEmitter } from 'events'; import { spawn, exec as sh } from 'child_process'; import { StringDecoder } from 'string_decoder'; export class Process extends EventEmitter { get hasError() { return Boolean((this._errorBuffer.length && this.code !== 0) || this.code !== 0 || this.error); } constructor(childProcess) { super(); this.childProcess = childProcess; this.code = 0; this.completed = false; this._outputBuffer = ''; this._errorBuffer = ''; this.stdoutDecoder = new StringDecoder(); this.stderrDecoder = new StringDecoder(); childProcess.stdout?.on('data', (data) => (this.stdout = data)); childProcess.stderr?.on('data', (data) => (this.stderr = data)); childProcess.on('exit', (code) => (this.code = code)); childProcess.on('close', () => this.complete()); childProcess.on('error', (error) => (this.error = error)); } set stdout(value) { this._outputBuffer += this.stdoutDecoder.write(value); } set stderr(value) { this._errorBuffer += this.stderrDecoder.write(value); } complete() { this.completed = true; this._outputBuffer += this.stdoutDecoder.end(); this._errorBuffer += this.stderrDecoder.end(); this.emit('done', this.output); } get output() { return { ok: !this.hasError && this.code === 0, code: this.error ? -1 : this.code, stdout: this._outputBuffer, stderr: this._errorBuffer, error: this.hasError ? new Error(this._errorBuffer) : undefined, }; } } export async function execString(command, options) { /* istanbul ignore next */ process.env.DEBUG && console.log(command, options); return execInternal(() => sh(command, options)); } export async function exec(command, args = [], options) { /* istanbul ignore next */ process.env.DEBUG && console.log(command, args, options); return execInternal(() => spawn(command, args, options)); } function execInternal(runner) { return new Promise((resolve, reject) => { try { const childProcess = runner(); const state = new Process(childProcess); state.on('done', () => resolve(state.output)); } catch (error) { reject(error); } }); }