@gtkx/utils 1.6.0 → 2.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -44
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/path.d.ts +5 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +10 -0
- package/dist/path.js.map +1 -0
- package/dist/process/index.d.ts +3 -1
- package/dist/process/index.d.ts.map +1 -1
- package/dist/process/index.js +3 -1
- package/dist/process/index.js.map +1 -1
- package/dist/process/kill-marked-processes.d.ts +3 -2
- package/dist/process/kill-marked-processes.d.ts.map +1 -1
- package/dist/process/kill-marked-processes.js +39 -13
- package/dist/process/kill-marked-processes.js.map +1 -1
- package/dist/process/kill-process-group.d.ts +16 -0
- package/dist/process/kill-process-group.d.ts.map +1 -0
- package/dist/process/kill-process-group.js +70 -0
- package/dist/process/kill-process-group.js.map +1 -0
- package/dist/process/process-guard.js +192 -6
- package/dist/process/process-guard.js.map +1 -1
- package/dist/process/process-status.d.ts +5 -0
- package/dist/process/process-status.d.ts.map +1 -0
- package/dist/process/process-status.js +19 -0
- package/dist/process/process-status.js.map +1 -0
- package/dist/process/resolve-executable.d.ts +2 -2
- package/dist/process/resolve-executable.d.ts.map +1 -1
- package/dist/process/resolve-executable.js +3 -37
- package/dist/process/resolve-executable.js.map +1 -1
- package/dist/process/spawn-with-parent-death-signal.d.ts +7 -1
- package/dist/process/spawn-with-parent-death-signal.d.ts.map +1 -1
- package/dist/process/spawn-with-parent-death-signal.js +315 -8
- package/dist/process/spawn-with-parent-death-signal.js.map +1 -1
- package/package.json +12 -4
- package/src/index.ts +1 -1
- package/src/path.ts +17 -0
- package/src/process/index.ts +14 -1
- package/src/process/kill-marked-processes.ts +58 -13
- package/src/process/kill-process-group.ts +105 -0
- package/src/process/process-guard.ts +261 -6
- package/src/process/process-status.ts +25 -0
- package/src/process/resolve-executable.ts +4 -46
- package/src/process/spawn-with-parent-death-signal.ts +422 -11
- package/dist/map/get-or-insert.d.ts +0 -8
- package/dist/map/get-or-insert.d.ts.map +0 -1
- package/dist/map/get-or-insert.js +0 -10
- package/dist/map/get-or-insert.js.map +0 -1
- package/dist/map/index.d.ts +0 -2
- package/dist/map/index.d.ts.map +0 -1
- package/dist/map/index.js +0 -2
- package/dist/map/index.js.map +0 -1
- package/src/map/get-or-insert.ts +0 -18
- package/src/map/index.ts +0 -1
|
@@ -1,16 +1,202 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { killMarkedProcesses, killMarkedProcessRun } from "./kill-marked-processes.js";
|
|
3
|
+
import { killProcessGroup, processGroupIdentity, removeCleanupDirectory, } from "./kill-process-group.js";
|
|
2
4
|
const GUARD_PREFIX = process.argv[2] ?? "";
|
|
5
|
+
const PROCESS_WATCH_ARGUMENT = process.argv[3];
|
|
3
6
|
const WATCHED_SIGNALS = ["SIGTERM", "SIGINT", "SIGHUP"];
|
|
4
|
-
const
|
|
7
|
+
const OWNER_POLL_INTERVAL_MS = 50;
|
|
8
|
+
const SUPERVISOR_EXIT_TIMEOUT_MS = 2000;
|
|
9
|
+
const state = {
|
|
10
|
+
bufferedCommands: "",
|
|
11
|
+
isSweeping: false,
|
|
12
|
+
jobs: new Map(),
|
|
13
|
+
};
|
|
14
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15
|
+
const isProcessIdentity = (value) => isRecord(value) &&
|
|
16
|
+
typeof value.pid === "number" &&
|
|
17
|
+
Number.isSafeInteger(value.pid) &&
|
|
18
|
+
value.pid > 1 &&
|
|
19
|
+
typeof value.startTime === "string" &&
|
|
20
|
+
/^\d+$/.test(value.startTime);
|
|
21
|
+
const isProcessWatch = (value) => isRecord(value) && isProcessIdentity(value.owner) && isProcessIdentity(value.target);
|
|
22
|
+
const isProcessGroupIdentity = (value) => isRecord(value) &&
|
|
23
|
+
typeof value.processGroupId === "number" &&
|
|
24
|
+
Number.isSafeInteger(value.processGroupId) &&
|
|
25
|
+
value.processGroupId > 1 &&
|
|
26
|
+
typeof value.leaderStartTime === "string" &&
|
|
27
|
+
/^\d+$/.test(value.leaderStartTime);
|
|
28
|
+
const isCleanupDirectoryIdentity = (value) => isRecord(value) &&
|
|
29
|
+
typeof value.path === "string" &&
|
|
30
|
+
typeof value.device === "string" &&
|
|
31
|
+
typeof value.inode === "string" &&
|
|
32
|
+
typeof value.userId === "string";
|
|
33
|
+
const isGuardJob = (value) => isRecord(value) &&
|
|
34
|
+
typeof value.marker === "string" &&
|
|
35
|
+
isProcessGroupIdentity(value.processGroup) &&
|
|
36
|
+
Array.isArray(value.cleanupDirectories) &&
|
|
37
|
+
value.cleanupDirectories.every(isCleanupDirectoryIdentity) &&
|
|
38
|
+
(value.signal === "SIGKILL" || value.signal === "SIGCONT");
|
|
39
|
+
const parseProcessWatch = () => {
|
|
40
|
+
if (PROCESS_WATCH_ARGUMENT === undefined) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const value = JSON.parse(PROCESS_WATCH_ARGUMENT);
|
|
45
|
+
return isProcessWatch(value) ? value : undefined;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const currentProcessIdentity = (pid) => {
|
|
52
|
+
try {
|
|
53
|
+
const stat = readFileSync(`/proc/${String(pid)}/stat`, "utf8");
|
|
54
|
+
const fields = stat.slice(stat.lastIndexOf(") ") + 2).split(" ", 20);
|
|
55
|
+
const state = fields[0];
|
|
56
|
+
const startTime = fields[19];
|
|
57
|
+
return startTime !== undefined && state !== undefined && !["Z", "X", "x"].includes(state)
|
|
58
|
+
? { pid, startTime }
|
|
59
|
+
: undefined;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const isCurrentProcess = (identity) => currentProcessIdentity(identity.pid)?.startTime === identity.startTime;
|
|
66
|
+
const killProcess = (identity) => {
|
|
67
|
+
if (!isCurrentProcess(identity)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
process.kill(identity.pid, "SIGKILL");
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const applyCommand = (command) => {
|
|
78
|
+
const operation = command[0];
|
|
79
|
+
let value;
|
|
80
|
+
try {
|
|
81
|
+
value = JSON.parse(command.slice(1));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (!isGuardJob(value)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (operation === "+") {
|
|
90
|
+
state.jobs.set(value.marker, value);
|
|
91
|
+
}
|
|
92
|
+
else if (operation === "-") {
|
|
93
|
+
state.jobs.delete(value.marker);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const receiveCommands = (chunk) => {
|
|
97
|
+
state.bufferedCommands += chunk.toString();
|
|
98
|
+
const commands = state.bufferedCommands.split("\n");
|
|
99
|
+
state.bufferedCommands = commands.pop() ?? "";
|
|
100
|
+
for (const command of commands) {
|
|
101
|
+
applyCommand(command);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const killJobs = () => {
|
|
105
|
+
for (const job of state.jobs.values()) {
|
|
106
|
+
killProcessGroup(job.processGroup, job.signal);
|
|
107
|
+
if (job.signal === "SIGKILL") {
|
|
108
|
+
killMarkedProcesses(job.marker);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const removeCleanupDirectories = () => {
|
|
113
|
+
const cleanupDirectories = new Map();
|
|
114
|
+
for (const job of state.jobs.values()) {
|
|
115
|
+
for (const identity of job.cleanupDirectories) {
|
|
116
|
+
cleanupDirectories.set(`${identity.device}:${identity.inode}`, identity);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
for (const identity of cleanupDirectories.values()) {
|
|
120
|
+
removeCleanupDirectory(identity);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const hasRunningSupervisor = () => {
|
|
124
|
+
for (const job of state.jobs.values()) {
|
|
125
|
+
if (job.signal !== "SIGCONT") {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const current = processGroupIdentity(job.processGroup.processGroupId);
|
|
129
|
+
if (current?.leaderStartTime === job.processGroup.leaderStartTime) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
};
|
|
135
|
+
const forceSupervisors = () => {
|
|
136
|
+
for (const job of state.jobs.values()) {
|
|
137
|
+
if (job.signal === "SIGCONT") {
|
|
138
|
+
killProcessGroup(job.processGroup);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const finishSweep = () => {
|
|
5
143
|
if (GUARD_PREFIX.length > 0) {
|
|
6
|
-
|
|
144
|
+
killMarkedProcessRun(GUARD_PREFIX);
|
|
7
145
|
}
|
|
146
|
+
removeCleanupDirectories();
|
|
8
147
|
process.exit(0);
|
|
9
148
|
};
|
|
149
|
+
const awaitSupervisors = (deadline) => {
|
|
150
|
+
if (hasRunningSupervisor() && Date.now() < deadline) {
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
awaitSupervisors(deadline);
|
|
153
|
+
}, OWNER_POLL_INTERVAL_MS);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
forceSupervisors();
|
|
157
|
+
finishSweep();
|
|
158
|
+
};
|
|
159
|
+
const sweep = (target) => {
|
|
160
|
+
if (state.isSweeping) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
state.isSweeping = true;
|
|
164
|
+
applyCommand(state.bufferedCommands);
|
|
165
|
+
if (target !== undefined) {
|
|
166
|
+
killProcess(target);
|
|
167
|
+
}
|
|
168
|
+
killJobs();
|
|
169
|
+
awaitSupervisors(Date.now() + SUPERVISOR_EXIT_TIMEOUT_MS);
|
|
170
|
+
};
|
|
171
|
+
const watch = parseProcessWatch();
|
|
172
|
+
const startOwnerPoll = () => {
|
|
173
|
+
if (watch === undefined) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const ownerPoll = setInterval(() => {
|
|
177
|
+
if (isCurrentProcess(watch.owner)) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
clearInterval(ownerPoll);
|
|
181
|
+
sweep(watch.target);
|
|
182
|
+
}, OWNER_POLL_INTERVAL_MS);
|
|
183
|
+
if (!isCurrentProcess(watch.owner)) {
|
|
184
|
+
clearInterval(ownerPoll);
|
|
185
|
+
sweep(watch.target);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
startOwnerPoll();
|
|
10
189
|
process.stdin.resume();
|
|
11
|
-
process.stdin.on("
|
|
12
|
-
process.stdin.on("
|
|
190
|
+
process.stdin.on("data", receiveCommands);
|
|
191
|
+
process.stdin.on("end", () => {
|
|
192
|
+
sweep();
|
|
193
|
+
});
|
|
194
|
+
process.stdin.on("error", () => {
|
|
195
|
+
sweep();
|
|
196
|
+
});
|
|
13
197
|
for (const signal of WATCHED_SIGNALS) {
|
|
14
|
-
process.on(signal,
|
|
198
|
+
process.on(signal, () => {
|
|
199
|
+
sweep();
|
|
200
|
+
});
|
|
15
201
|
}
|
|
16
202
|
//# sourceMappingURL=process-guard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-guard.js","sourceRoot":"","sources":["../../src/process/process-guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3C,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAqC,CAAC;AAE5F,MAAM,KAAK,GAAG,GAAS,EAAE;IACrB,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC;AAEF,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;AACvB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC/B,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAEjC,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC9B,CAAC","sourcesContent":["import { killMarkedProcesses } from \"./kill-marked-processes.ts\";\n\nconst GUARD_PREFIX = process.argv[2] ?? \"\";\nconst WATCHED_SIGNALS = [\"SIGTERM\", \"SIGINT\", \"SIGHUP\"] as const satisfies NodeJS.Signals[];\n\nconst sweep = (): void => {\n if (GUARD_PREFIX.length > 0) {\n killMarkedProcesses(GUARD_PREFIX);\n }\n\n process.exit(0);\n};\n\nprocess.stdin.resume();\nprocess.stdin.on(\"end\", sweep);\nprocess.stdin.on(\"error\", sweep);\n\nfor (const signal of WATCHED_SIGNALS) {\n process.on(signal, sweep);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"process-guard.js","sourceRoot":"","sources":["../../src/process/process-guard.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { killMarkedProcesses, killMarkedProcessRun } from \"./kill-marked-processes.ts\";\nimport {\n type CleanupDirectoryIdentity,\n killProcessGroup,\n type ProcessGroupIdentity,\n processGroupIdentity,\n removeCleanupDirectory,\n} from \"./kill-process-group.ts\";\n\nconst GUARD_PREFIX = process.argv[2] ?? \"\";\nconst PROCESS_WATCH_ARGUMENT = process.argv[3];\nconst WATCHED_SIGNALS = [\"SIGTERM\", \"SIGINT\", \"SIGHUP\"] as const satisfies NodeJS.Signals[];\nconst OWNER_POLL_INTERVAL_MS = 50;\nconst SUPERVISOR_EXIT_TIMEOUT_MS = 2000;\n\ntype ProcessIdentity = {\n pid: number;\n startTime: string;\n};\n\ntype ProcessWatch = {\n owner: ProcessIdentity;\n target: ProcessIdentity;\n};\n\ntype GuardJob = {\n marker: string;\n processGroup: ProcessGroupIdentity;\n cleanupDirectories: CleanupDirectoryIdentity[];\n signal: NodeJS.Signals;\n};\n\nconst state: { bufferedCommands: string; isSweeping: boolean; jobs: Map<string, GuardJob> } = {\n bufferedCommands: \"\",\n isSweeping: false,\n jobs: new Map(),\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isProcessIdentity = (value: unknown): value is ProcessIdentity =>\n isRecord(value) &&\n typeof value.pid === \"number\" &&\n Number.isSafeInteger(value.pid) &&\n value.pid > 1 &&\n typeof value.startTime === \"string\" &&\n /^\\d+$/.test(value.startTime);\n\nconst isProcessWatch = (value: unknown): value is ProcessWatch =>\n isRecord(value) && isProcessIdentity(value.owner) && isProcessIdentity(value.target);\n\nconst isProcessGroupIdentity = (value: unknown): value is ProcessGroupIdentity =>\n isRecord(value) &&\n typeof value.processGroupId === \"number\" &&\n Number.isSafeInteger(value.processGroupId) &&\n value.processGroupId > 1 &&\n typeof value.leaderStartTime === \"string\" &&\n /^\\d+$/.test(value.leaderStartTime);\n\nconst isCleanupDirectoryIdentity = (value: unknown): value is CleanupDirectoryIdentity =>\n isRecord(value) &&\n typeof value.path === \"string\" &&\n typeof value.device === \"string\" &&\n typeof value.inode === \"string\" &&\n typeof value.userId === \"string\";\n\nconst isGuardJob = (value: unknown): value is GuardJob =>\n isRecord(value) &&\n typeof value.marker === \"string\" &&\n isProcessGroupIdentity(value.processGroup) &&\n Array.isArray(value.cleanupDirectories) &&\n value.cleanupDirectories.every(isCleanupDirectoryIdentity) &&\n (value.signal === \"SIGKILL\" || value.signal === \"SIGCONT\");\n\nconst parseProcessWatch = (): ProcessWatch | undefined => {\n if (PROCESS_WATCH_ARGUMENT === undefined) {\n return undefined;\n }\n\n try {\n const value: unknown = JSON.parse(PROCESS_WATCH_ARGUMENT);\n\n return isProcessWatch(value) ? value : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst currentProcessIdentity = (pid: number): ProcessIdentity | undefined => {\n try {\n const stat = readFileSync(`/proc/${String(pid)}/stat`, \"utf8\");\n const fields = stat.slice(stat.lastIndexOf(\") \") + 2).split(\" \", 20);\n const state = fields[0];\n const startTime = fields[19];\n\n return startTime !== undefined && state !== undefined && ![\"Z\", \"X\", \"x\"].includes(state)\n ? { pid, startTime }\n : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst isCurrentProcess = (identity: ProcessIdentity): boolean =>\n currentProcessIdentity(identity.pid)?.startTime === identity.startTime;\n\nconst killProcess = (identity: ProcessIdentity): void => {\n if (!isCurrentProcess(identity)) {\n return;\n }\n\n try {\n process.kill(identity.pid, \"SIGKILL\");\n } catch {\n return;\n }\n};\n\nconst applyCommand = (command: string): void => {\n const operation = command[0];\n let value: unknown;\n\n try {\n value = JSON.parse(command.slice(1));\n } catch {\n return;\n }\n\n if (!isGuardJob(value)) {\n return;\n }\n\n if (operation === \"+\") {\n state.jobs.set(value.marker, value);\n } else if (operation === \"-\") {\n state.jobs.delete(value.marker);\n }\n};\n\nconst receiveCommands = (chunk: Buffer | string): void => {\n state.bufferedCommands += chunk.toString();\n const commands = state.bufferedCommands.split(\"\\n\");\n state.bufferedCommands = commands.pop() ?? \"\";\n\n for (const command of commands) {\n applyCommand(command);\n }\n};\n\nconst killJobs = (): void => {\n for (const job of state.jobs.values()) {\n killProcessGroup(job.processGroup, job.signal);\n\n if (job.signal === \"SIGKILL\") {\n killMarkedProcesses(job.marker);\n }\n }\n};\n\nconst removeCleanupDirectories = (): void => {\n const cleanupDirectories: Map<string, CleanupDirectoryIdentity> = new Map();\n\n for (const job of state.jobs.values()) {\n for (const identity of job.cleanupDirectories) {\n cleanupDirectories.set(`${identity.device}:${identity.inode}`, identity);\n }\n }\n\n for (const identity of cleanupDirectories.values()) {\n removeCleanupDirectory(identity);\n }\n};\n\nconst hasRunningSupervisor = (): boolean => {\n for (const job of state.jobs.values()) {\n if (job.signal !== \"SIGCONT\") {\n continue;\n }\n\n const current = processGroupIdentity(job.processGroup.processGroupId);\n\n if (current?.leaderStartTime === job.processGroup.leaderStartTime) {\n return true;\n }\n }\n\n return false;\n};\n\nconst forceSupervisors = (): void => {\n for (const job of state.jobs.values()) {\n if (job.signal === \"SIGCONT\") {\n killProcessGroup(job.processGroup);\n }\n }\n};\n\nconst finishSweep = (): void => {\n if (GUARD_PREFIX.length > 0) {\n killMarkedProcessRun(GUARD_PREFIX);\n }\n\n removeCleanupDirectories();\n process.exit(0);\n};\n\nconst awaitSupervisors = (deadline: number): void => {\n if (hasRunningSupervisor() && Date.now() < deadline) {\n setTimeout(() => {\n awaitSupervisors(deadline);\n }, OWNER_POLL_INTERVAL_MS);\n\n return;\n }\n\n forceSupervisors();\n finishSweep();\n};\n\nconst sweep = (target?: ProcessIdentity): void => {\n if (state.isSweeping) {\n return;\n }\n\n state.isSweeping = true;\n applyCommand(state.bufferedCommands);\n\n if (target !== undefined) {\n killProcess(target);\n }\n\n killJobs();\n awaitSupervisors(Date.now() + SUPERVISOR_EXIT_TIMEOUT_MS);\n};\n\nconst watch = parseProcessWatch();\n\nconst startOwnerPoll = (): void => {\n if (watch === undefined) {\n return;\n }\n\n const ownerPoll = setInterval(() => {\n if (isCurrentProcess(watch.owner)) {\n return;\n }\n\n clearInterval(ownerPoll);\n sweep(watch.target);\n }, OWNER_POLL_INTERVAL_MS);\n\n if (!isCurrentProcess(watch.owner)) {\n clearInterval(ownerPoll);\n sweep(watch.target);\n }\n};\n\nstartOwnerPoll();\n\nprocess.stdin.resume();\nprocess.stdin.on(\"data\", receiveCommands);\nprocess.stdin.on(\"end\", () => {\n sweep();\n});\nprocess.stdin.on(\"error\", () => {\n sweep();\n});\n\nfor (const signal of WATCHED_SIGNALS) {\n process.on(signal, () => {\n sweep();\n });\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare const readProcessStatFields: (pid: number) => string[] | undefined;
|
|
2
|
+
declare const isReapedState: (state: string | undefined) => boolean;
|
|
3
|
+
declare const isProcessAlive: (pid: number | undefined) => boolean;
|
|
4
|
+
export { isProcessAlive, isReapedState, readProcessStatFields };
|
|
5
|
+
//# sourceMappingURL=process-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-status.d.ts","sourceRoot":"","sources":["../../src/process/process-status.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,MAAM,EAAE,GAAG,SAavD,CAAC;AAEF,QAAA,MAAM,aAAa,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,OAA0D,CAAC;AAE9G,QAAA,MAAM,cAAc,GAAI,KAAK,MAAM,GAAG,SAAS,KAAG,OACiC,CAAC;AAEpF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,qBAAqB,EAAE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
const REAPED_STATES = new Set(["Z", "X", "x"]);
|
|
3
|
+
const readProcessStatFields = (pid) => {
|
|
4
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
const stat = readFileSync(`/proc/${String(pid)}/stat`, "utf8");
|
|
9
|
+
const separator = stat.lastIndexOf(") ");
|
|
10
|
+
return separator === -1 ? undefined : stat.slice(separator + 2).split(" ");
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const isReapedState = (state) => state === undefined || REAPED_STATES.has(state);
|
|
17
|
+
const isProcessAlive = (pid) => pid !== undefined && pid > 1 && !isReapedState(readProcessStatFields(pid)?.[0]);
|
|
18
|
+
export { isProcessAlive, isReapedState, readProcessStatFields };
|
|
19
|
+
//# sourceMappingURL=process-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-status.js","sourceRoot":"","sources":["../../src/process/process-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,aAAa,GAAwB,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAEpE,MAAM,qBAAqB,GAAG,CAAC,GAAW,EAAwB,EAAE;IAChE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QACzC,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAEzC,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,KAAyB,EAAW,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAE9G,MAAM,cAAc,GAAG,CAAC,GAAuB,EAAW,EAAE,CACxD,GAAG,KAAK,SAAS,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,qBAAqB,EAAE,CAAC","sourcesContent":["import { readFileSync } from \"node:fs\";\n\nconst REAPED_STATES: ReadonlySet<string> = new Set([\"Z\", \"X\", \"x\"]);\n\nconst readProcessStatFields = (pid: number): string[] | undefined => {\n if (!Number.isSafeInteger(pid) || pid <= 0) {\n return undefined;\n }\n\n try {\n const stat = readFileSync(`/proc/${String(pid)}/stat`, \"utf8\");\n const separator = stat.lastIndexOf(\") \");\n\n return separator === -1 ? undefined : stat.slice(separator + 2).split(\" \");\n } catch {\n return undefined;\n }\n};\n\nconst isReapedState = (state: string | undefined): boolean => state === undefined || REAPED_STATES.has(state);\n\nconst isProcessAlive = (pid: number | undefined): boolean =>\n pid !== undefined && pid > 1 && !isReapedState(readProcessStatFields(pid)?.[0]);\n\nexport { isProcessAlive, isReapedState, readProcessStatFields };\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare
|
|
2
|
-
declare
|
|
1
|
+
declare const tryResolveExecutable: (command: string) => string | undefined;
|
|
2
|
+
declare const resolveExecutable: (command: string) => string;
|
|
3
3
|
export { resolveExecutable, tryResolveExecutable };
|
|
4
4
|
//# sourceMappingURL=resolve-executable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-executable.d.ts","sourceRoot":"","sources":["../../src/process/resolve-executable.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolve-executable.d.ts","sourceRoot":"","sources":["../../src/process/resolve-executable.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,oBAAoB,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,SACF,CAAC;AAExD,QAAA,MAAM,iBAAiB,GAAI,SAAS,MAAM,KAAG,MAA6B,CAAC;AAE3E,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -1,39 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
try {
|
|
5
|
-
accessSync(path, constants.X_OK);
|
|
6
|
-
return statSync(path).isFile();
|
|
7
|
-
}
|
|
8
|
-
catch {
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
const findOnPath = (command) => {
|
|
13
|
-
const searchPaths = (process.env.PATH ?? "").split(delimiter).filter((entry) => entry.length > 0);
|
|
14
|
-
for (const directory of searchPaths) {
|
|
15
|
-
const candidate = join(directory, command);
|
|
16
|
-
if (isExecutable(candidate)) {
|
|
17
|
-
return candidate;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return undefined;
|
|
21
|
-
};
|
|
22
|
-
function tryResolveExecutable(command) {
|
|
23
|
-
if (isAbsolute(command)) {
|
|
24
|
-
return command;
|
|
25
|
-
}
|
|
26
|
-
if (command.includes("/")) {
|
|
27
|
-
return resolve(command);
|
|
28
|
-
}
|
|
29
|
-
return findOnPath(command);
|
|
30
|
-
}
|
|
31
|
-
function resolveExecutable(command) {
|
|
32
|
-
const found = tryResolveExecutable(command);
|
|
33
|
-
if (found === undefined) {
|
|
34
|
-
throw new Error(`Cannot find the "${command}" executable on PATH`);
|
|
35
|
-
}
|
|
36
|
-
return found;
|
|
37
|
-
}
|
|
1
|
+
import which from "which";
|
|
2
|
+
const tryResolveExecutable = (command) => which.sync(command, { nothrow: true }) ?? undefined;
|
|
3
|
+
const resolveExecutable = (command) => which.sync(command);
|
|
38
4
|
export { resolveExecutable, tryResolveExecutable };
|
|
39
5
|
//# sourceMappingURL=resolve-executable.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-executable.js","sourceRoot":"","sources":["../../src/process/resolve-executable.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"resolve-executable.js","sourceRoot":"","sources":["../../src/process/resolve-executable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,oBAAoB,GAAG,CAAC,OAAe,EAAsB,EAAE,CACjE,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,SAAS,CAAC;AAExD,MAAM,iBAAiB,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAE3E,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,CAAC","sourcesContent":["import which from \"which\";\n\nconst tryResolveExecutable = (command: string): string | undefined =>\n which.sync(command, { nothrow: true }) ?? undefined;\n\nconst resolveExecutable = (command: string): string => which.sync(command);\n\nexport { resolveExecutable, tryResolveExecutable };\n"]}
|
|
@@ -2,7 +2,13 @@ import { type ChildProcess, type StdioOptions } from "node:child_process";
|
|
|
2
2
|
type ParentDeathSpawnOptions = {
|
|
3
3
|
stdio?: StdioOptions;
|
|
4
4
|
env?: NodeJS.ProcessEnv;
|
|
5
|
+
cleanupDirectories?: string[];
|
|
5
6
|
};
|
|
7
|
+
type ParentDeathSupervisorOptions = Omit<ParentDeathSpawnOptions, "cleanupDirectories"> & {
|
|
8
|
+
cleanupDirectory: string;
|
|
9
|
+
};
|
|
10
|
+
declare const watchParentProcess: () => void;
|
|
6
11
|
declare function spawnWithParentDeathSignal(command: string, args: string[], options?: ParentDeathSpawnOptions): ChildProcess;
|
|
7
|
-
|
|
12
|
+
declare const spawnWithParentDeathSupervisor: (command: string, args: string[], options: ParentDeathSupervisorOptions) => ChildProcess;
|
|
13
|
+
export { spawnWithParentDeathSignal, spawnWithParentDeathSupervisor, watchParentProcess };
|
|
8
14
|
//# sourceMappingURL=spawn-with-parent-death-signal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn-with-parent-death-signal.d.ts","sourceRoot":"","sources":["../../src/process/spawn-with-parent-death-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"spawn-with-parent-death-signal.d.ts","sourceRoot":"","sources":["../../src/process/spawn-with-parent-death-signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAmBjF,KAAK,uBAAuB,GAAG;IAC3B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC,CAAC;AAEF,KAAK,4BAA4B,GAAG,IAAI,CAAC,uBAAuB,EAAE,oBAAoB,CAAC,GAAG;IACtF,gBAAgB,EAAE,MAAM,CAAC;CAC5B,CAAC;AA8QF,QAAA,MAAM,kBAAkB,QAAO,IAY9B,CAAC;AAiHF,iBAAS,0BAA0B,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,uBAA4B,GACtC,YAAY,CAOd;AAED,QAAA,MAAM,8BAA8B,GAChC,SAAS,MAAM,EACf,MAAM,MAAM,EAAE,EACd,SAAS,4BAA4B,KACtC,YA2CF,CAAC;AAEF,OAAO,EAAE,0BAA0B,EAAE,8BAA8B,EAAE,kBAAkB,EAAE,CAAC"}
|