diff options
-rw-r--r-- | cli/js/lib.deno.ns.d.ts | 10 | ||||
-rw-r--r-- | cli/js/process.ts | 45 | ||||
-rw-r--r-- | cli/tests/unit/process_test.ts | 18 | ||||
-rw-r--r-- | std/examples/chat/server_test.ts | 10 | ||||
-rw-r--r-- | std/examples/tests/catj_test.ts | 14 | ||||
-rw-r--r-- | std/examples/tests/echo_server_test.ts | 4 | ||||
-rw-r--r-- | std/http/file_server_test.ts | 2 | ||||
-rw-r--r-- | std/http/racing_server_test.ts | 4 | ||||
-rw-r--r-- | std/http/server_test.ts | 8 |
9 files changed, 61 insertions, 54 deletions
diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index 63e9b342e..c79007ebd 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -1741,12 +1741,12 @@ declare namespace Deno { options?: { recursive: boolean } ): AsyncIterableIterator<FsEvent>; - export class Process { + export class Process<T extends RunOptions = RunOptions> { readonly rid: number; readonly pid: number; - readonly stdin?: Writer & Closer; - readonly stdout?: Reader & Closer; - readonly stderr?: Reader & Closer; + readonly stdin: T["stdin"] extends "piped" ? Writer & Closer : null; + readonly stdout: T["stdout"] extends "piped" ? Reader & Closer : null; + readonly stderr: T["stderr"] extends "piped" ? Reader & Closer : null; /** Resolves to the current status of the process. */ status(): Promise<ProcessStatus>; /** Buffer the stdout until EOF and return it as `Uint8Array`. @@ -1829,7 +1829,7 @@ declare namespace Deno { * Details of the spawned process are returned. * * Requires `allow-run` permission. */ - export function run(opt: RunOptions): Process; + export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>; interface InspectOptions { depth?: number; diff --git a/cli/js/process.ts b/cli/js/process.ts index c8627f86d..cfae7fe56 100644 --- a/cli/js/process.ts +++ b/cli/js/process.ts @@ -5,17 +5,15 @@ import { Closer, Reader, Writer } from "./io.ts"; import { readAll } from "./buffer.ts"; import { kill, runStatus as runStatusOp, run as runOp } from "./ops/process.ts"; -export type ProcessStdio = "inherit" | "piped" | "null"; - // TODO Maybe extend VSCode's 'CommandOptions'? // See https://code.visualstudio.com/docs/editor/tasks-appendix#_schema-for-tasksjson export interface RunOptions { cmd: string[]; cwd?: string; env?: { [key: string]: string }; - stdout?: ProcessStdio | number; - stderr?: ProcessStdio | number; - stdin?: ProcessStdio | number; + stdout?: "inherit" | "piped" | "null" | number; + stderr?: "inherit" | "piped" | "null" | number; + stdin?: "inherit" | "piped" | "null" | number; } async function runStatus(rid: number): Promise<ProcessStatus> { @@ -30,12 +28,12 @@ async function runStatus(rid: number): Promise<ProcessStatus> { } } -export class Process { +export class Process<T extends RunOptions = RunOptions> { readonly rid: number; readonly pid: number; - readonly stdin?: Writer & Closer; - readonly stdout?: Reader & Closer; - readonly stderr?: Reader & Closer; + readonly stdin!: T["stdin"] extends "piped" ? Writer & Closer : null; + readonly stdout!: T["stdout"] extends "piped" ? Reader & Closer : null; + readonly stderr!: T["stderr"] extends "piped" ? Reader & Closer : null; // @internal constructor(res: RunResponse) { @@ -43,15 +41,19 @@ export class Process { this.pid = res.pid; if (res.stdinRid && res.stdinRid > 0) { - this.stdin = new File(res.stdinRid); + this.stdin = (new File(res.stdinRid) as unknown) as Process<T>["stdin"]; } if (res.stdoutRid && res.stdoutRid > 0) { - this.stdout = new File(res.stdoutRid); + this.stdout = (new File(res.stdoutRid) as unknown) as Process< + T + >["stdout"]; } if (res.stderrRid && res.stderrRid > 0) { - this.stderr = new File(res.stderrRid); + this.stderr = (new File(res.stderrRid) as unknown) as Process< + T + >["stderr"]; } } @@ -61,23 +63,23 @@ export class Process { async output(): Promise<Uint8Array> { if (!this.stdout) { - throw new Error("Process.output: stdout is undefined"); + throw new TypeError("stdout was not piped"); } try { - return await readAll(this.stdout); + return await readAll(this.stdout as Reader & Closer); } finally { - this.stdout.close(); + (this.stdout as Reader & Closer).close(); } } async stderrOutput(): Promise<Uint8Array> { if (!this.stderr) { - throw new Error("Process.stderrOutput: stderr is undefined"); + throw new TypeError("stderr was not piped"); } try { - return await readAll(this.stderr); + return await readAll(this.stderr as Reader & Closer); } finally { - this.stderr.close(); + (this.stderr as Reader & Closer).close(); } } @@ -107,14 +109,15 @@ interface RunResponse { stdoutRid: number | null; stderrRid: number | null; } -export function run({ + +export function run<T extends RunOptions = RunOptions>({ cmd, cwd = undefined, env = {}, stdout = "inherit", stderr = "inherit", stdin = "inherit", -}: RunOptions): Process { +}: T): Process<T> { const res = runOp({ cmd: cmd.map(String), cwd, @@ -126,5 +129,5 @@ export function run({ stdoutRid: isRid(stdout) ? stdout : 0, stderrRid: isRid(stderr) ? stderr : 0, }) as RunResponse; - return new Process(res); + return new Process<T>(res); } diff --git a/cli/tests/unit/process_test.ts b/cli/tests/unit/process_test.ts index abd845041..79e36dc4b 100644 --- a/cli/tests/unit/process_test.ts +++ b/cli/tests/unit/process_test.ts @@ -36,7 +36,7 @@ unitTest({ perms: { run: true } }, async function runSuccess(): Promise<void> { assertEquals(status.success, true); assertEquals(status.code, 0); assertEquals(status.signal, undefined); - p.stdout!.close(); + p.stdout.close(); p.close(); }); @@ -141,7 +141,7 @@ unitTest({ perms: { run: true } }, async function runStdinPiped(): Promise< const n = await p.stdin.write(msg); assertEquals(n, msg.byteLength); - p.stdin!.close(); + p.stdin.close(); const status = await p.status(); assertEquals(status.success, true); @@ -161,16 +161,16 @@ unitTest({ perms: { run: true } }, async function runStdoutPiped(): Promise< assert(!p.stderr); const data = new Uint8Array(10); - let r = await p.stdout!.read(data); + let r = await p.stdout.read(data); if (r === null) { throw new Error("p.stdout.read(...) should not be null"); } assertEquals(r, 5); const s = new TextDecoder().decode(data.subarray(0, r)); assertEquals(s, "hello"); - r = await p.stdout!.read(data); + r = await p.stdout.read(data); assertEquals(r, null); - p.stdout!.close(); + p.stdout.close(); const status = await p.status(); assertEquals(status.success, true); @@ -190,14 +190,14 @@ unitTest({ perms: { run: true } }, async function runStderrPiped(): Promise< assert(!p.stdout); const data = new Uint8Array(10); - let r = await p.stderr!.read(data); + let r = await p.stderr.read(data); if (r === null) { throw new Error("p.stderr.read should not return null here"); } assertEquals(r, 5); const s = new TextDecoder().decode(data.subarray(0, r)); assertEquals(s, "hello"); - r = await p.stderr!.read(data); + r = await p.stderr.read(data); assertEquals(r, null); p.stderr!.close(); @@ -320,9 +320,9 @@ unitTest({ perms: { run: true } }, async function runClose(): Promise<void> { p.close(); const data = new Uint8Array(10); - const r = await p.stderr!.read(data); + const r = await p.stderr.read(data); assertEquals(r, null); - p.stderr!.close(); + p.stderr.close(); }); unitTest(function signalNumbers(): void { diff --git a/std/examples/chat/server_test.ts b/std/examples/chat/server_test.ts index 7375de47a..8e04b71d8 100644 --- a/std/examples/chat/server_test.ts +++ b/std/examples/chat/server_test.ts @@ -7,7 +7,9 @@ import { delay } from "../../async/delay.ts"; const { test } = Deno; -async function startServer(): Promise<Deno.Process> { +async function startServer(): Promise< + Deno.Process<Deno.RunOptions & { stdout: "piped" }> +> { const server = Deno.run({ // TODO(lucacasonato): remove unstable once possible cmd: [ @@ -27,7 +29,7 @@ async function startServer(): Promise<Deno.Process> { const s = await r.readLine(); assert(s !== null && s.includes("chat server starting")); } catch (err) { - server.stdout!.close(); + server.stdout.close(); server.close(); } @@ -46,7 +48,7 @@ test({ assert(html.includes("ws chat example"), "body is ok"); } finally { server.close(); - server.stdout!.close(); + server.stdout.close(); } await delay(10); }, @@ -66,7 +68,7 @@ test({ assertEquals((await it.next()).value, "[1]: Hello"); } finally { server.close(); - server.stdout!.close(); + server.stdout.close(); ws!.conn.close(); } }, diff --git a/std/examples/tests/catj_test.ts b/std/examples/tests/catj_test.ts index a859db0c1..58533ab60 100644 --- a/std/examples/tests/catj_test.ts +++ b/std/examples/tests/catj_test.ts @@ -17,7 +17,7 @@ Deno.test("[examples/catj] print an array", async () => { assertStrictEquals(actual, expected); } finally { - process.stdin!.close(); + process.stdin.close(); process.close(); } }); @@ -36,7 +36,7 @@ Deno.test("[examples/catj] print an object", async () => { assertStrictEquals(actual, expected); } finally { - process.stdin!.close(); + process.stdin.close(); process.close(); } }); @@ -54,7 +54,7 @@ Deno.test("[examples/catj] print multiple files", async () => { assertStrictEquals(actual, expected); } finally { - process.stdin!.close(); + process.stdin.close(); process.close(); } }); @@ -64,8 +64,8 @@ Deno.test("[examples/catj] read from stdin", async () => { const process = catj("-"); const input = `{ "foo": "bar" }`; try { - await process.stdin!.write(new TextEncoder().encode(input)); - process.stdin!.close(); + await process.stdin.write(new TextEncoder().encode(input)); + process.stdin.close(); const output = await process.output(); const actual = decoder.decode(output).trim(); @@ -75,7 +75,9 @@ Deno.test("[examples/catj] read from stdin", async () => { } }); -function catj(...files: string[]): Deno.Process { +function catj( + ...files: string[] +): Deno.Process<Deno.RunOptions & { stdin: "piped"; stdout: "piped" }> { return Deno.run({ cmd: [Deno.execPath(), "run", "--allow-read", "catj.ts", ...files], cwd: "examples", diff --git a/std/examples/tests/echo_server_test.ts b/std/examples/tests/echo_server_test.ts index 475b0f73f..2cf52e466 100644 --- a/std/examples/tests/echo_server_test.ts +++ b/std/examples/tests/echo_server_test.ts @@ -13,7 +13,7 @@ Deno.test("[examples/echo_server]", async () => { let conn: Deno.Conn | undefined; try { - const processReader = new BufReader(process.stdout!); + const processReader = new BufReader(process.stdout); const message = await processReader.readLine(); assertNotEquals(message, null); @@ -38,7 +38,7 @@ Deno.test("[examples/echo_server]", async () => { assertStrictEquals(actualResponse, expectedResponse); } finally { conn?.close(); - process.stdout!.close(); + process.stdout.close(); process.close(); } }); diff --git a/std/http/file_server_test.ts b/std/http/file_server_test.ts index dbbaf81ff..ceea566fa 100644 --- a/std/http/file_server_test.ts +++ b/std/http/file_server_test.ts @@ -5,7 +5,7 @@ import { TextProtoReader } from "../textproto/mod.ts"; import { ServerRequest } from "./server.ts"; import { serveFile } from "./file_server.ts"; const { test } = Deno; -let fileServer: Deno.Process; +let fileServer: Deno.Process<Deno.RunOptions & { stdout: "piped" }>; type FileServerCfg = { target?: string; diff --git a/std/http/racing_server_test.ts b/std/http/racing_server_test.ts index 845e5a490..054dfc385 100644 --- a/std/http/racing_server_test.ts +++ b/std/http/racing_server_test.ts @@ -3,7 +3,7 @@ import { BufReader, BufWriter } from "../io/bufio.ts"; import { TextProtoReader } from "../textproto/mod.ts"; const { connect, run, test } = Deno; -let server: Deno.Process; +let server: Deno.Process<Deno.RunOptions & { stdout: "piped" }>; async function startServer(): Promise<void> { server = run({ // TODO(lucacasonato): remove unstable when stabilized @@ -18,7 +18,7 @@ async function startServer(): Promise<void> { } function killServer(): void { server.close(); - server.stdout?.close(); + server.stdout.close(); } const input = [ diff --git a/std/http/server_test.ts b/std/http/server_test.ts index d522b9a8f..2d911c450 100644 --- a/std/http/server_test.ts +++ b/std/http/server_test.ts @@ -372,7 +372,7 @@ test({ .catch((_): void => {}); // Ignores the error when closing the process. try { - const r = new TextProtoReader(new BufReader(p.stdout!)); + const r = new TextProtoReader(new BufReader(p.stdout)); const s = await r.readLine(); assert(s !== null && s.includes("server listening")); await delay(100); @@ -387,7 +387,7 @@ test({ // Stops the sever and allows `p.status()` promise to resolve Deno.kill(p.pid, Deno.Signal.SIGKILL); await statusPromise; - p.stdout!.close(); + p.stdout.close(); p.close(); } }, @@ -417,7 +417,7 @@ test({ .catch((_): void => {}); // Ignores the error when closing the process. try { - const r = new TextProtoReader(new BufReader(p.stdout!)); + const r = new TextProtoReader(new BufReader(p.stdout)); const s = await r.readLine(); assert( s !== null && s.includes("server listening"), @@ -444,7 +444,7 @@ test({ // Stops the sever and allows `p.status()` promise to resolve Deno.kill(p.pid, Deno.Signal.SIGKILL); await statusPromise; - p.stdout!.close(); + p.stdout.close(); p.close(); } }, |