Skip to content

Commit bc5ed01

Browse files
committed
convert process to resource
1 parent 994550b commit bc5ed01

File tree

2 files changed

+188
-185
lines changed

2 files changed

+188
-185
lines changed

process/src/exec/posix.ts

Lines changed: 89 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
createSignal,
55
Err,
66
Ok,
7+
resource,
78
type Result,
89
spawn,
910
withResolvers,
@@ -16,78 +17,107 @@ import { ExecError } from "./error.ts";
1617

1718
type ProcessResultValue = [number?, string?];
1819

19-
export const createPosixProcess: CreateOSProcess = function* createPosixProcess(
20+
export const createPosixProcess: CreateOSProcess = (
2021
command,
2122
options,
22-
) {
23-
let processResult = withResolvers<Result<ProcessResultValue>>();
23+
) => {
24+
return resource(function* (provide) {
25+
let processResult = withResolvers<Result<ProcessResultValue>>();
2426

25-
// Killing all child processes started by this command is surprisingly
26-
// tricky. If a process spawns another processes and we kill the parent,
27-
// then the child process is NOT automatically killed. Instead we're using
28-
// the `detached` option to force the child into its own process group,
29-
// which all of its children in turn will inherit. By sending the signal to
30-
// `-pid` rather than `pid`, we are sending it to the entire process group
31-
// instead. This will send the signal to all processes started by the child
32-
// process.
33-
//
34-
// More information here: https://unix.stackexchange.com/questions/14815/process-descendants
35-
let childProcess = spawnProcess(command, options.arguments || [], {
36-
detached: true,
37-
shell: options.shell,
38-
env: options.env,
39-
cwd: options.cwd,
40-
stdio: "pipe",
41-
});
27+
// Killing all child processes started by this command is surprisingly
28+
// tricky. If a process spawns another processes and we kill the parent,
29+
// then the child process is NOT automatically killed. Instead we're using
30+
// the `detached` option to force the child into its own process group,
31+
// which all of its children in turn will inherit. By sending the signal to
32+
// `-pid` rather than `pid`, we are sending it to the entire process group
33+
// instead. This will send the signal to all processes started by the child
34+
// process.
35+
//
36+
// More information here: https://unix.stackexchange.com/questions/14815/process-descendants
37+
let childProcess = spawnProcess(command, options.arguments || [], {
38+
detached: true,
39+
shell: options.shell,
40+
env: options.env,
41+
cwd: options.cwd,
42+
stdio: "pipe",
43+
});
4244

43-
let { pid } = childProcess;
45+
let { pid } = childProcess;
4446

45-
let io = {
46-
stdout: yield* useReadable(childProcess.stdout),
47-
stderr: yield* useReadable(childProcess.stderr),
48-
stdoutDone: withResolvers<void>(),
49-
stderrDone: withResolvers<void>(),
50-
};
47+
let io = {
48+
stdout: yield* useReadable(childProcess.stdout),
49+
stderr: yield* useReadable(childProcess.stderr),
50+
stdoutDone: withResolvers<void>(),
51+
stderrDone: withResolvers<void>(),
52+
};
5153

52-
let stdout = createSignal<Uint8Array, void>();
53-
let stderr = createSignal<Uint8Array, void>();
54+
let stdout = createSignal<Uint8Array, void>();
55+
let stderr = createSignal<Uint8Array, void>();
5456

55-
yield* spawn(function* () {
56-
let next = yield* io.stdout.next();
57-
while (!next.done) {
58-
stdout.send(next.value);
59-
next = yield* io.stdout.next();
60-
}
61-
stdout.close();
62-
io.stdoutDone.resolve();
63-
});
57+
yield* spawn(function* () {
58+
let next = yield* io.stdout.next();
59+
while (!next.done) {
60+
stdout.send(next.value);
61+
next = yield* io.stdout.next();
62+
}
63+
stdout.close();
64+
io.stdoutDone.resolve();
65+
});
6466

65-
yield* spawn(function* () {
66-
let next = yield* io.stderr.next();
67-
while (!next.done) {
68-
stderr.send(next.value);
69-
next = yield* io.stderr.next();
70-
}
71-
stderr.close();
72-
io.stderrDone.resolve();
73-
});
67+
yield* spawn(function* () {
68+
let next = yield* io.stderr.next();
69+
while (!next.done) {
70+
stderr.send(next.value);
71+
next = yield* io.stderr.next();
72+
}
73+
stderr.close();
74+
io.stderrDone.resolve();
75+
});
7476

75-
yield* spawn(function* trapError() {
76-
let [error] = yield* once<[Error]>(childProcess, "error");
77-
processResult.resolve(Err(error));
78-
});
77+
let stdin: Writable<string> = {
78+
send(data: string) {
79+
childProcess.stdin.write(data);
80+
},
81+
};
7982

80-
let stdin: Writable<string> = {
81-
send(data: string) {
82-
childProcess.stdin.write(data);
83-
},
84-
};
83+
yield* spawn(function* trapError() {
84+
let [error] = yield* once<[Error]>(childProcess, "error");
85+
processResult.resolve(Err(error));
86+
});
8587

86-
yield* spawn(function* () {
87-
try {
88+
yield* spawn(function* () {
8889
let value = yield* once<ProcessResultValue>(childProcess, "close");
89-
// yield* all([io.stdoutDone.operation, io.stderrDone.operation]);
9090
processResult.resolve(Ok(value));
91+
});
92+
93+
function* join() {
94+
let result = yield* processResult.operation;
95+
if (result.ok) {
96+
let [code, signal] = result.value;
97+
return { command, options, code, signal } as ExitStatus;
98+
} else {
99+
throw result.error;
100+
}
101+
}
102+
103+
function* expect() {
104+
let status: ExitStatus = yield* join();
105+
if (status.code != 0) {
106+
throw new ExecError(status, command, options);
107+
} else {
108+
return status;
109+
}
110+
}
111+
112+
try {
113+
yield* provide({
114+
pid: pid as number,
115+
stdin,
116+
stdout,
117+
stderr,
118+
join,
119+
expect,
120+
});
91121
} finally {
92122
try {
93123
if (typeof childProcess.pid === "undefined") {
@@ -101,33 +131,4 @@ export const createPosixProcess: CreateOSProcess = function* createPosixProcess(
101131
}
102132
}
103133
});
104-
105-
function* join() {
106-
let result = yield* processResult.operation;
107-
if (result.ok) {
108-
let [code, signal] = result.value;
109-
return { command, options, code, signal } as ExitStatus;
110-
} else {
111-
throw result.error;
112-
}
113-
}
114-
115-
function* expect() {
116-
let status: ExitStatus = yield* join();
117-
if (status.code != 0) {
118-
throw new ExecError(status, command, options);
119-
} else {
120-
return status;
121-
}
122-
}
123-
124-
// FYI: this function starts a process and returns without blocking
125-
return {
126-
pid: pid as number,
127-
stdin,
128-
stdout,
129-
stderr,
130-
join,
131-
expect,
132-
};
133134
};

0 commit comments

Comments
 (0)