0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-01 20:25:12 -05:00

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
This commit is contained in:
Yoshiya Hinosawa 2022-10-17 19:51:25 +09:00 committed by GitHub
parent 0dc2f02dfa
commit e41af14b2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 1 deletions

View file

@ -1542,6 +1542,10 @@ declare namespace Deno {
stdout?: "piped" | "inherit" | "null"; stdout?: "piped" | "inherit" | "null";
/** Defaults to "piped". */ /** Defaults to "piped". */
stderr?: "piped" | "inherit" | "null"; 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. /** **UNSTABLE**: New API, yet to be vetted.

View file

@ -787,3 +787,28 @@ setInterval(() => {
}, Deno.errors.NotFound); }, 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");
},
);

View file

@ -36,6 +36,7 @@
stdout = "piped", stdout = "piped",
stderr = "piped", stderr = "piped",
signal = undefined, signal = undefined,
windowsRawArguments = false,
} = {}) { } = {}) {
const child = ops.op_spawn_child({ const child = ops.op_spawn_child({
cmd: pathFromURL(command), cmd: pathFromURL(command),
@ -48,6 +49,7 @@
stdin, stdin,
stdout, stdout,
stderr, stderr,
windowsRawArguments,
}, apiName); }, apiName);
return new Child(illegalConstructorKey, { return new Child(illegalConstructorKey, {
...child, ...child,
@ -243,6 +245,7 @@
stdin = "null", stdin = "null",
stdout = "piped", stdout = "piped",
stderr = "piped", stderr = "piped",
windowsRawArguments = false,
} = {}) { } = {}) {
if (stdin === "piped") { if (stdin === "piped") {
throw new TypeError( throw new TypeError(
@ -260,6 +263,7 @@
stdin, stdin,
stdout, stdout,
stderr, stderr,
windowsRawArguments,
}); });
return { return {
success: result.status.success, success: result.status.success,

View file

@ -17,6 +17,8 @@ use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::RefCell; use std::cell::RefCell;
#[cfg(windows)]
use std::os::windows::process::CommandExt;
use std::process::ExitStatus; use std::process::ExitStatus;
use std::rc::Rc; use std::rc::Rc;
@ -55,6 +57,8 @@ pub struct SpawnArgs {
gid: Option<u32>, gid: Option<u32>,
#[cfg(unix)] #[cfg(unix)]
uid: Option<u32>, uid: Option<u32>,
#[cfg(windows)]
windows_raw_arguments: bool,
#[serde(flatten)] #[serde(flatten)]
stdio: ChildStdio, stdio: ChildStdio,
@ -131,6 +135,17 @@ fn create_command(
.check(&args.cmd, Some(api_name))?; .check(&args.cmd, Some(api_name))?;
let mut command = std::process::Command::new(args.cmd); 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); command.args(args.args);
if let Some(cwd) = args.cwd { if let Some(cwd) = args.cwd {