turbo-gulp
Version:
Gulp tasks to boost high-quality projects.
108 lines (107 loc) • 3.89 kB
JavaScript
import { execFile as _execFile, spawn as _spawn, } from "child_process";
import * as fs from "fs";
import { Incident } from "incident";
import { PassThrough } from "stream";
import { promisify } from "util";
function asBuffer(val) {
return val instanceof Buffer ? val : new Buffer(val, "utf8");
}
export class ExecFileError extends Incident {
constructor(nativeError, stdout, stderr) {
const data = {
cmd: nativeError.cmd,
killed: nativeError.killed,
code: nativeError.code,
signal: nativeError.signal,
stdout: asBuffer(stdout),
stderr: asBuffer(stderr),
};
const message = `An error occured during the execution of: ${data.cmd}\n${nativeError.stack}`;
super(nativeError, "ExecFileError", data, message);
}
}
const _readFile = promisify(fs.readFile);
const _writeFile = promisify(fs.writeFile);
export async function readText(file) {
return _readFile(file, "utf8");
}
export async function writeText(file, text) {
return _writeFile(file, text);
}
export async function execFile(file, args, options) {
return new Promise((resolve, reject) => {
const normalizedOptions = Object.assign({}, options, { encoding: "buffer" });
_execFile(file, args, normalizedOptions, (error, stdout, stderr) => {
if (error !== null) {
reject(new ExecFileError(error, stdout, stderr));
return;
}
const result = {
stdout: asBuffer(stdout),
stderr: asBuffer(stderr),
};
resolve(result);
});
});
}
export class SpawnedProcess {
constructor(file, args, options) {
this.stdoutChunks = [];
this.stderrChunks = [];
this.exit = undefined;
const detached = options.detached !== undefined ? options.detached : false;
this.process = _spawn(file, args, { stdio: [process.stdin, "pipe", "pipe"], cwd: options.cwd, env: options.env, detached });
const stdout = new PassThrough();
this.process.stdout.pipe(stdout);
const stderr = new PassThrough();
this.process.stderr.pipe(stderr);
if (options.stdio === "inherit") {
stdout.pipe(process.stdout);
stderr.pipe(process.stderr);
}
stdout.on("data", (chunk) => {
this.stdoutChunks.push(chunk);
});
stderr.on("data", (chunk) => {
this.stderrChunks.push(chunk);
});
this.process.once("exit", (code, signal) => {
if (code !== null) {
this.exit = { type: "code", code };
}
else {
this.exit = { type: "signal", signal: signal };
}
});
}
async toPromise() {
return new Promise((resolve, reject) => {
if (this.exit !== undefined) {
const [stdout, stderr] = this.getBuffers();
resolve({ stdout, stderr, exit: this.exit });
}
else {
this.process.once("exit", (code, signal) => {
let exit;
if (code !== null) {
exit = { type: "code", code };
}
else {
exit = { type: "signal", signal: signal };
}
const [stdout, stderr] = this.getBuffers();
resolve({ stdout, stderr, exit });
});
}
});
}
getBuffers() {
const stdout = Buffer.concat(this.stdoutChunks);
const stderr = Buffer.concat(this.stderrChunks);
this.stdoutChunks.length = 0;
this.stderrChunks.length = 0;
this.stdoutChunks.push(stdout);
this.stderrChunks.push(stderr);
return [stdout, stderr];
}
}