summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoshiya Hinosawa <stibium121@gmail.com>2022-10-17 19:51:25 +0900
committerGitHub <noreply@github.com>2022-10-17 19:51:25 +0900
commite41af14b2a5e7643e4d4e882b20a828ef0104757 (patch)
tree272f45e879ea16217fea30842b22a0f7ba3a067d
parent0dc2f02dfa2b299cd8a8d352c880b05be463cf0f (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.ts4
-rw-r--r--cli/tests/unit/spawn_test.ts27
-rw-r--r--runtime/js/40_spawn.js4
-rw-r--r--runtime/ops/spawn.rs15
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 {