diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2019-06-22 01:00:14 +0200 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2019-06-21 16:00:14 -0700 |
commit | 642eaf97c67c6070935a2977014c743ba59deff8 (patch) | |
tree | e31a30799762aa72439185f0e7ece6151210084e /js | |
parent | eb93dc58a11d9e9a295eff31f9c2c6a3a4c5170b (diff) |
feat: redirect process stdio to file (#2554)
Diffstat (limited to 'js')
-rw-r--r-- | js/process.ts | 54 | ||||
-rw-r--r-- | js/process_test.ts | 72 | ||||
-rw-r--r-- | js/test_util.ts | 3 |
3 files changed, 118 insertions, 11 deletions
diff --git a/js/process.ts b/js/process.ts index c0a66f311..ce6a05760 100644 --- a/js/process.ts +++ b/js/process.ts @@ -28,9 +28,9 @@ export interface RunOptions { args: string[]; cwd?: string; env?: { [key: string]: string }; - stdout?: ProcessStdio; - stderr?: ProcessStdio; - stdin?: ProcessStdio; + stdout?: ProcessStdio | number; + stderr?: ProcessStdio | number; + stdin?: ProcessStdio | number; } async function runStatus(rid: number): Promise<ProcessStatus> { @@ -149,6 +149,10 @@ function stdioMap(s: ProcessStdio): msg.ProcessStdio { } } +function isRid(arg: unknown): arg is number { + return !isNaN(arg as number); +} + /** * Spawns new subprocess. * @@ -159,7 +163,8 @@ function stdioMap(s: ProcessStdio): msg.ProcessStdio { * mapping. * * By default subprocess inherits stdio of parent process. To change that - * `opt.stdout`, `opt.stderr` and `opt.stdin` can be specified independently. + * `opt.stdout`, `opt.stderr` and `opt.stdin` can be specified independently - + * they can be set to either `ProcessStdio` or `rid` of open file. */ export function run(opt: RunOptions): Process { const builder = flatbuffers.createBuilder(); @@ -177,14 +182,49 @@ export function run(opt: RunOptions): Process { } } const envOffset = msg.Run.createEnvVector(builder, kvOffset); + + let stdInOffset = stdioMap("inherit"); + let stdOutOffset = stdioMap("inherit"); + let stdErrOffset = stdioMap("inherit"); + let stdinRidOffset = 0; + let stdoutRidOffset = 0; + let stderrRidOffset = 0; + + if (opt.stdin) { + if (isRid(opt.stdin)) { + stdinRidOffset = opt.stdin; + } else { + stdInOffset = stdioMap(opt.stdin); + } + } + + if (opt.stdout) { + if (isRid(opt.stdout)) { + stdoutRidOffset = opt.stdout; + } else { + stdOutOffset = stdioMap(opt.stdout); + } + } + + if (opt.stderr) { + if (isRid(opt.stderr)) { + stderrRidOffset = opt.stderr; + } else { + stdErrOffset = stdioMap(opt.stderr); + } + } + const inner = msg.Run.createRun( builder, argsOffset, cwdOffset, envOffset, - opt.stdin ? stdioMap(opt.stdin) : stdioMap("inherit"), - opt.stdout ? stdioMap(opt.stdout) : stdioMap("inherit"), - opt.stderr ? stdioMap(opt.stderr) : stdioMap("inherit") + stdInOffset, + stdOutOffset, + stdErrOffset, + stdinRidOffset, + stdoutRidOffset, + stderrRidOffset ); const baseRes = dispatch.sendSync(builder, msg.Any.Run, inner); assert(baseRes != null); diff --git a/js/process_test.ts b/js/process_test.ts index 6eb4dfd89..6e5fe7947 100644 --- a/js/process_test.ts +++ b/js/process_test.ts @@ -1,6 +1,21 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { test, testPerm, assert, assertEquals } from "./test_util.ts"; -const { kill, run, DenoError, ErrorKind } = Deno; +import { + test, + testPerm, + assert, + assertEquals, + assertStrContains +} from "./test_util.ts"; +const { + kill, + run, + DenoError, + ErrorKind, + readFile, + open, + makeTempDir, + writeFile +} = Deno; test(function runPermissions(): void { let caughtError = false; @@ -71,7 +86,7 @@ testPerm( { write: true, run: true }, async function runWithCwdIsAsync(): Promise<void> { const enc = new TextEncoder(); - const cwd = Deno.makeTempDirSync({ prefix: "deno_command_test" }); + const cwd = await makeTempDir({ prefix: "deno_command_test" }); const exitCodeFile = "deno_was_here"; const pyProgramFile = "poll_exit.py"; @@ -205,6 +220,57 @@ testPerm({ run: true }, async function runStderrOutput(): Promise<void> { p.close(); }); +testPerm( + { run: true, write: true, read: true }, + async function runRedirectStdoutStderr(): Promise<void> { + const tempDir = await makeTempDir(); + const fileName = tempDir + "/redirected_stdio.txt"; + const file = await open(fileName, "w"); + + const p = run({ + args: [ + "python", + "-c", + "import sys; sys.stderr.write('error\\n'); sys.stdout.write('output\\n');" + ], + stdout: file.rid, + stderr: file.rid + }); + + await p.status(); + p.close(); + file.close(); + + const fileContents = await readFile(fileName); + const decoder = new TextDecoder(); + const text = decoder.decode(fileContents); + + assertStrContains(text, "error"); + assertStrContains(text, "output"); + } +); + +testPerm( + { run: true, write: true, read: true }, + async function runRedirectStdin(): Promise<void> { + const tempDir = await makeTempDir(); + const fileName = tempDir + "/redirected_stdio.txt"; + const encoder = new TextEncoder(); + await writeFile(fileName, encoder.encode("hello")); + const file = await open(fileName, "r"); + + const p = run({ + args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], + stdin: file.rid + }); + + const status = await p.status(); + assertEquals(status.code, 0); + p.close(); + file.close(); + } +); + testPerm({ run: true }, async function runEnv(): Promise<void> { const p = run({ args: [ diff --git a/js/test_util.ts b/js/test_util.ts index 1b9e2f48c..454f26ff2 100644 --- a/js/test_util.ts +++ b/js/test_util.ts @@ -16,7 +16,8 @@ export { assert, assertEquals, assertNotEquals, - assertStrictEq + assertStrictEq, + assertStrContains } from "./deps/https/deno.land/std/testing/asserts.ts"; interface TestPermissions { |