Skip to content

Commit 1a8df7b

Browse files
authored
Merge pull request #1032 from thefrontside/tm/no-sigterm-windows-v4
2 parents 670e512 + fa2f4ec commit 1a8df7b

File tree

8 files changed

+102
-34
lines changed

8 files changed

+102
-34
lines changed

.gitattributes

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Set default line ending behavior
2+
* text=auto
3+
4+
# Explicitly set line endings for text files
5+
*.ts text eol=lf
6+
*.mjs text eol=lf
7+
*.js text eol=lf
8+
*.json text eol=lf
9+
*.md text eol=lf
10+
*.yml text eol=lf
11+
*.yaml text eol=lf
12+
13+
# Binary files
14+
*.png binary
15+
*.jpg binary
16+
*.jpeg binary
17+
*.gif binary
18+
*.ico binary
19+
*.woff binary
20+
*.woff2 binary

.github/workflows/verify.yaml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ permissions:
1010
contents: read
1111

1212
jobs:
13-
test-deno:
14-
runs-on: ubuntu-latest
13+
test:
14+
strategy:
15+
matrix:
16+
os: [ubuntu-latest, macos-latest, windows-latest]
17+
runs-on: ${{ matrix.os }}
1518

1619
steps:
1720
- name: checkout
@@ -28,7 +31,13 @@ jobs:
2831
- name: lint
2932
run: deno lint
3033

31-
- name: test
34+
- name: test (Windows)
35+
if: runner.os == 'Windows'
36+
run: deno task test
37+
shell: cmd
38+
39+
- name: test (Unix)
40+
if: runner.os != 'Windows'
3241
run: deno task test
3342

3443
test-node:

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 4.0.0-alpha.9
4+
5+
- Do not bind SIGTERM in Windows for v4
6+
https://github.com/thefrontside/effection/pull/1032
7+
38
## 4.0.0-alpha.8
49

510
- Add `until()` operation for turning promises into operations

deno.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
"publish": { "include": ["lib", "mod.ts", "README.md"] },
66
"lock": false,
77
"tasks": {
8-
"test": "deno test --allow-run=deno --allow-read --allow-env",
8+
"test": "deno test --allow-run --allow-read --allow-env --allow-ffi",
99
"test:node": "deno run -A tasks/built-test.ts",
1010
"build:npm": "deno run -A tasks/build-npm.ts",
1111
"bench": "deno run -A tasks/bench.ts",
1212
"build:jsr": "deno run -A tasks/build-jsr.ts"
1313
},
1414
"lint": {
1515
"rules": { "exclude": ["prefer-const", "require-yield"] },
16-
"exclude": ["build", "www"]
16+
"exclude": ["build", "www", "docs", "tasks"]
1717
},
1818
"fmt": { "exclude": ["build", "www", "CODE_OF_CONDUCT.md", "README.md"] },
1919
"test": { "exclude": ["build"] },
@@ -22,7 +22,8 @@
2222
"@std/testing": "jsr:@std/testing@1",
2323
"ts-expect": "npm:[email protected]",
2424
"@std/expect": "jsr:@std/expect@1",
25-
"tinyexec": "npm:[email protected]"
25+
"ctrlc-windows": "npm:[email protected]",
26+
"tinyexec": "npm:[email protected]"
2627
},
27-
"version": "4.0.0-alpha.8"
28+
"version": "4.0.0-alpha.9"
2829
}

lib/main.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,18 @@ export async function main(
8888
hardexit = (status) => Deno.exit(status);
8989
try {
9090
Deno.addSignalListener("SIGINT", interrupt.SIGINT);
91-
Deno.addSignalListener("SIGTERM", interrupt.SIGTERM);
91+
/**
92+
* Windows only supports ctrl-c (SIGINT), ctrl-break (SIGBREAK), and ctrl-close (SIGUP)
93+
*/
94+
if (Deno.build.os !== "windows") {
95+
Deno.addSignalListener("SIGTERM", interrupt.SIGTERM);
96+
}
9297
yield* body(Deno.args.slice());
9398
} finally {
9499
Deno.removeSignalListener("SIGINT", interrupt.SIGINT);
95-
Deno.removeSignalListener("SIGTERM", interrupt.SIGTERM);
100+
if (Deno.build.os !== "windows") {
101+
Deno.removeSignalListener("SIGTERM", interrupt.SIGTERM);
102+
}
96103
}
97104
},
98105
*node() {
@@ -104,11 +111,15 @@ export async function main(
104111
hardexit = (status) => process.exit(status);
105112
try {
106113
process.on("SIGINT", interrupt.SIGINT);
107-
process.on("SIGTERM", interrupt.SIGTERM);
114+
if (process.platform !== "win32") {
115+
process.on("SIGTERM", interrupt.SIGTERM);
116+
}
108117
yield* body(process.argv.slice(2));
109118
} finally {
110119
process.off("SIGINT", interrupt.SIGINT);
111-
process.off("SIGTERM", interrupt.SIGINT);
120+
if (process.platform !== "win32") {
121+
process.off("SIGTERM", interrupt.SIGINT);
122+
}
112123
}
113124
},
114125
*browser() {

tasks/built-test.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,17 @@ await emptyDir(outDir);
77
const entryPoints = [
88
"./lib/mod.ts",
99
];
10-
for await (const entry of Deno.readDir("test")) {
11-
if (entry.isFile) {
12-
entryPoints.push(`./test/${entry.name}`);
13-
}
14-
}
1510

1611
await build({
1712
entryPoints,
1813
outDir,
1914
shims: {
2015
deno: true,
2116
},
17+
test: true,
2218
typeCheck: false,
19+
scriptModule: false,
20+
esModule: true,
2321
compilerOptions: {
2422
lib: ["ESNext", "DOM"],
2523
target: "ES2020",

test/main.test.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, expect, it, x } from "./suite.ts";
22
import { each, run, type Stream } from "../mod.ts";
33

4-
function* until(stream: Stream<string, void>, text: string) {
4+
function* detect(stream: Stream<string, void>, text: string) {
55
for (const line of yield* each(stream)) {
66
if (line.includes(text)) {
77
return;
@@ -15,7 +15,7 @@ describe("main", () => {
1515
await run(function* () {
1616
let proc = yield* x("deno", ["run", "test/main/ok.daemon.ts"]);
1717

18-
yield* until(proc.lines, "started");
18+
yield* detect(proc.lines, "started");
1919

2020
const { exitCode, stdout } = yield* proc.kill("SIGINT");
2121

@@ -25,34 +25,36 @@ describe("main", () => {
2525
});
2626
});
2727

28-
it("gracefully shuts down on SIGTERM", async () => {
29-
await run(function* () {
30-
let proc = yield* x("deno", ["run", "test/main/ok.daemon.ts"]);
28+
if (Deno.build.os !== "windows") {
29+
it("gracefully shuts down on SIGTERM", async () => {
30+
await run(function* () {
31+
let proc = yield* x("deno", ["run", "test/main/ok.daemon.ts"]);
3132

32-
yield* until(proc.lines, "started");
33+
yield* detect(proc.lines, "started");
3334

34-
const { exitCode, stdout } = yield* proc.kill("SIGTERM");
35+
const { exitCode, stdout } = yield* proc.kill("SIGTERM");
3536

36-
expect(stdout).toContain("gracefully stopped");
37+
expect(stdout).toContain("gracefully stopped");
3738

38-
expect(exitCode).toBe(143);
39+
expect(exitCode).toBe(143);
40+
});
3941
});
40-
});
42+
}
4143

4244
it("exits gracefully on explicit exit()", async () => {
4345
await run(function* () {
4446
let proc = yield* x("deno", ["run", "test/main/ok.exit.ts"]);
4547

46-
yield* until(proc.lines, "goodbye.");
47-
yield* until(proc.lines, "Ok, computer.");
48+
yield* detect(proc.lines, "goodbye.");
49+
yield* detect(proc.lines, "Ok, computer.");
4850
});
4951
});
5052

5153
it("exits gracefully with 0 on implicit exit", async () => {
5254
await run(function* () {
5355
let proc = yield* x("deno", ["run", "test/main/ok.implicit.ts"]);
5456

55-
yield* until(proc.lines, "goodbye.");
57+
yield* detect(proc.lines, "goodbye.");
5658

5759
const { exitCode } = yield* proc;
5860

@@ -88,7 +90,7 @@ describe("main", () => {
8890
await run(function* () {
8991
let proc = yield* x("deno", ["run", "test/main/just.suspend.ts"]);
9092

91-
yield* until(proc.lines, "started");
93+
yield* detect(proc.lines, "started");
9294

9395
const { exitCode, stdout } = yield* proc.kill("SIGINT");
9496

test/suite.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
export { expect } from "@std/expect";
1+
import { expect } from "@std/expect";
2+
import { ctrlc } from "ctrlc-windows";
3+
import { type KillSignal, type Options, type Output, x as $x } from "tinyexec";
24
export { afterEach, beforeEach, describe, it } from "@std/testing/bdd";
35
export { expectType } from "ts-expect";
4-
import { type KillSignal, type Options, type Output, x as $x } from "tinyexec";
6+
export { expect };
57

68
import type { Operation, Stream } from "../lib/types.ts";
7-
import { call, resource, sleep, spawn, stream } from "../mod.ts";
9+
import { resource, sleep, spawn, stream, until } from "../mod.ts";
810

911
export function* createNumber(value: number): Operation<number> {
1012
yield* sleep(1);
@@ -54,6 +56,21 @@ export function* syncResolve(value: string): Operation<string> {
5456
export function* syncReject(value: string): Operation<string> {
5557
throw new Error(`boom: ${value}`);
5658
}
59+
export interface TinyProcess extends Operation<Output> {
60+
/**
61+
* A stream of lines coming from both stdin and stdout. The stream
62+
* will terminate when stdout and stderr are closed which usually
63+
* corresponds to the process ending.
64+
*/
65+
lines: Stream<string, void>;
66+
67+
/**
68+
* Send `signal` to this process
69+
* @param signal - the OS signal to send to the process
70+
* @returns void
71+
*/
72+
kill(signal?: KillSignal): Operation<Output>;
73+
}
5774

5875
export interface TinyProcess extends Operation<Output> {
5976
/**
@@ -81,7 +98,7 @@ export function x(
8198

8299
let promise: Promise<Output> = tinyexec as unknown as Promise<Output>;
83100

84-
let output = call(() => promise);
101+
let output = until(promise);
85102

86103
let tinyproc: TinyProcess = {
87104
*[Symbol.iterator]() {
@@ -90,6 +107,11 @@ export function x(
90107
lines: stream(tinyexec),
91108
*kill(signal) {
92109
tinyexec.kill(signal);
110+
if (
111+
Deno.build.os === "windows" && signal === "SIGINT" && tinyexec.pid
112+
) {
113+
ctrlc(tinyexec.pid);
114+
}
93115
return yield* output;
94116
},
95117
};

0 commit comments

Comments
 (0)