process-rerun
Version:
The purpose of this library is - build simple and flexible interface for parallel command execution with rerun (on fail) possibility
80 lines • 3.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.execute = execute;
exports.getCache = getCache;
const node_child_process_1 = require("node:child_process");
const sat_utils_1 = require("sat-utils");
const error_1 = require("../error");
/**
* Extracts every shared cache payload emitted by the child process on its stdout.
*
* A process can publish data back to the runner by printing one or more lines shaped like:
* shared-cache: "<json payload here>"
*
* Each json payload lives inside the double quotes with its own quotes escaped.
* Returns an array with one parsed payload per matched line (empty when none are present),
* preserving the order in which the process printed them.
*/
function getCache(output) {
if (!(0, sat_utils_1.isString)(output))
return [];
const entries = [];
for (const match of output.matchAll(/shared-cache:\s*"((?:\\.|[^"\\])*)"/g)) {
const raw = match[1];
try {
// `raw` is the body of a JSON string literal (inner quotes escaped),
// so decode it first, then parse the decoded json payload.
const decoded = JSON.parse(`"${raw}"`);
try {
entries.push(JSON.parse(decoded));
}
catch {
entries.push(decoded);
}
}
catch {
entries.push(raw);
}
}
return entries;
}
function execute({ cmd, logProcessResult, executionHolder, execOpts = {}, }) {
if (!(0, sat_utils_1.isString)(cmd)) {
throw new error_1.ProcessRerunError('Type', `cmd (first argument should be a string), current type is ${(0, sat_utils_1.getType)(cmd)}`);
}
if (!(0, sat_utils_1.isObject)(executionHolder)) {
throw new error_1.ProcessRerunError('Type', `executionHolder (third argument should be an object), current type is ${(0, sat_utils_1.getType)(executionHolder)}`);
}
if (!(0, sat_utils_1.isFunction)(logProcessResult)) {
throw new error_1.ProcessRerunError('Type', `executionHolder (second argument should be a function), current type is ${(0, sat_utils_1.getType)(logProcessResult)}`);
}
const startTime = +Date.now();
let stdout = '';
let stderr = '';
let settled = false;
const execProc = (0, node_child_process_1.spawn)(cmd, { ...execOpts, shell: true, detached: process.platform !== 'win32' });
execProc.stdout?.on('data', chunk => {
stdout += chunk.toString();
});
execProc.stderr?.on('data', chunk => {
stderr += chunk.toString();
});
const finalize = (error) => {
if (settled)
return;
settled = true;
logProcessResult(cmd, startTime, execProc, error, stdout, stderr);
executionHolder.stackTrace += `${stdout}${stderr}`;
// collect every shared-cache line the process printed over its whole lifetime
executionHolder.cache = getCache(stdout);
};
execProc.on('error', finalize);
execProc.on('close', (code, signal) => {
const error = code !== 0 && code !== null
? Object.assign(new Error(`Command failed: ${cmd}`), { code, signal })
: null;
finalize(error);
});
return execProc;
}
//# sourceMappingURL=index.js.map