@clickup/pg-microsharding
Version:
Microshards support for PostgreSQL
131 lines • 5.45 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runShell = runShell;
const child_process_1 = require("child_process");
const chalk_1 = __importDefault(require("chalk"));
const compact_1 = __importDefault(require("lodash/compact"));
const lastLines_1 = require("./lastLines");
const logging_1 = require("./logging");
const pluralize_1 = require("./pluralize");
const MAX_INPUT_LINES = 2;
const MAX_PROGRESS_LINES = 3;
/**
* Runs a shell command passing it an optional input as stdin. Throws on errors.
* Returns the lines of stdout. If onOutArg is absent, then stderr of the
* process to piped to logging's stderr. Otherwise, onOutArg() is called with
* the full output (combined stdout + stderr) on every data chunk and also every
* ~1 second if there is no activity (that allows the caller to e.g. prepend
* ticking timestamps to the output lines to emphasize that the process is still
* alive). If onOutArg="progress", then last MAX_PROGRESS_LINES lines of the
* output are progress-printed (with ticking timestamps prepended) and then
* erased in the end.
*/
async function runShell(cmd, input, comment, showProgress) {
let inputStr = null;
if (input) {
const inputLines = (0, compact_1.default)(input.split("\n"));
const inputLinesLess = inputLines.slice(0, MAX_INPUT_LINES);
const inputLinesMore = inputLines.length - inputLinesLess.length;
inputStr = (0, compact_1.default)([
...inputLinesLess,
inputLinesMore > 0 && `...and ${(0, pluralize_1.pluralize)(inputLinesMore, "more line")}`,
]).join("\n");
}
if (comment) {
logging_1.log.shellCmd({ comment, cmd, input: inputStr });
}
const onOut = showProgress
? (out) => (showProgress === "progress" ? logging_1.progress : logging_1.progress.unlogged)(chalk_1.default
.gray((0, lastLines_1.lastLines)(out, MAX_PROGRESS_LINES, (logging_1.stdout.columns || 80) - 32))
.replace(/^/gm, "> "))
: undefined;
let timeout;
let proc;
const sigIntHandler = () => (proc === null || proc === void 0 ? void 0 : proc.pid) && process.kill(proc.pid, "SIGINT");
process.on("SIGINT", sigIntHandler);
logging_1.stdout.setMaxListeners(logging_1.stdout.getMaxListeners() + 1);
logging_1.stderr.setMaxListeners(logging_1.stderr.getMaxListeners() + 1);
process.setMaxListeners(process.getMaxListeners() + 1);
try {
return await new Promise((resolve, reject) => {
proc = (0, child_process_1.spawn)("/bin/bash", ["-o", "pipefail", "-c", cmd], {
shell: false,
env: {
...process.env,
PGOPTIONS: (0, compact_1.default)([
"--client-min-messages=warning",
process.env["PGOPTIONS"],
]).join(" "),
},
});
if (input) {
proc.stdin.write(input);
proc.stdin.end();
}
if (!onOut) {
proc.stderr.pipe(logging_1.stderr, { end: false });
}
let stdoutStr = "";
let stderrStr = "";
let outStr = "";
const onOutWithTimer = () => {
clearTimeout(timeout);
onOut === null || onOut === void 0 ? void 0 : onOut(outStr);
timeout = setTimeout(onOutWithTimer, 1000);
};
proc.stdout.on("data", (data) => {
const str = data.toString();
stdoutStr += str;
outStr += str;
onOutWithTimer();
});
proc.stderr.on("data", (data) => {
const str = data.toString();
logging_1.stdlog.write(str);
stderrStr += str;
outStr += str;
onOutWithTimer();
});
proc.on("error", (err) => {
onOutWithTimer();
reject(err);
});
proc.on("close", (code, signal) => {
onOutWithTimer();
if (code !== 0) {
reject((0, compact_1.default)([
`Process exited with ${signal ? `signal ${signal}` : `code ${code}`}`,
onOut && stderrStr,
]).join("\n"));
}
else {
resolve(stdoutStr);
}
});
});
}
catch (e) {
if (!comment) {
logging_1.log.shellCmd({
comment: "Error running the command",
cmd,
input: inputStr,
isError: true,
});
}
throw e;
}
finally {
clearTimeout(timeout);
proc === null || proc === void 0 ? void 0 : proc.stderr.unpipe(logging_1.stderr);
process.setMaxListeners(process.getMaxListeners() - 1);
logging_1.stderr.setMaxListeners(logging_1.stderr.getMaxListeners() - 1);
logging_1.stdout.setMaxListeners(logging_1.stdout.getMaxListeners() - 1);
process.removeListener("SIGINT", sigIntHandler);
onOut && logging_1.progress.clear();
}
}
//# sourceMappingURL=runShell.js.map