@yolkai/nx-workspace
Version:
149 lines (148 loc) • 5.63 kB
JavaScript
;
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 architect_1 = require("@angular-devkit/architect");
const child_process_1 = require("child_process");
const rxjs_1 = require("rxjs");
const file_utils_1 = require("@yolkai/nx-workspace/src/core/file-utils");
try {
require('dotenv').config();
}
catch (e) { }
exports.default = architect_1.createBuilder(run);
function run(options, context) {
options.parsedArgs = parseArgs(options.args);
return rxjs_1.Observable.create((observer) => __awaiter(this, void 0, void 0, function* () {
if (!options.commands) {
observer.next({
success: false,
error: 'ERROR: Bad builder config for @yolkai/run-command - "commands" option is required'
});
return;
}
if (options.readyWhen && !options.parallel) {
observer.error('ERROR: Bad builder config for @yolkai/run-command - "readyWhen" can only be used when parallel=true');
return;
}
if (options.commands.some(c => !c.command)) {
observer.error('ERROR: Bad builder config for @yolkai/run-command - "command" option is required');
return;
}
try {
const success = options.parallel
? yield runInParallel(options)
: yield runSerially(options, context);
observer.next({ success });
observer.complete();
}
catch (e) {
observer.error(`ERROR: Something went wrong in @yolkai/run-command - ${e.message}`);
}
}));
}
function runInParallel(options) {
return __awaiter(this, void 0, void 0, function* () {
const procs = options.commands.map(c => createProcess(c.command, options.readyWhen, options.parsedArgs).then(result => ({
result,
command: c.command
})));
if (options.readyWhen) {
const r = yield Promise.race(procs);
if (!r.result) {
process.stderr.write(`Warning: @yolkai/run-command command "${r.command}" exited with non-zero status code`);
return false;
}
else {
return true;
}
}
else {
const r = yield Promise.all(procs);
const failed = r.filter(v => !v.result);
if (failed.length > 0) {
failed.forEach(f => {
process.stderr.write(`Warning: @yolkai/run-command command "${f.command}" exited with non-zero status code`);
});
return false;
}
else {
return true;
}
}
});
}
function runSerially(options, context) {
return __awaiter(this, void 0, void 0, function* () {
const failedCommand = yield options.commands.reduce((m, c) => __awaiter(this, void 0, void 0, function* () {
if ((yield m) === null) {
const success = yield createProcess(c.command, options.readyWhen, options.parsedArgs);
return !success ? c.command : null;
}
else {
return m;
}
}), Promise.resolve(null));
if (failedCommand) {
context.logger.warn(`Warning: @yolkai/run-command command "${failedCommand}" exited with non-zero status code`);
return false;
}
return true;
});
}
function createProcess(command, readyWhen, parsedArgs) {
command = transformCommand(command, parsedArgs);
return new Promise(res => {
const childProcess = child_process_1.exec(command, { maxBuffer: file_utils_1.TEN_MEGABYTES });
/**
* Ensure the child process is killed when the parent exits
*/
process.on('exit', () => childProcess.kill());
childProcess.stdout.on('data', data => {
process.stdout.write(data);
if (readyWhen && data.toString().indexOf(readyWhen) > -1) {
res(true);
}
});
childProcess.stderr.on('data', err => {
process.stderr.write(err);
if (readyWhen && err.toString().indexOf(readyWhen) > -1) {
res(true);
}
});
childProcess.on('close', code => {
if (!readyWhen) {
res(code === 0);
}
});
});
}
function transformCommand(command, args) {
const regex = /{args\.([^}]+)}/g;
return command.replace(regex, (_, group) => args[group]);
}
function parseArgs(args) {
if (!args) {
return {};
}
return args
.split(' ')
.map(t => t.trim())
.reduce((m, c) => {
if (!c.startsWith('--')) {
throw new Error(`Invalid args: ${args}`);
}
const [key, value] = c.substring(2).split('=');
if (!key || !value) {
throw new Error(`Invalid args: ${args}`);
}
m[key] = value;
return m;
}, {});
}