summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/js/40_spawn.js126
-rw-r--r--runtime/js/90_deno_ns.js1
-rw-r--r--runtime/js/99_main.js70
-rw-r--r--runtime/ops/spawn.rs120
4 files changed, 251 insertions, 66 deletions
diff --git a/runtime/js/40_spawn.js b/runtime/js/40_spawn.js
index a927d619e..4d2fb1607 100644
--- a/runtime/js/40_spawn.js
+++ b/runtime/js/40_spawn.js
@@ -26,7 +26,7 @@
const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
- function spawnChildInner(command, apiName, {
+ function spawnChildInner(opFn, command, apiName, {
args = [],
cwd = undefined,
clearEnv = false,
@@ -39,7 +39,7 @@
signal = undefined,
windowsRawArguments = false,
} = {}) {
- const child = ops.op_spawn_child({
+ const child = opFn({
cmd: pathFromURL(command),
args: ArrayPrototypeMap(args, String),
cwd: pathFromURL(cwd),
@@ -58,8 +58,10 @@
});
}
- function spawnChild(command, options = {}) {
- return spawnChildInner(command, "Deno.spawnChild()", options);
+ function createSpawnChild(opFn) {
+ return function spawnChild(command, options = {}) {
+ return spawnChildInner(opFn, command, "Deno.spawnChild()", options);
+ };
}
async function collectOutput(readableStream) {
@@ -227,68 +229,72 @@
}
}
- function spawn(command, options) {
- if (options?.stdin === "piped") {
- throw new TypeError(
- "Piped stdin is not supported for this function, use 'Deno.spawnChild()' instead",
- );
- }
- return spawnChildInner(command, "Deno.spawn()", options).output();
+ function createSpawn(opFn) {
+ return function spawn(command, options) {
+ if (options?.stdin === "piped") {
+ throw new TypeError(
+ "Piped stdin is not supported for this function, use 'Deno.spawnChild()' instead",
+ );
+ }
+ return spawnChildInner(opFn, command, "Deno.spawn()", options).output();
+ };
}
- function spawnSync(command, {
- args = [],
- cwd = undefined,
- clearEnv = false,
- env = {},
- uid = undefined,
- gid = undefined,
- stdin = "null",
- stdout = "piped",
- stderr = "piped",
- windowsRawArguments = false,
- } = {}) {
- if (stdin === "piped") {
- throw new TypeError(
- "Piped stdin is not supported for this function, use 'Deno.spawnChild()' instead",
- );
- }
- const result = ops.op_spawn_sync({
- cmd: pathFromURL(command),
- args: ArrayPrototypeMap(args, String),
- cwd: pathFromURL(cwd),
- clearEnv,
- env: ObjectEntries(env),
- uid,
- gid,
- stdin,
- stdout,
- stderr,
- windowsRawArguments,
- });
- return {
- success: result.status.success,
- code: result.status.code,
- signal: result.status.signal,
- get stdout() {
- if (result.stdout == null) {
- throw new TypeError("stdout is not piped");
- }
- return result.stdout;
- },
- get stderr() {
- if (result.stderr == null) {
- throw new TypeError("stderr is not piped");
- }
- return result.stderr;
- },
+ function createSpawnSync(opFn) {
+ return function spawnSync(command, {
+ args = [],
+ cwd = undefined,
+ clearEnv = false,
+ env = {},
+ uid = undefined,
+ gid = undefined,
+ stdin = "null",
+ stdout = "piped",
+ stderr = "piped",
+ windowsRawArguments = false,
+ } = {}) {
+ if (stdin === "piped") {
+ throw new TypeError(
+ "Piped stdin is not supported for this function, use 'Deno.spawnChild()' instead",
+ );
+ }
+ const result = opFn({
+ cmd: pathFromURL(command),
+ args: ArrayPrototypeMap(args, String),
+ cwd: pathFromURL(cwd),
+ clearEnv,
+ env: ObjectEntries(env),
+ uid,
+ gid,
+ stdin,
+ stdout,
+ stderr,
+ windowsRawArguments,
+ });
+ return {
+ success: result.status.success,
+ code: result.status.code,
+ signal: result.status.signal,
+ get stdout() {
+ if (result.stdout == null) {
+ throw new TypeError("stdout is not piped");
+ }
+ return result.stdout;
+ },
+ get stderr() {
+ if (result.stderr == null) {
+ throw new TypeError("stderr is not piped");
+ }
+ return result.stderr;
+ },
+ };
};
}
window.__bootstrap.spawn = {
Child,
- spawnChild,
- spawn,
- spawnSync,
+ createSpawn,
+ createSpawnChild,
+ createSpawnSync,
};
})(this);
diff --git a/runtime/js/90_deno_ns.js b/runtime/js/90_deno_ns.js
index 64653d469..033ad421e 100644
--- a/runtime/js/90_deno_ns.js
+++ b/runtime/js/90_deno_ns.js
@@ -4,6 +4,7 @@
((window) => {
const core = window.Deno.core;
const __bootstrap = window.__bootstrap;
+
__bootstrap.denoNs = {
metrics: core.metrics,
test: __bootstrap.testing.test,
diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js
index ef99969b2..9b4a9e857 100644
--- a/runtime/js/99_main.js
+++ b/runtime/js/99_main.js
@@ -700,6 +700,7 @@ delete Intl.v8BreakIterator;
const wrapConsole = window.__bootstrap.console.wrapConsole;
// Remove bootstrapping data from the global scope
+ const __bootstrap = globalThis.__bootstrap;
delete globalThis.__bootstrap;
delete globalThis.bootstrap;
util.log("bootstrapMainRuntime");
@@ -755,6 +756,27 @@ delete Intl.v8BreakIterator;
const internalSymbol = Symbol("Deno.internal");
+ // These have to initialized here and not in `90_deno_ns.js` because
+ // the op function that needs to be passed will be invalidated by creating
+ // a snapshot
+ ObjectAssign(internals, {
+ nodeUnstable: {
+ spawnChild: __bootstrap.spawn.createSpawnChild(
+ ops.op_node_unstable_spawn_child,
+ ),
+ spawn: __bootstrap.spawn.createSpawn(ops.op_node_unstable_spawn_child),
+ spawnSync: __bootstrap.spawn.createSpawnSync(
+ ops.op_node_unstable_spawn_sync,
+ ),
+ serve: __bootstrap.flash.createServe(ops.op_node_unstable_flash_serve),
+ upgradeHttpRaw: __bootstrap.flash.upgradeHttpRaw,
+ listenDatagram: __bootstrap.net.createListenDatagram(
+ ops.op_node_unstable_net_listen_udp,
+ ops.op_node_unstable_net_listen_unixpacket,
+ ),
+ },
+ });
+
const finalDenoNs = {
core,
internal: internalSymbol,
@@ -773,6 +795,19 @@ delete Intl.v8BreakIterator;
if (runtimeOptions.unstableFlag) {
ObjectAssign(finalDenoNs, denoNsUnstable);
+ // These have to initialized here and not in `90_deno_ns.js` because
+ // the op function that needs to be passed will be invalidated by creating
+ // a snapshot
+ ObjectAssign(finalDenoNs, {
+ spawnChild: __bootstrap.spawn.createSpawnChild(ops.op_spawn_child),
+ spawn: __bootstrap.spawn.createSpawn(ops.op_spawn_child),
+ spawnSync: __bootstrap.spawn.createSpawnSync(ops.op_spawn_sync),
+ serve: __bootstrap.flash.createServe(ops.op_flash_serve),
+ listenDatagram: __bootstrap.net.createListenDatagram(
+ ops.op_net_listen_udp,
+ ops.op_net_listen_unixpacket,
+ ),
+ });
}
// Setup `Deno` global - we're actually overriding already existing global
@@ -800,6 +835,7 @@ delete Intl.v8BreakIterator;
const wrapConsole = window.__bootstrap.console.wrapConsole;
// Remove bootstrapping data from the global scope
+ const __bootstrap = globalThis.__bootstrap;
delete globalThis.__bootstrap;
delete globalThis.bootstrap;
util.log("bootstrapWorkerRuntime");
@@ -849,6 +885,27 @@ delete Intl.v8BreakIterator;
const internalSymbol = Symbol("Deno.internal");
+ // These have to initialized here and not in `90_deno_ns.js` because
+ // the op function that needs to be passed will be invalidated by creating
+ // a snapshot
+ ObjectAssign(internals, {
+ nodeUnstable: {
+ spawnChild: __bootstrap.spawn.createSpawnChild(
+ ops.op_node_unstable_spawn_child,
+ ),
+ spawn: __bootstrap.spawn.createSpawn(ops.op_node_unstable_spawn_child),
+ spawnSync: __bootstrap.spawn.createSpawnSync(
+ ops.op_node_unstable_spawn_sync,
+ ),
+ serve: __bootstrap.flash.createServe(ops.op_node_unstable_flash_serve),
+ upgradeHttpRaw: __bootstrap.flash.upgradeHttpRaw,
+ listenDatagram: __bootstrap.net.createListenDatagram(
+ ops.op_node_unstable_net_listen_udp,
+ ops.op_node_unstable_net_listen_unixpacket,
+ ),
+ },
+ });
+
const finalDenoNs = {
core,
internal: internalSymbol,
@@ -859,6 +916,19 @@ delete Intl.v8BreakIterator;
};
if (runtimeOptions.unstableFlag) {
ObjectAssign(finalDenoNs, denoNsUnstable);
+ // These have to initialized here and not in `90_deno_ns.js` because
+ // the op function that needs to be passed will be invalidated by creating
+ // a snapshot
+ ObjectAssign(finalDenoNs, {
+ spawnChild: __bootstrap.spawn.createSpawnChild(ops.op_spawn_child),
+ spawn: __bootstrap.spawn.createSpawn(ops.op_spawn_child),
+ spawnSync: __bootstrap.spawn.createSpawnSync(ops.op_spawn_sync),
+ serve: __bootstrap.flash.createServe(ops.op_flash_serve),
+ listenDatagram: __bootstrap.net.createListenDatagram(
+ ops.op_net_listen_udp,
+ ops.op_net_listen_unixpacket,
+ ),
+ });
}
ObjectDefineProperties(finalDenoNs, {
pid: util.readOnly(runtimeOptions.pid),
diff --git a/runtime/ops/spawn.rs b/runtime/ops/spawn.rs
index 7fe77302a..03ab7d5c2 100644
--- a/runtime/ops/spawn.rs
+++ b/runtime/ops/spawn.rs
@@ -31,8 +31,10 @@ pub fn init() -> Extension {
Extension::builder()
.ops(vec![
op_spawn_child::decl(),
+ op_node_unstable_spawn_child::decl(),
op_spawn_wait::decl(),
op_spawn_sync::decl(),
+ op_node_unstable_spawn_sync::decl(),
])
.build()
}
@@ -123,6 +125,70 @@ pub struct SpawnOutput {
stderr: Option<ZeroCopyBuf>,
}
+fn node_unstable_create_command(
+ state: &mut OpState,
+ args: SpawnArgs,
+ api_name: &str,
+) -> Result<std::process::Command, AnyError> {
+ state
+ .borrow_mut::<Permissions>()
+ .run
+ .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 {
+ command.current_dir(cwd);
+ }
+
+ if args.clear_env {
+ command.env_clear();
+ }
+ command.envs(args.env);
+
+ #[cfg(unix)]
+ if let Some(gid) = args.gid {
+ command.gid(gid);
+ }
+ #[cfg(unix)]
+ if let Some(uid) = args.uid {
+ command.uid(uid);
+ }
+ #[cfg(unix)]
+ // TODO(bartlomieju):
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ unsafe {
+ command.pre_exec(|| {
+ libc::setgroups(0, std::ptr::null());
+ Ok(())
+ });
+ }
+
+ command.stdin(args.stdio.stdin.as_stdio());
+ command.stdout(match args.stdio.stdout {
+ Stdio::Inherit => StdioOrRid::Rid(1).as_stdio(state)?,
+ value => value.as_stdio(),
+ });
+ command.stderr(match args.stdio.stderr {
+ Stdio::Inherit => StdioOrRid::Rid(2).as_stdio(state)?,
+ value => value.as_stdio(),
+ });
+
+ Ok(command)
+}
+
fn create_command(
state: &mut OpState,
args: SpawnArgs,
@@ -200,14 +266,11 @@ struct Child {
stderr_rid: Option<ResourceId>,
}
-#[op]
-fn op_spawn_child(
+fn spawn_child(
state: &mut OpState,
- args: SpawnArgs,
- api_name: String,
+ command: std::process::Command,
) -> Result<Child, AnyError> {
- let mut command =
- tokio::process::Command::from(create_command(state, args, &api_name)?);
+ let mut command = tokio::process::Command::from(command);
// TODO(@crowlkats): allow detaching processes.
// currently deno will orphan a process when exiting with an error or Deno.exit()
// We want to kill child when it's closed
@@ -243,6 +306,26 @@ fn op_spawn_child(
}
#[op]
+fn op_spawn_child(
+ state: &mut OpState,
+ args: SpawnArgs,
+ api_name: String,
+) -> Result<Child, AnyError> {
+ let command = create_command(state, args, &api_name)?;
+ spawn_child(state, command)
+}
+
+#[op]
+fn op_node_unstable_spawn_child(
+ state: &mut OpState,
+ args: SpawnArgs,
+ api_name: String,
+) -> Result<Child, AnyError> {
+ let command = node_unstable_create_command(state, args, &api_name)?;
+ spawn_child(state, command)
+}
+
+#[op]
async fn op_spawn_wait(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
@@ -283,3 +366,28 @@ fn op_spawn_sync(
},
})
}
+
+#[op]
+fn op_node_unstable_spawn_sync(
+ state: &mut OpState,
+ args: SpawnArgs,
+) -> Result<SpawnOutput, AnyError> {
+ let stdout = matches!(args.stdio.stdout, Stdio::Piped);
+ let stderr = matches!(args.stdio.stderr, Stdio::Piped);
+ let output =
+ node_unstable_create_command(state, args, "Deno.spawnSync()")?.output()?;
+
+ Ok(SpawnOutput {
+ status: output.status.try_into()?,
+ stdout: if stdout {
+ Some(output.stdout.into())
+ } else {
+ None
+ },
+ stderr: if stderr {
+ Some(output.stderr.into())
+ } else {
+ None
+ },
+ })
+}