@gtkx/utils 1.6.0 → 2.0.0-beta.2
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 +5 -5
- 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 +1 -0
- package/dist/process/index.d.ts.map +1 -1
- package/dist/process/index.js +1 -0
- 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 +44 -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 +72 -0
- package/dist/process/kill-process-group.js.map +1 -0
- package/dist/process/process-guard.js +77 -2
- package/dist/process/process-guard.js.map +1 -1
- 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 +1 -0
- package/dist/process/spawn-with-parent-death-signal.d.ts.map +1 -1
- package/dist/process/spawn-with-parent-death-signal.js +66 -3
- package/dist/process/spawn-with-parent-death-signal.js.map +1 -1
- package/package.json +9 -3
- package/src/index.ts +1 -1
- package/src/path.ts +17 -0
- package/src/process/index.ts +5 -0
- package/src/process/kill-marked-processes.ts +62 -13
- package/src/process/kill-process-group.ts +104 -0
- package/src/process/process-guard.ts +106 -2
- package/src/process/resolve-executable.ts +4 -46
- package/src/process/spawn-with-parent-death-signal.ts +106 -3
- 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
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<p align="center">
|
|
14
14
|
<a href="https://www.npmjs.com/package/create-gtkx"><img src="https://img.shields.io/npm/v/create-gtkx?color=cb3837&logo=npm&label=create-gtkx" alt="npm version" /></a>
|
|
15
15
|
<a href="https://www.npmjs.com/package/create-gtkx"><img src="https://img.shields.io/npm/dm/create-gtkx?color=cb3837&logo=npm&label=downloads" alt="npm downloads" /></a>
|
|
16
|
-
<img src="https://img.shields.io/badge/node-%E2%89%
|
|
16
|
+
<img src="https://img.shields.io/badge/node-%E2%89%A526.7-339933?logo=node.js&logoColor=white" alt="Node >= 26.7" />
|
|
17
17
|
<a href="https://github.com/gtkx-org/gtkx/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MPL--2.0-blue.svg" alt="License: MPL-2.0" /></a>
|
|
18
18
|
<a href="https://github.com/gtkx-org/gtkx/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/gtkx-org/gtkx/ci.yml?branch=main&logo=github&label=CI" alt="CI status" /></a>
|
|
19
19
|
<img src="https://img.shields.io/badge/TypeScript-strict-3178c6?logo=typescript&logoColor=white" alt="TypeScript" />
|
|
@@ -116,7 +116,7 @@ At runtime, the native Rust core calls straight into the system GTK4, Adwaita, a
|
|
|
116
116
|
|
|
117
117
|
## Quick start
|
|
118
118
|
|
|
119
|
-
GTKX is Linux-only and needs Node.js
|
|
119
|
+
GTKX is Linux-only and needs Node.js 26.7 or later. See [Requirements](#requirements).
|
|
120
120
|
|
|
121
121
|
Scaffold a new app with the `create-gtkx` initializer:
|
|
122
122
|
|
|
@@ -145,8 +145,8 @@ The documentation at **[gtkx.dev](https://gtkx.dev)** includes a step-by-step tu
|
|
|
145
145
|
|
|
146
146
|
GTKX is Linux-only. You need:
|
|
147
147
|
|
|
148
|
-
- Linux with the GTK4 (4.20 or later)
|
|
149
|
-
- Node.js
|
|
148
|
+
- Linux with the GTK4 (4.20 or later), Adwaita (1.8 or later), and GLib development libraries
|
|
149
|
+
- Node.js 26.7 or later
|
|
150
150
|
|
|
151
151
|
The `@gtkx/native` addon ships prebuilt for x64 and arm64 glibc Linux; other targets need to build it from the GTKX repository, which requires a Rust toolchain.
|
|
152
152
|
|
|
@@ -167,7 +167,7 @@ GTKX is stable and ready for production use.
|
|
|
167
167
|
|
|
168
168
|
## Contributing
|
|
169
169
|
|
|
170
|
-
Contributions are welcome. See [CONTRIBUTING.md](https://github.com/gtkx-org/gtkx/blob/main/CONTRIBUTING.md), the [Code of Conduct](https://github.com/gtkx-org/gtkx/blob/main/CODE_OF_CONDUCT.md), and the [security policy](https://github.com/gtkx-org/gtkx/blob/main/SECURITY.md). Building the repo needs Node.js
|
|
170
|
+
Contributions are welcome. See [CONTRIBUTING.md](https://github.com/gtkx-org/gtkx/blob/main/CONTRIBUTING.md), the [Code of Conduct](https://github.com/gtkx-org/gtkx/blob/main/CODE_OF_CONDUCT.md), and the [security policy](https://github.com/gtkx-org/gtkx/blob/main/SECURITY.md). Building the repo needs Node.js 26.7 or later, pnpm, and a Rust toolchain.
|
|
171
171
|
|
|
172
172
|
## License
|
|
173
173
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ export * from "./array/index.ts";
|
|
|
2
2
|
export * from "./class/index.ts";
|
|
3
3
|
export * from "./error/index.ts";
|
|
4
4
|
export * from "./log/index.ts";
|
|
5
|
-
export * from "./map/index.ts";
|
|
6
5
|
export * from "./object/index.ts";
|
|
6
|
+
export * from "./path.ts";
|
|
7
7
|
export * from "./predicate/index.ts";
|
|
8
8
|
export * from "./process/index.ts";
|
|
9
9
|
export * from "./set/index.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@ export * from "./array/index.js";
|
|
|
2
2
|
export * from "./class/index.js";
|
|
3
3
|
export * from "./error/index.js";
|
|
4
4
|
export * from "./log/index.js";
|
|
5
|
-
export * from "./map/index.js";
|
|
6
5
|
export * from "./object/index.js";
|
|
6
|
+
export * from "./path.js";
|
|
7
7
|
export * from "./predicate/index.js";
|
|
8
8
|
export * from "./process/index.js";
|
|
9
9
|
export * from "./set/index.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC","sourcesContent":["export * from \"./array/index.ts\";\nexport * from \"./class/index.ts\";\nexport * from \"./error/index.ts\";\nexport * from \"./log/index.ts\";\nexport * from \"./object/index.ts\";\nexport * from \"./path.ts\";\nexport * from \"./predicate/index.ts\";\nexport * from \"./process/index.ts\";\nexport * from \"./set/index.ts\";\nexport * from \"./source/index.ts\";\nexport * from \"./string/index.ts\";\n"]}
|
package/dist/path.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare const isPathInside: (parent: string, candidate: string) => boolean;
|
|
2
|
+
declare const isPathWithin: (parent: string, candidate: string) => boolean;
|
|
3
|
+
declare const toPosixPath: (path: string) => string;
|
|
4
|
+
export { isPathInside, isPathWithin, toPosixPath };
|
|
5
|
+
//# sourceMappingURL=path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,WAAW,MAAM,KAAG,OAIzD,CAAC;AAEF,QAAA,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,WAAW,MAAM,KAAG,OACX,CAAC;AAEhD,QAAA,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,MAAoC,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/path.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isAbsolute, relative, sep } from "node:path";
|
|
2
|
+
const isOutsidePath = (path) => path === ".." || path.startsWith(`..${sep}`) || isAbsolute(path);
|
|
3
|
+
const isPathInside = (parent, candidate) => {
|
|
4
|
+
const path = relative(parent, candidate);
|
|
5
|
+
return path !== "" && !isOutsidePath(path);
|
|
6
|
+
};
|
|
7
|
+
const isPathWithin = (parent, candidate) => !isOutsidePath(relative(parent, candidate));
|
|
8
|
+
const toPosixPath = (path) => path.replaceAll("\\", "/");
|
|
9
|
+
export { isPathInside, isPathWithin, toPosixPath };
|
|
10
|
+
//# sourceMappingURL=path.js.map
|
package/dist/path.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,aAAa,GAAG,CAAC,IAAY,EAAW,EAAE,CAC5C,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAErE,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,SAAiB,EAAW,EAAE;IAChE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAEzC,OAAO,IAAI,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,SAAiB,EAAW,EAAE,CAChE,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAEhD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC","sourcesContent":["import { isAbsolute, relative, sep } from \"node:path\";\n\nconst isOutsidePath = (path: string): boolean =>\n path === \"..\" || path.startsWith(`..${sep}`) || isAbsolute(path);\n\nconst isPathInside = (parent: string, candidate: string): boolean => {\n const path = relative(parent, candidate);\n\n return path !== \"\" && !isOutsidePath(path);\n};\n\nconst isPathWithin = (parent: string, candidate: string): boolean =>\n !isOutsidePath(relative(parent, candidate));\n\nconst toPosixPath = (path: string): string => path.replaceAll(\"\\\\\", \"/\");\n\nexport { isPathInside, isPathWithin, toPosixPath };\n"]}
|
package/dist/process/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { exitCodeForSignal } from "./exit-code-for-signal.ts";
|
|
2
2
|
export { installGracefulShutdown } from "./install-graceful-shutdown.ts";
|
|
3
|
+
export { killProcessGroup, type ProcessGroupIdentity, processGroupIdentity, } from "./kill-process-group.ts";
|
|
3
4
|
export { resolveExecutable, tryResolveExecutable } from "./resolve-executable.ts";
|
|
4
5
|
export { spawnWithParentDeathSignal } from "./spawn-with-parent-death-signal.ts";
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/process/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/process/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EACH,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,oBAAoB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC"}
|
package/dist/process/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { exitCodeForSignal } from "./exit-code-for-signal.js";
|
|
2
2
|
export { installGracefulShutdown } from "./install-graceful-shutdown.js";
|
|
3
|
+
export { killProcessGroup, processGroupIdentity, } from "./kill-process-group.js";
|
|
3
4
|
export { resolveExecutable, tryResolveExecutable } from "./resolve-executable.js";
|
|
4
5
|
export { spawnWithParentDeathSignal } from "./spawn-with-parent-death-signal.js";
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/process/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC","sourcesContent":["export { exitCodeForSignal } from \"./exit-code-for-signal.ts\";\nexport { installGracefulShutdown } from \"./install-graceful-shutdown.ts\";\nexport { resolveExecutable, tryResolveExecutable } from \"./resolve-executable.ts\";\nexport { spawnWithParentDeathSignal } from \"./spawn-with-parent-death-signal.ts\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/process/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EACH,gBAAgB,EAEhB,oBAAoB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC","sourcesContent":["export { exitCodeForSignal } from \"./exit-code-for-signal.ts\";\nexport { installGracefulShutdown } from \"./install-graceful-shutdown.ts\";\nexport {\n killProcessGroup,\n type ProcessGroupIdentity,\n processGroupIdentity,\n} from \"./kill-process-group.ts\";\nexport { resolveExecutable, tryResolveExecutable } from \"./resolve-executable.ts\";\nexport { spawnWithParentDeathSignal } from \"./spawn-with-parent-death-signal.ts\";\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
declare const PROCESS_MARKER = "GTKX_PROCESS_GUARD";
|
|
2
|
-
declare
|
|
3
|
-
|
|
2
|
+
declare const killMarkedProcesses: (marker: string) => void;
|
|
3
|
+
declare const killMarkedProcessRun: (runPrefix: string) => void;
|
|
4
|
+
export { PROCESS_MARKER, killMarkedProcessRun, killMarkedProcesses };
|
|
4
5
|
//# sourceMappingURL=kill-marked-processes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kill-marked-processes.d.ts","sourceRoot":"","sources":["../../src/process/kill-marked-processes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"kill-marked-processes.d.ts","sourceRoot":"","sources":["../../src/process/kill-marked-processes.ts"],"names":[],"mappings":"AAUA,QAAA,MAAM,cAAc,uBAAuB,CAAC;AAwE5C,QAAA,MAAM,mBAAmB,GAAI,QAAQ,MAAM,KAAG,IAE7C,CAAC;AAEF,QAAA,MAAM,oBAAoB,GAAI,WAAW,MAAM,KAAG,IAIjD,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -1,38 +1,69 @@
|
|
|
1
1
|
import { readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
const PROCESS_MARKER = "GTKX_PROCESS_GUARD";
|
|
3
3
|
const MAX_KILL_PASSES = 8;
|
|
4
|
-
const
|
|
4
|
+
const JOB_ID_PATTERN = /^[0-9a-f]{8}$/;
|
|
5
|
+
const processIdentity = (pid) => {
|
|
6
|
+
try {
|
|
7
|
+
const stat = readFileSync(`/proc/${String(pid)}/stat`, "utf8");
|
|
8
|
+
const fields = stat.slice(stat.lastIndexOf(") ") + 2).split(" ");
|
|
9
|
+
const sessionId = Number(fields[3]);
|
|
10
|
+
const startTime = fields[19];
|
|
11
|
+
return startTime !== undefined && Number.isSafeInteger(sessionId)
|
|
12
|
+
? { pid, sessionId, startTime }
|
|
13
|
+
: undefined;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const isMarked = (pid, isMatch) => {
|
|
5
20
|
try {
|
|
6
21
|
return readFileSync(`/proc/${String(pid)}/environ`, "utf8")
|
|
7
22
|
.split("\0")
|
|
8
|
-
.some((assignment) => assignment
|
|
23
|
+
.some((assignment) => isMatch(assignment));
|
|
9
24
|
}
|
|
10
25
|
catch {
|
|
11
26
|
return false;
|
|
12
27
|
}
|
|
13
28
|
};
|
|
14
|
-
const
|
|
29
|
+
const markedProcesses = (isMatch) => readdirSync("/proc")
|
|
15
30
|
.map(Number)
|
|
16
31
|
.filter((pid) => Number.isSafeInteger(pid) && pid > 1 && pid !== process.pid)
|
|
17
|
-
.filter((pid) => isMarked(pid,
|
|
18
|
-
|
|
32
|
+
.filter((pid) => isMarked(pid, isMatch))
|
|
33
|
+
.map((pid) => processIdentity(pid))
|
|
34
|
+
.filter((identity) => identity !== undefined);
|
|
35
|
+
const killProcess = (identity, isMatch) => {
|
|
36
|
+
if (!isMarked(identity.pid, isMatch)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const current = processIdentity(identity.pid);
|
|
40
|
+
if (current?.sessionId !== identity.sessionId ||
|
|
41
|
+
current.startTime !== identity.startTime) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
19
44
|
try {
|
|
20
|
-
process.kill(pid, "SIGKILL");
|
|
45
|
+
process.kill(identity.pid, "SIGKILL");
|
|
21
46
|
}
|
|
22
47
|
catch {
|
|
23
48
|
return;
|
|
24
49
|
}
|
|
25
50
|
};
|
|
26
|
-
|
|
51
|
+
const killMatchingProcesses = (isMatch) => {
|
|
27
52
|
for (let pass = 0; pass < MAX_KILL_PASSES; pass += 1) {
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
53
|
+
const processes = markedProcesses(isMatch);
|
|
54
|
+
if (processes.length === 0) {
|
|
30
55
|
return;
|
|
31
56
|
}
|
|
32
|
-
for (const
|
|
33
|
-
|
|
57
|
+
for (const identity of processes) {
|
|
58
|
+
killProcess(identity, isMatch);
|
|
34
59
|
}
|
|
35
60
|
}
|
|
36
|
-
}
|
|
37
|
-
|
|
61
|
+
};
|
|
62
|
+
const killMarkedProcesses = (marker) => {
|
|
63
|
+
killMatchingProcesses((assignment) => assignment === marker);
|
|
64
|
+
};
|
|
65
|
+
const killMarkedProcessRun = (runPrefix) => {
|
|
66
|
+
killMatchingProcesses((assignment) => assignment.startsWith(runPrefix) && JOB_ID_PATTERN.test(assignment.slice(runPrefix.length)));
|
|
67
|
+
};
|
|
68
|
+
export { PROCESS_MARKER, killMarkedProcessRun, killMarkedProcesses };
|
|
38
69
|
//# sourceMappingURL=kill-marked-processes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kill-marked-processes.js","sourceRoot":"","sources":["../../src/process/kill-marked-processes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"kill-marked-processes.js","sourceRoot":"","sources":["../../src/process/kill-marked-processes.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, readFileSync } from \"node:fs\";\n\ntype ProcessIdentity = {\n pid: number;\n sessionId: number;\n startTime: string;\n};\n\ntype MarkerMatcher = (assignment: string) => boolean;\n\nconst PROCESS_MARKER = \"GTKX_PROCESS_GUARD\";\nconst MAX_KILL_PASSES = 8;\nconst JOB_ID_PATTERN = /^[0-9a-f]{8}$/;\n\nconst processIdentity = (pid: number): ProcessIdentity | undefined => {\n try {\n const stat = readFileSync(`/proc/${String(pid)}/stat`, \"utf8\");\n const fields = stat.slice(stat.lastIndexOf(\") \") + 2).split(\" \");\n const sessionId = Number(fields[3]);\n const startTime = fields[19];\n\n return startTime !== undefined && Number.isSafeInteger(sessionId)\n ? { pid, sessionId, startTime }\n : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst isMarked = (pid: number, isMatch: MarkerMatcher): boolean => {\n try {\n return readFileSync(`/proc/${String(pid)}/environ`, \"utf8\")\n .split(\"\\0\")\n .some((assignment) => isMatch(assignment));\n } catch {\n return false;\n }\n};\n\nconst markedProcesses = (isMatch: MarkerMatcher): ProcessIdentity[] =>\n readdirSync(\"/proc\")\n .map(Number)\n .filter((pid) => Number.isSafeInteger(pid) && pid > 1 && pid !== process.pid)\n .filter((pid) => isMarked(pid, isMatch))\n .map((pid) => processIdentity(pid))\n .filter((identity): identity is ProcessIdentity => identity !== undefined);\n\nconst killProcess = (identity: ProcessIdentity, isMatch: MarkerMatcher): void => {\n if (!isMarked(identity.pid, isMatch)) {\n return;\n }\n\n const current = processIdentity(identity.pid);\n\n if (\n current?.sessionId !== identity.sessionId ||\n current.startTime !== identity.startTime\n ) {\n return;\n }\n\n try {\n process.kill(identity.pid, \"SIGKILL\");\n } catch {\n return;\n }\n};\n\nconst killMatchingProcesses = (isMatch: MarkerMatcher): void => {\n for (let pass = 0; pass < MAX_KILL_PASSES; pass += 1) {\n const processes = markedProcesses(isMatch);\n\n if (processes.length === 0) {\n return;\n }\n\n for (const identity of processes) {\n killProcess(identity, isMatch);\n }\n }\n};\n\nconst killMarkedProcesses = (marker: string): void => {\n killMatchingProcesses((assignment) => assignment === marker);\n};\n\nconst killMarkedProcessRun = (runPrefix: string): void => {\n killMatchingProcesses((assignment) =>\n assignment.startsWith(runPrefix) && JOB_ID_PATTERN.test(assignment.slice(runPrefix.length)),\n );\n};\n\nexport { PROCESS_MARKER, killMarkedProcessRun, killMarkedProcesses };\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type ProcessGroupIdentity = {
|
|
2
|
+
processGroupId: number;
|
|
3
|
+
leaderStartTime: string;
|
|
4
|
+
};
|
|
5
|
+
type CleanupDirectoryIdentity = {
|
|
6
|
+
path: string;
|
|
7
|
+
device: string;
|
|
8
|
+
inode: string;
|
|
9
|
+
userId: string;
|
|
10
|
+
};
|
|
11
|
+
declare const processGroupIdentity: (processGroupId: number) => ProcessGroupIdentity | undefined;
|
|
12
|
+
declare const killProcessGroup: (identity: ProcessGroupIdentity) => void;
|
|
13
|
+
declare const cleanupDirectoryIdentity: (path: string) => CleanupDirectoryIdentity | undefined;
|
|
14
|
+
declare const removeCleanupDirectory: (identity: CleanupDirectoryIdentity) => void;
|
|
15
|
+
export { type CleanupDirectoryIdentity, cleanupDirectoryIdentity, killProcessGroup, type ProcessGroupIdentity, processGroupIdentity, removeCleanupDirectory, };
|
|
16
|
+
//# sourceMappingURL=kill-process-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kill-process-group.d.ts","sourceRoot":"","sources":["../../src/process/kill-process-group.ts"],"names":[],"mappings":"AAGA,KAAK,oBAAoB,GAAG;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,CAAC;AAIF,QAAA,MAAM,oBAAoB,GAAI,gBAAgB,MAAM,KAAG,oBAAoB,GAAG,SAkB7E,CAAC;AAQF,QAAA,MAAM,gBAAgB,GAAI,UAAU,oBAAoB,KAAG,IAU1D,CAAC;AAEF,QAAA,MAAM,wBAAwB,GAAI,MAAM,MAAM,KAAG,wBAAwB,GAAG,SAqB3E,CAAC;AAEF,QAAA,MAAM,sBAAsB,GAAI,UAAU,wBAAwB,KAAG,IAgBpE,CAAC;AAEF,OAAO,EACH,KAAK,wBAAwB,EAC7B,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,sBAAsB,GACzB,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { lstatSync, readFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, resolve } from "node:path";
|
|
3
|
+
const isProcessGroupId = (value) => Number.isSafeInteger(value) && value > 1;
|
|
4
|
+
const processGroupIdentity = (processGroupId) => {
|
|
5
|
+
if (!isProcessGroupId(processGroupId)) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
try {
|
|
9
|
+
const stat = readFileSync(`/proc/${String(processGroupId)}/stat`, "utf8");
|
|
10
|
+
const fields = stat.slice(stat.lastIndexOf(") ") + 2).split(" ");
|
|
11
|
+
const actualProcessGroupId = Number(fields[2]);
|
|
12
|
+
const sessionId = Number(fields[3]);
|
|
13
|
+
const leaderStartTime = fields[19];
|
|
14
|
+
return actualProcessGroupId === processGroupId && sessionId === processGroupId && leaderStartTime !== undefined
|
|
15
|
+
? { processGroupId, leaderStartTime }
|
|
16
|
+
: undefined;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const isCurrentProcessGroup = (identity) => {
|
|
23
|
+
const current = processGroupIdentity(identity.processGroupId);
|
|
24
|
+
return current?.leaderStartTime === identity.leaderStartTime;
|
|
25
|
+
};
|
|
26
|
+
const killProcessGroup = (identity) => {
|
|
27
|
+
if (!isCurrentProcessGroup(identity)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
process.kill(-identity.processGroupId, "SIGKILL");
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const cleanupDirectoryIdentity = (path) => {
|
|
38
|
+
const absolutePath = resolve(path);
|
|
39
|
+
if (absolutePath === "/" || !isAbsolute(path)) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const entry = lstatSync(absolutePath, { bigint: true });
|
|
44
|
+
return entry.isDirectory()
|
|
45
|
+
? {
|
|
46
|
+
path: absolutePath,
|
|
47
|
+
device: entry.dev.toString(),
|
|
48
|
+
inode: entry.ino.toString(),
|
|
49
|
+
userId: entry.uid.toString(),
|
|
50
|
+
}
|
|
51
|
+
: undefined;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const removeCleanupDirectory = (identity) => {
|
|
58
|
+
const current = cleanupDirectoryIdentity(identity.path);
|
|
59
|
+
if (current?.device !== identity.device ||
|
|
60
|
+
current.inode !== identity.inode ||
|
|
61
|
+
current.userId !== identity.userId) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
rmSync(identity.path, { recursive: true, force: true });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
export { cleanupDirectoryIdentity, killProcessGroup, processGroupIdentity, removeCleanupDirectory, };
|
|
72
|
+
//# sourceMappingURL=kill-process-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kill-process-group.js","sourceRoot":"","sources":["../../src/process/kill-process-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAchD,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAW,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;AAE9F,MAAM,oBAAoB,GAAG,CAAC,cAAsB,EAAoC,EAAE;IACtF,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,CAAC;QACpC,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QAEnC,OAAO,oBAAoB,KAAK,cAAc,IAAI,SAAS,KAAK,cAAc,IAAI,eAAe,KAAK,SAAS;YAC3G,CAAC,CAAC,EAAE,cAAc,EAAE,eAAe,EAAE;YACrC,CAAC,CAAC,SAAS,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,QAA8B,EAAW,EAAE;IACtE,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAE9D,OAAO,OAAO,EAAE,eAAe,KAAK,QAAQ,CAAC,eAAe,CAAC;AACjE,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,QAA8B,EAAQ,EAAE;IAC9D,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,OAAO;IACX,CAAC;IAED,IAAI,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO;IACX,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,CAAC,IAAY,EAAwC,EAAE;IACpF,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,YAAY,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAExD,OAAO,KAAK,CAAC,WAAW,EAAE;YACtB,CAAC,CAAC;gBACM,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;gBAC5B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;gBAC3B,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;aAC/B;YACL,CAAC,CAAC,SAAS,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,QAAkC,EAAQ,EAAE;IACxE,MAAM,OAAO,GAAG,wBAAwB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAExD,IACI,OAAO,EAAE,MAAM,KAAK,QAAQ,CAAC,MAAM;QACnC,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK;QAChC,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EACpC,CAAC;QACC,OAAO;IACX,CAAC;IAED,IAAI,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACL,OAAO;IACX,CAAC;AACL,CAAC,CAAC;AAEF,OAAO,EAEH,wBAAwB,EACxB,gBAAgB,EAEhB,oBAAoB,EACpB,sBAAsB,GACzB,CAAC","sourcesContent":["import { lstatSync, readFileSync, rmSync } from \"node:fs\";\nimport { isAbsolute, resolve } from \"node:path\";\n\ntype ProcessGroupIdentity = {\n processGroupId: number;\n leaderStartTime: string;\n};\n\ntype CleanupDirectoryIdentity = {\n path: string;\n device: string;\n inode: string;\n userId: string;\n};\n\nconst isProcessGroupId = (value: number): boolean => Number.isSafeInteger(value) && value > 1;\n\nconst processGroupIdentity = (processGroupId: number): ProcessGroupIdentity | undefined => {\n if (!isProcessGroupId(processGroupId)) {\n return undefined;\n }\n\n try {\n const stat = readFileSync(`/proc/${String(processGroupId)}/stat`, \"utf8\");\n const fields = stat.slice(stat.lastIndexOf(\") \") + 2).split(\" \");\n const actualProcessGroupId = Number(fields[2]);\n const sessionId = Number(fields[3]);\n const leaderStartTime = fields[19];\n\n return actualProcessGroupId === processGroupId && sessionId === processGroupId && leaderStartTime !== undefined\n ? { processGroupId, leaderStartTime }\n : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst isCurrentProcessGroup = (identity: ProcessGroupIdentity): boolean => {\n const current = processGroupIdentity(identity.processGroupId);\n\n return current?.leaderStartTime === identity.leaderStartTime;\n};\n\nconst killProcessGroup = (identity: ProcessGroupIdentity): void => {\n if (!isCurrentProcessGroup(identity)) {\n return;\n }\n\n try {\n process.kill(-identity.processGroupId, \"SIGKILL\");\n } catch {\n return;\n }\n};\n\nconst cleanupDirectoryIdentity = (path: string): CleanupDirectoryIdentity | undefined => {\n const absolutePath = resolve(path);\n\n if (absolutePath === \"/\" || !isAbsolute(path)) {\n return undefined;\n }\n\n try {\n const entry = lstatSync(absolutePath, { bigint: true });\n\n return entry.isDirectory()\n ? {\n path: absolutePath,\n device: entry.dev.toString(),\n inode: entry.ino.toString(),\n userId: entry.uid.toString(),\n }\n : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst removeCleanupDirectory = (identity: CleanupDirectoryIdentity): void => {\n const current = cleanupDirectoryIdentity(identity.path);\n\n if (\n current?.device !== identity.device ||\n current.inode !== identity.inode ||\n current.userId !== identity.userId\n ) {\n return;\n }\n\n try {\n rmSync(identity.path, { recursive: true, force: true });\n } catch {\n return;\n }\n};\n\nexport {\n type CleanupDirectoryIdentity,\n cleanupDirectoryIdentity,\n killProcessGroup,\n type ProcessGroupIdentity,\n processGroupIdentity,\n removeCleanupDirectory,\n};\n"]}
|
|
@@ -1,13 +1,88 @@
|
|
|
1
|
-
import { killMarkedProcesses } from "./kill-marked-processes.js";
|
|
1
|
+
import { killMarkedProcesses, killMarkedProcessRun } from "./kill-marked-processes.js";
|
|
2
|
+
import { killProcessGroup, removeCleanupDirectory, } from "./kill-process-group.js";
|
|
2
3
|
const GUARD_PREFIX = process.argv[2] ?? "";
|
|
3
4
|
const WATCHED_SIGNALS = ["SIGTERM", "SIGINT", "SIGHUP"];
|
|
5
|
+
const state = {
|
|
6
|
+
bufferedCommands: "",
|
|
7
|
+
isSweeping: false,
|
|
8
|
+
jobs: new Map(),
|
|
9
|
+
};
|
|
10
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
const isProcessGroupIdentity = (value) => isRecord(value) &&
|
|
12
|
+
typeof value.processGroupId === "number" &&
|
|
13
|
+
Number.isSafeInteger(value.processGroupId) &&
|
|
14
|
+
value.processGroupId > 1 &&
|
|
15
|
+
typeof value.leaderStartTime === "string" &&
|
|
16
|
+
/^\d+$/.test(value.leaderStartTime);
|
|
17
|
+
const isCleanupDirectoryIdentity = (value) => isRecord(value) &&
|
|
18
|
+
typeof value.path === "string" &&
|
|
19
|
+
typeof value.device === "string" &&
|
|
20
|
+
typeof value.inode === "string" &&
|
|
21
|
+
typeof value.userId === "string";
|
|
22
|
+
const isGuardJob = (value) => isRecord(value) &&
|
|
23
|
+
typeof value.marker === "string" &&
|
|
24
|
+
isProcessGroupIdentity(value.processGroup) &&
|
|
25
|
+
Array.isArray(value.cleanupDirectories) &&
|
|
26
|
+
value.cleanupDirectories.every(isCleanupDirectoryIdentity);
|
|
27
|
+
const applyCommand = (command) => {
|
|
28
|
+
const operation = command[0];
|
|
29
|
+
let value;
|
|
30
|
+
try {
|
|
31
|
+
value = JSON.parse(command.slice(1));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (!isGuardJob(value)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (operation === "+") {
|
|
40
|
+
state.jobs.set(value.marker, value);
|
|
41
|
+
}
|
|
42
|
+
else if (operation === "-") {
|
|
43
|
+
state.jobs.delete(value.marker);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const receiveCommands = (chunk) => {
|
|
47
|
+
state.bufferedCommands += chunk.toString();
|
|
48
|
+
const commands = state.bufferedCommands.split("\n");
|
|
49
|
+
state.bufferedCommands = commands.pop() ?? "";
|
|
50
|
+
for (const command of commands) {
|
|
51
|
+
applyCommand(command);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const killJobs = () => {
|
|
55
|
+
for (const job of state.jobs.values()) {
|
|
56
|
+
killProcessGroup(job.processGroup);
|
|
57
|
+
killMarkedProcesses(job.marker);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const removeCleanupDirectories = () => {
|
|
61
|
+
const cleanupDirectories = new Map();
|
|
62
|
+
for (const job of state.jobs.values()) {
|
|
63
|
+
for (const identity of job.cleanupDirectories) {
|
|
64
|
+
cleanupDirectories.set(`${identity.device}:${identity.inode}`, identity);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const identity of cleanupDirectories.values()) {
|
|
68
|
+
removeCleanupDirectory(identity);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
4
71
|
const sweep = () => {
|
|
72
|
+
if (state.isSweeping) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
state.isSweeping = true;
|
|
76
|
+
applyCommand(state.bufferedCommands);
|
|
77
|
+
killJobs();
|
|
5
78
|
if (GUARD_PREFIX.length > 0) {
|
|
6
|
-
|
|
79
|
+
killMarkedProcessRun(GUARD_PREFIX);
|
|
7
80
|
}
|
|
81
|
+
removeCleanupDirectories();
|
|
8
82
|
process.exit(0);
|
|
9
83
|
};
|
|
10
84
|
process.stdin.resume();
|
|
85
|
+
process.stdin.on("data", receiveCommands);
|
|
11
86
|
process.stdin.on("end", sweep);
|
|
12
87
|
process.stdin.on("error", sweep);
|
|
13
88
|
for (const signal of WATCHED_SIGNALS) {
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"process-guard.js","sourceRoot":"","sources":["../../src/process/process-guard.ts"],"names":[],"mappings":"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","sourcesContent":["import { killMarkedProcesses, killMarkedProcessRun } from \"./kill-marked-processes.ts\";\nimport {\n type CleanupDirectoryIdentity,\n killProcessGroup,\n type ProcessGroupIdentity,\n removeCleanupDirectory,\n} from \"./kill-process-group.ts\";\n\nconst GUARD_PREFIX = process.argv[2] ?? \"\";\nconst WATCHED_SIGNALS = [\"SIGTERM\", \"SIGINT\", \"SIGHUP\"] as const satisfies NodeJS.Signals[];\ntype GuardJob = {\n marker: string;\n processGroup: ProcessGroupIdentity;\n cleanupDirectories: CleanupDirectoryIdentity[];\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 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\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);\n killMarkedProcesses(job.marker);\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 sweep = (): void => {\n if (state.isSweeping) {\n return;\n }\n\n state.isSweeping = true;\n applyCommand(state.bufferedCommands);\n killJobs();\n\n if (GUARD_PREFIX.length > 0) {\n killMarkedProcessRun(GUARD_PREFIX);\n }\n\n removeCleanupDirectories();\n process.exit(0);\n};\n\nprocess.stdin.resume();\nprocess.stdin.on(\"data\", receiveCommands);\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,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,6 +2,7 @@ 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
|
};
|
|
6
7
|
declare function spawnWithParentDeathSignal(command: string, args: string[], options?: ParentDeathSpawnOptions): ChildProcess;
|
|
7
8
|
export { spawnWithParentDeathSignal };
|
|
@@ -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;AAgBjF,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;AA0GF,iBAAS,0BAA0B,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,uBAA4B,GACtC,YAAY,CA4Cd;AAED,OAAO,EAAE,0BAA0B,EAAE,CAAC"}
|