diff options
author | Yoshiya Hinosawa <stibium121@gmail.com> | 2022-10-17 19:51:25 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-17 19:51:25 +0900 |
commit | e41af14b2a5e7643e4d4e882b20a828ef0104757 (patch) | |
tree | 272f45e879ea16217fea30842b22a0f7ba3a067d | |
parent | 0dc2f02dfa2b299cd8a8d352c880b05be463cf0f (diff) |
feat(unstable): add windowsRawArguments to SpawnOptions (#16319)
This change adds `windowsRawArguments` to `SpawnOptions`. The option enables
skipping the default quoting and escaping while creating the command on
windows.
The option works in a similar way as `windowsVerbatimArguments` in
child_process.spawn options in Node.js, and is necessary for simulating
it in `std/node`.
closes #8852
-rw-r--r-- | cli/dts/lib.deno.unstable.d.ts | 4 | ||||
-rw-r--r-- | cli/tests/unit/spawn_test.ts | 27 | ||||
-rw-r--r-- | runtime/js/40_spawn.js | 4 | ||||
-rw-r--r-- | runtime/ops/spawn.rs | 15 |
4 files changed, 49 insertions, 1 deletions
diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index 6eb7153ba..1feb11e97 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -1542,6 +1542,10 @@ declare namespace Deno { stdout?: "piped" | "inherit" | "null"; /** Defaults to "piped". */ stderr?: "piped" | "inherit" | "null"; + + /** Skips quoting and escaping of the arguments on windows. This option + * is ignored on non-windows platforms. Defaults to "false". */ + windowsRawArguments?: boolean; } /** **UNSTABLE**: New API, yet to be vetted. diff --git a/cli/tests/unit/spawn_test.ts b/cli/tests/unit/spawn_test.ts index df95e333b..149886a1c 100644 --- a/cli/tests/unit/spawn_test.ts +++ b/cli/tests/unit/spawn_test.ts @@ -733,7 +733,7 @@ const child = await Deno.spawnChild(Deno.execPath(), { }); const readable = child.stdout.pipeThrough(new TextDecoderStream()); const reader = readable.getReader(); -// set up an interval that will end after reading a few messages from stdout, +// set up an interval that will end after reading a few messages from stdout, // to verify that stdio streams are properly unrefed let count = 0; let interval; @@ -787,3 +787,28 @@ setInterval(() => { }, Deno.errors.NotFound); }, ); + +Deno.test( + { ignore: Deno.build.os !== "windows" }, + async function spawnWindowsRawArguments() { + let { success, stdout } = await Deno.spawn("cmd", { + args: ["/d", "/s", "/c", '"deno ^"--version^""'], + windowsRawArguments: true, + }); + assert(success); + let stdoutText = new TextDecoder().decode(stdout); + assertStringIncludes(stdoutText, "deno"); + assertStringIncludes(stdoutText, "v8"); + assertStringIncludes(stdoutText, "typescript"); + + ({ success, stdout } = Deno.spawnSync("cmd", { + args: ["/d", "/s", "/c", '"deno ^"--version^""'], + windowsRawArguments: true, + })); + assert(success); + stdoutText = new TextDecoder().decode(stdout); + assertStringIncludes(stdoutText, "deno"); + assertStringIncludes(stdoutText, "v8"); + assertStringIncludes(stdoutText, "typescript"); + }, +); diff --git a/runtime/js/40_spawn.js b/runtime/js/40_spawn.js index a0283f0ff..a9a968ba3 100644 --- a/runtime/js/40_spawn.js +++ b/runtime/js/40_spawn.js @@ -36,6 +36,7 @@ stdout = "piped", stderr = "piped", signal = undefined, + windowsRawArguments = false, } = {}) { const child = ops.op_spawn_child({ cmd: pathFromURL(command), @@ -48,6 +49,7 @@ stdin, stdout, stderr, + windowsRawArguments, }, apiName); return new Child(illegalConstructorKey, { ...child, @@ -243,6 +245,7 @@ stdin = "null", stdout = "piped", stderr = "piped", + windowsRawArguments = false, } = {}) { if (stdin === "piped") { throw new TypeError( @@ -260,6 +263,7 @@ stdin, stdout, stderr, + windowsRawArguments, }); return { success: result.status.success, diff --git a/runtime/ops/spawn.rs b/runtime/ops/spawn.rs index 9286e6d0c..7fe77302a 100644 --- a/runtime/ops/spawn.rs +++ b/runtime/ops/spawn.rs @@ -17,6 +17,8 @@ use serde::Deserialize; use serde::Serialize; use std::borrow::Cow; use std::cell::RefCell; +#[cfg(windows)] +use std::os::windows::process::CommandExt; use std::process::ExitStatus; use std::rc::Rc; @@ -55,6 +57,8 @@ pub struct SpawnArgs { gid: Option<u32>, #[cfg(unix)] uid: Option<u32>, + #[cfg(windows)] + windows_raw_arguments: bool, #[serde(flatten)] stdio: ChildStdio, @@ -131,6 +135,17 @@ fn create_command( .check(&args.cmd, Some(api_name))?; let mut command = std::process::Command::new(args.cmd); + + #[cfg(windows)] + if args.windows_raw_arguments { + for arg in args.args.iter() { + command.raw_arg(arg); + } + } else { + command.args(args.args); + } + + #[cfg(not(windows))] command.args(args.args); if let Some(cwd) = args.cwd { |