@clickup/pg-microsharding
Version:
Microshards support for PostgreSQL
102 lines • 4.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isInTmuxSession = isInTmuxSession;
exports.tryReattachToTmuxSession = tryReattachToTmuxSession;
exports.runInTmux = runInTmux;
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const tmp_1 = require("tmp");
const logging_1 = require("./logging");
const quote_1 = require("./quote");
const TMUX_SESSION = "pg-microsharding-tmux";
const ACTIVE_BG = "#000033";
/**
* Returns true if this script runs inside a TMUX session.
*/
function isInTmuxSession() {
return !!process.env["TMUX"];
}
/**
* If there is already an active TMUX session, reattaches to it. We need to keep
* the strong notion of singleton for all long-running microsharding actions, so
* that e.g. if we run `pg-microsharding rebalance` in one terminal, and then
* run it again in another terminal, the second run will attach to the first
* one.
*/
async function tryReattachToTmuxSession() {
if (isInTmuxSession()) {
return;
}
try {
(0, child_process_1.execSync)("which tmux", { stdio: "ignore" });
}
catch {
throw "TMUX is required to run this action. Please install it.";
}
// Try to reattach to an existing session instead of starting a new one (in
// case we e.g. got disconnected).
try {
(0, child_process_1.execSync)(`tmux attach-session -d -t ${TMUX_SESSION} 2>/dev/null`, {
stdio: "inherit",
});
process.exit(0);
}
catch {
// No such session yet.
}
}
/**
* Opens M TMUX panes, in each run N commands sequentially (panes[M][N]). If a
* single command fails, then fails the whole pane.
*
* In case we already run it from a TMUX session, just runs all the commands
* sequentially.
*/
async function runInTmux(panes) {
if (isInTmuxSession()) {
for (const { title, command } of panes.flat()) {
logging_1.print.section(`\n##\n## ${title}\n##\n`);
(0, child_process_1.execSync)(command.map((v) => (0, quote_1.shellQuote)(v)).join(" "), {
stdio: "inherit",
});
}
return;
}
(0, tmp_1.setGracefulCleanup)();
const tmuxCommands = ["set -e"];
for (const [i, sequence] of panes.entries()) {
const commands = [
"set -e",
String.raw `trap 'test $? -eq 0 && printf "\033[1;32mDONE. Press ^C to close this pane..." || printf "\033[0;31mFAILURE. Press ^C to close this pane..."; sleep 100000' EXIT`,
];
for (const [i, { title, command }] of sequence.entries()) {
const progress = `${i + 1} of ${sequence.length}`;
commands.push(`printf '\\033]2;%s\\033\\' ' ${progress} | ${title} '`, command.map(quote_1.shellQuote).join(" "), "echo");
}
// TMUX has a limit on the command total length:
// https://github.com/tmux/tmux/issues/254. So instead of passing the big
// script, we instead put this script in a temporary file and then run it
// using the `bash this-temp-file` plain command via TMUX. Notice that the
// temporary files are auto-removed, but if the script is terminated cruelly
// with e.g. -9 signal, they may linger; it's not a big deal since they are
// cleaned up by linux tmpwatch anyway, we just don't have a better option.
const tmpFile = (0, tmp_1.fileSync)({
tmpdir: logging_1.TMP_DIR,
prefix: "tmux-" +
sequence
.map(({ key }) => key)
.slice(0, 10)
.join("-"),
}).name;
(0, fs_1.writeFileSync)(tmpFile, commands.join("\n"));
if (i === 0) {
tmuxCommands.push(`tmux new-session -s ${TMUX_SESSION} -d bash ${(0, quote_1.shellQuote)(tmpFile)}`);
}
else {
tmuxCommands.push(`tmux split-window -f bash ${(0, quote_1.shellQuote)(tmpFile)}`, "tmux select-layout tiled");
}
}
tmuxCommands.push('tmux bind -n "C-c" confirm-before -p "Confirm SIGINT? (y/n)" "send-keys C-c"', `tmux set -g window-active-style "bg=${ACTIVE_BG}"`, `tmux set -g pane-active-border-style "bg=${ACTIVE_BG}"`, "tmux set mouse on", "tmux set pane-border-status top", 'tmux set pane-border-format "#T"', "tmux select-layout tiled", `tmux attach-session -d -t ${TMUX_SESSION}`);
(0, child_process_1.execSync)(tmuxCommands.join("\n"), { stdio: "inherit" });
}
//# sourceMappingURL=runInTmux.js.map