summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/node/polyfills/internal/child_process.ts19
-rw-r--r--runtime/ops/process.rs38
-rw-r--r--tests/specs/node/stdio_ipc/__test__.jsonc5
-rw-r--r--tests/specs/node/stdio_ipc/main.mjs16
-rw-r--r--tests/specs/node/stdio_ipc/main.out1
5 files changed, 62 insertions, 17 deletions
diff --git a/ext/node/polyfills/internal/child_process.ts b/ext/node/polyfills/internal/child_process.ts
index b6137e0d1..cabae63ee 100644
--- a/ext/node/polyfills/internal/child_process.ts
+++ b/ext/node/polyfills/internal/child_process.ts
@@ -362,17 +362,25 @@ export class ChildProcess extends EventEmitter {
}
}
-const supportedNodeStdioTypes: NodeStdio[] = ["pipe", "ignore", "inherit"];
+const supportedNodeStdioTypes: NodeStdio[] = [
+ "pipe",
+ "ignore",
+ "inherit",
+ "ipc",
+];
function toDenoStdio(
pipe: NodeStdio | number | Stream | null | undefined,
): DenoStdio {
if (pipe instanceof Stream) {
return "inherit";
}
+ if (typeof pipe === "number") {
+ /* Assume it's a rid returned by fs APIs */
+ return pipe;
+ }
if (
- !supportedNodeStdioTypes.includes(pipe as NodeStdio) ||
- typeof pipe === "number"
+ !supportedNodeStdioTypes.includes(pipe as NodeStdio)
) {
notImplemented(`toDenoStdio pipe=${typeof pipe} (${pipe})`);
}
@@ -385,6 +393,8 @@ function toDenoStdio(
return "null";
case "inherit":
return "inherit";
+ case "ipc":
+ return "ipc_for_internal_use";
default:
notImplemented(`toDenoStdio pipe=${typeof pipe} (${pipe})`);
}
@@ -1083,8 +1093,7 @@ function toDenoArgs(args: string[]): string[] {
if (useRunArgs) {
// -A is not ideal, but needed to propagate permissions.
- // --unstable is needed for Node compat.
- denoArgs.unshift("run", "-A", "--unstable");
+ denoArgs.unshift("run", "-A");
}
return denoArgs;
diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs
index b894b35db..ecf6ef49b 100644
--- a/runtime/ops/process.rs
+++ b/runtime/ops/process.rs
@@ -37,11 +37,12 @@ use std::os::unix::process::CommandExt;
pub const UNSTABLE_FEATURE_NAME: &str = "process";
#[derive(Copy, Clone, Eq, PartialEq, Deserialize)]
-#[serde(rename_all = "camelCase")]
+#[serde(rename_all = "snake_case")]
pub enum Stdio {
Inherit,
Piped,
Null,
+ IpcForInternalUse,
}
impl Stdio {
@@ -50,6 +51,7 @@ impl Stdio {
Stdio::Inherit => std::process::Stdio::inherit(),
Stdio::Piped => std::process::Stdio::piped(),
Stdio::Null => std::process::Stdio::null(),
+ _ => unreachable!(),
}
}
}
@@ -72,6 +74,9 @@ impl<'de> Deserialize<'de> for StdioOrRid {
"inherit" => Ok(StdioOrRid::Stdio(Stdio::Inherit)),
"piped" => Ok(StdioOrRid::Stdio(Stdio::Piped)),
"null" => Ok(StdioOrRid::Stdio(Stdio::Null)),
+ "ipc_for_internal_use" => {
+ Ok(StdioOrRid::Stdio(Stdio::IpcForInternalUse))
+ }
val => Err(serde::de::Error::unknown_variant(
val,
&["inherit", "piped", "null"],
@@ -102,6 +107,10 @@ impl StdioOrRid {
}
}
}
+
+ pub fn is_ipc(&self) -> bool {
+ matches!(self, StdioOrRid::Stdio(Stdio::IpcForInternalUse))
+ }
}
deno_core::extension!(
@@ -150,9 +159,9 @@ pub struct SpawnArgs {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ChildStdio {
- stdin: Stdio,
- stdout: Stdio,
- stderr: Stdio,
+ stdin: StdioOrRid,
+ stdout: StdioOrRid,
+ stderr: StdioOrRid,
}
#[derive(Serialize)]
@@ -210,7 +219,7 @@ type CreateCommand = (std::process::Command, Option<ResourceId>);
fn create_command(
state: &mut OpState,
- args: SpawnArgs,
+ mut args: SpawnArgs,
api_name: &str,
) -> Result<CreateCommand, AnyError> {
state
@@ -249,14 +258,19 @@ fn create_command(
command.uid(uid);
}
- command.stdin(args.stdio.stdin.as_stdio());
+ if args.stdio.stdin.is_ipc() {
+ args.ipc = Some(0);
+ } else {
+ command.stdin(args.stdio.stdin.as_stdio(state)?);
+ }
+
command.stdout(match args.stdio.stdout {
- Stdio::Inherit => StdioOrRid::Rid(1).as_stdio(state)?,
- value => value.as_stdio(),
+ StdioOrRid::Stdio(Stdio::Inherit) => StdioOrRid::Rid(1).as_stdio(state)?,
+ value => value.as_stdio(state)?,
});
command.stderr(match args.stdio.stderr {
- Stdio::Inherit => StdioOrRid::Rid(2).as_stdio(state)?,
- value => value.as_stdio(),
+ StdioOrRid::Stdio(Stdio::Inherit) => StdioOrRid::Rid(2).as_stdio(state)?,
+ value => value.as_stdio(state)?,
});
#[cfg(unix)]
@@ -608,8 +622,8 @@ fn op_spawn_sync(
state: &mut OpState,
#[serde] args: SpawnArgs,
) -> Result<SpawnOutput, AnyError> {
- let stdout = matches!(args.stdio.stdout, Stdio::Piped);
- let stderr = matches!(args.stdio.stderr, Stdio::Piped);
+ let stdout = matches!(args.stdio.stdout, StdioOrRid::Stdio(Stdio::Piped));
+ let stderr = matches!(args.stdio.stderr, StdioOrRid::Stdio(Stdio::Piped));
let (mut command, _) =
create_command(state, args, "Deno.Command().outputSync()")?;
let output = command.output().with_context(|| {
diff --git a/tests/specs/node/stdio_ipc/__test__.jsonc b/tests/specs/node/stdio_ipc/__test__.jsonc
new file mode 100644
index 000000000..8ec9880fd
--- /dev/null
+++ b/tests/specs/node/stdio_ipc/__test__.jsonc
@@ -0,0 +1,5 @@
+{
+ "args": "run -A main.mjs",
+ "output": "main.out",
+ "exitCode": 0
+}
diff --git a/tests/specs/node/stdio_ipc/main.mjs b/tests/specs/node/stdio_ipc/main.mjs
new file mode 100644
index 000000000..4a1a8ddbd
--- /dev/null
+++ b/tests/specs/node/stdio_ipc/main.mjs
@@ -0,0 +1,16 @@
+import { spawn } from "node:child_process";
+import process from "node:process";
+
+if (process.argv[2] === "child") {
+ process.send("hahah");
+} else {
+ const proc = spawn(process.execPath, ["./main.mjs", "child"], {
+ stdio: ["ipc", "inherit", "inherit"],
+ });
+
+ proc.on("message", function (msg) {
+ console.log(`msg: ${msg}`);
+ proc.kill();
+ Deno.exit(0);
+ });
+}
diff --git a/tests/specs/node/stdio_ipc/main.out b/tests/specs/node/stdio_ipc/main.out
new file mode 100644
index 000000000..7979ca2eb
--- /dev/null
+++ b/tests/specs/node/stdio_ipc/main.out
@@ -0,0 +1 @@
+msg: hahah