UNPKG

renovate

Version:

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

156 lines (155 loc) 4.63 kB
import { getEnv } from "../env.js"; import { ExecError } from "./exec-error.js"; import { sanitize } from "../sanitize.js"; import { logger } from "../../logger/index.js"; import { asRawCommand, isCommandWithOptions } from "./utils.js"; import { instrument } from "../../instrumentation/index.js"; import { isNullOrUndefined } from "@sindresorhus/is"; import { join, split } from "shlex"; import { execa } from "execa"; //#region lib/util/exec/common.ts 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) => { const len = Buffer.byteLength(chunk, encoding); stdoutLen += len; if (stdoutLen > opts.maxBuffer) cp.emit("error", /* @__PURE__ */ new Error("stdout maxBuffer exceeded")); else stdout.push(chunk); }); cp.stderr?.on("data", (chunk) => { const len = Buffer.byteLength(chunk, encoding); stderrLen += len; if (stderrLen > opts.maxBuffer) cp.emit("error", /* @__PURE__ */ new Error("stderr maxBuffer exceeded")); else stderr.push(chunk); }); return [stdout, stderr]; } function registerDataListeners(readable, dataListeners) { if (isNullOrUndefined(readable) || isNullOrUndefined(dataListeners)) return; for (const listener of dataListeners) readable.on("data", listener); } function exec(commandArgument, opts) { let theCmd = commandArgument; let ignoreFailure = false; if (isCommandWithOptions(commandArgument)) { theCmd = join(commandArgument.command); if (commandArgument.ignoreFailure !== void 0) ignoreFailure = commandArgument.ignoreFailure; } return new Promise((resolve, reject) => { let cmd = asRawCommand(theCmd); let args = []; const maxBuffer = opts.maxBuffer ?? 10 * 1024 * 1024; let shell = opts.shell ?? false; if (isCommandWithOptions(commandArgument) && commandArgument.shell !== void 0) shell = commandArgument.shell; if (shell === false) { const parts = split(cmd); // v8 ignore else -- TODO: add test #40625 if (parts) { cmd = parts[0]; args = parts.slice(1); } } const cp = execa(cmd, args, { ...opts, detached: process.platform !== "win32", shell, extendEnv: false }); const [stdout, stderr] = initStreamListeners(cp, { ...opts, maxBuffer }); cp.on("error", (error) => { kill(cp, "SIGTERM"); reject(new ExecError(error.message, rejectInfo(), error)); }); cp.on("exit", (code, signal) => { if (NONTERM.includes(signal)) return; if (signal) { kill(cp, signal); reject(new ExecError(`Command failed: ${cp.spawnargs.join(" ")}\nInterrupted by ${signal}`, { ...rejectInfo(), signal })); return; } if (code !== 0) { if (ignoreFailure === void 0 || ignoreFailure === false) { reject(new ExecError(`Command failed: ${cp.spawnargs.join(" ")}\n${stringify(stderr)}`, { ...rejectInfo(), exitCode: code })); return; } logger.once.debug({ command: cp.spawnargs.join(" "), stdout: stringify(stdout), stderr: stringify(stderr), exitCode: code }, `Ignoring failure to execute comamnd \`${cp.spawnargs.join(" ")}\`, as ignoreFailure=true is set`); resolve({ stderr: stringify(stderr), stdout: stringify(stdout), 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 && getEnv().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 { cp.stderr?.destroy(); cp.stdout?.destroy(); cp.unref(); return cp.kill(signal); } } catch { return false; } } const rawExec = (cmd, opts) => instrument(`rawExec: ${sanitize(asRawCommand(cmd))}`, () => exec(cmd, opts)); //#endregion export { exec, rawExec }; //# sourceMappingURL=common.js.map