UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

148 lines 5.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.rawExec = void 0; exports.exec = exec; const tslib_1 = require("tslib"); const node_child_process_1 = require("node:child_process"); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const exec_error_1 = require("./exec-error"); // https://man7.org/linux/man-pages/man7/signal.7.html#NAME // Non TERM/CORE signals // The following is step 3. in https://github.com/renovatebot/renovate/issues/16197#issuecomment-1171423890 const NONTERM = [ 'SIGCHLD', 'SIGCLD', 'SIGCONT', 'SIGSTOP', 'SIGTSTP', 'SIGTTIN', 'SIGTTOU', 'SIGURG', 'SIGWINCH', ]; const encoding = 'utf8'; function stringify(list) { return Buffer.concat(list).toString(encoding); } function initStreamListeners(cp, opts) { const stdout = []; const stderr = []; let stdoutLen = 0; let stderrLen = 0; registerDataListeners(cp.stdout, opts.outputListeners?.stdout); registerDataListeners(cp.stderr, opts.outputListeners?.stderr); cp.stdout?.on('data', (chunk) => { // process.stdout.write(data.toString()); const len = Buffer.byteLength(chunk, encoding); stdoutLen += len; if (stdoutLen > opts.maxBuffer) { cp.emit('error', new Error('stdout maxBuffer exceeded')); } else { stdout.push(chunk); } }); cp.stderr?.on('data', (chunk) => { // process.stderr.write(data.toString()); const len = Buffer.byteLength(chunk, encoding); stderrLen += len; if (stderrLen > opts.maxBuffer) { cp.emit('error', new Error('stderr maxBuffer exceeded')); } else { stderr.push(chunk); } }); return [stdout, stderr]; } function registerDataListeners(readable, dataListeners) { if (is_1.default.nullOrUndefined(readable) || is_1.default.nullOrUndefined(dataListeners)) { return; } for (const listener of dataListeners) { readable.on('data', listener); } } function exec(cmd, opts) { return new Promise((resolve, reject) => { const maxBuffer = opts.maxBuffer ?? 10 * 1024 * 1024; // Set default max buffer size to 10MB const cp = (0, node_child_process_1.spawn)(cmd, { ...opts, // force detached on non WIN platforms // https://github.com/nodejs/node/issues/21825#issuecomment-611328888 detached: process.platform !== 'win32', shell: typeof opts.shell === 'string' ? opts.shell : true, // force shell }); // handle streams const [stdout, stderr] = initStreamListeners(cp, { ...opts, maxBuffer, }); // handle process events cp.on('error', (error) => { kill(cp, 'SIGTERM'); // rethrowing, use originally emitted error message reject(new exec_error_1.ExecError(error.message, rejectInfo(), error)); }); cp.on('exit', (code, signal) => { if (NONTERM.includes(signal)) { return; } if (signal) { kill(cp, signal); reject(new exec_error_1.ExecError(`Command failed: ${cmd}\nInterrupted by ${signal}`, { ...rejectInfo(), signal, })); return; } if (code !== 0) { reject(new exec_error_1.ExecError(`Command failed: ${cmd}\n${stringify(stderr)}`, { ...rejectInfo(), exitCode: code, })); return; } resolve({ stderr: stringify(stderr), stdout: stringify(stdout), }); }); function rejectInfo() { return { cmd: cp.spawnargs.join(' '), options: opts, stdout: stringify(stdout), stderr: stringify(stderr), }; } }); } function kill(cp, signal) { try { if (cp.pid && process.env.RENOVATE_X_EXEC_GPID_HANDLE) { /** * If `pid` is negative, but not `-1`, signal shall be sent to all processes * (excluding an unspecified set of system processes), * whose process group ID (pgid) is equal to the absolute value of pid, * and for which the process has permission to send a signal. */ return process.kill(-cp.pid, signal); } else { // destroying stdio is needed for unref to work // https://nodejs.org/api/child_process.html#subprocessunref // https://github.com/nodejs/node/blob/4d5ff25a813fd18939c9f76b17e36291e3ea15c3/lib/child_process.js#L412-L426 cp.stderr?.destroy(); cp.stdout?.destroy(); cp.unref(); return cp.kill(signal); } } catch { // cp is a single node tree, therefore -pid is invalid as there is no such pgid, return false; } } exports.rawExec = exec; //# sourceMappingURL=common.js.map