firebase-tools
Version:
Command-Line Interface for Firebase
113 lines (112 loc) • 3.84 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_VENV_DIR = void 0;
exports.virtualEnvCmd = virtualEnvCmd;
exports.runWithVirtualEnv = runWithVirtualEnv;
exports.killProcessTree = killProcessTree;
exports.trackVirtualEnvChild = trackVirtualEnvChild;
exports.untrackVirtualEnvChild = untrackVirtualEnvChild;
const os = require("os");
const path = require("path");
const cross_spawn_1 = require("cross-spawn");
const cp = require("child_process");
const logger_1 = require("../logger");
const utils_1 = require("../utils");
const error_1 = require("../error");
exports.DEFAULT_VENV_DIR = "venv";
function virtualEnvCmd(cwd, venvDir) {
const activateScriptPath = utils_1.IS_WINDOWS ? ["Scripts", "activate.bat"] : ["bin", "activate"];
const venvActivate = `"${path.join(cwd, venvDir, ...activateScriptPath)}"`;
return {
command: utils_1.IS_WINDOWS ? venvActivate : ".",
args: utils_1.IS_WINDOWS ? [] : [venvActivate],
};
}
function runWithVirtualEnv(commandAndArgs, cwd, envs, spawnOpts = {}, venvDir = exports.DEFAULT_VENV_DIR) {
const { command, args } = virtualEnvCmd(cwd, venvDir);
args.push("&&", ...commandAndArgs);
logger_1.logger.debug(`Running command with virtualenv: command=${command}, args=${JSON.stringify(args)}`);
return (0, cross_spawn_1.spawn)(command, args, {
shell: true,
cwd,
stdio: "pipe",
...spawnOpts,
env: { ...process.env, ...envs },
});
}
function killProcessTree(pid) {
if (!pid || pid <= 0) {
return;
}
if (utils_1.IS_WINDOWS) {
const result = cp.spawnSync("taskkill", ["/pid", pid.toString(), "/T", "/F"]);
if (result.error || result.status !== 0) {
logger_1.logger.debug(`taskkill on pid ${pid} exited with ${String(result.status)}: ` +
`${result.error?.message ?? result.stderr?.toString().trim() ?? ""}`);
}
return;
}
try {
process.kill(-pid, "SIGKILL");
}
catch (e) {
logger_1.logger.debug(`Failed to kill process group ${pid}: ${(0, error_1.getErrMsg)(e)}`);
}
}
const CLEANUP_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP", "SIGQUIT"];
const trackedChildren = new Set();
const signalHandlers = new Map();
function reRaise(signal) {
try {
process.kill(process.pid, signal);
}
catch (e) {
logger_1.logger.debug(`Could not re-raise ${signal}, exiting instead: ${(0, error_1.getErrMsg)(e)}`);
process.exit(128 + (os.constants.signals[signal] ?? 0));
}
}
function killAllTrackedChildren() {
for (const child of trackedChildren) {
if (child.pid && child.exitCode === null && child.signalCode === null) {
killProcessTree(child.pid);
}
}
trackedChildren.clear();
}
function removeCleanupHandlers() {
if (!signalHandlers.size) {
return;
}
process.removeListener("exit", killAllTrackedChildren);
for (const [signal, handler] of signalHandlers) {
process.removeListener(signal, handler);
}
signalHandlers.clear();
}
function addCleanupHandlers() {
if (signalHandlers.size) {
return;
}
process.on("exit", killAllTrackedChildren);
for (const signal of CLEANUP_SIGNALS) {
const handler = () => {
killAllTrackedChildren();
removeCleanupHandlers();
if (process.listenerCount(signal) === 0) {
reRaise(signal);
}
};
signalHandlers.set(signal, handler);
process.on(signal, handler);
}
}
function trackVirtualEnvChild(child) {
trackedChildren.add(child);
addCleanupHandlers();
}
function untrackVirtualEnvChild(child) {
trackedChildren.delete(child);
if (!trackedChildren.size) {
removeCleanupHandlers();
}
}