@cloud-cli/exec
Version:
Promise wrapper for child_process.spawn
67 lines (66 loc) • 2.4 kB
JavaScript
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);
}
});
}