UNPKG

@yolkai/nx-workspace

Version:

Extensible Dev Tools for Monorepos

149 lines (148 loc) 5.63 kB
"use strict"; 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; }, {}); }