summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/ops/mod.rs6
-rw-r--r--cli/proc_state.rs1
-rw-r--r--cli/tests/integration/npm_tests.rs11
-rw-r--r--ext/flash/01_http.js418
-rw-r--r--ext/flash/lib.rs28
-rw-r--r--ext/net/01_net.js50
-rw-r--r--ext/net/ops.rs33
-rw-r--r--ext/net/ops_unix.rs27
-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
m---------test_util/std0
13 files changed, 569 insertions, 322 deletions
diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs
index df3331353..c02b951b2 100644
--- a/cli/ops/mod.rs
+++ b/cli/ops/mod.rs
@@ -1,7 +1,6 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use crate::proc_state::ProcState;
-use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::Extension;
@@ -27,10 +26,5 @@ fn init_proc_state(ps: ProcState) -> Extension {
#[op]
fn op_npm_process_state(state: &mut OpState) -> Result<String, AnyError> {
let proc_state = state.borrow_mut::<ProcState>();
- if !proc_state.options.unstable() {
- bail!(
- "Unstable use of npm process state. The --unstable flag must be provided."
- )
- }
Ok(proc_state.npm_resolver.get_npm_process_state())
}
diff --git a/cli/proc_state.rs b/cli/proc_state.rs
index 117451c56..29f4ce3bd 100644
--- a/cli/proc_state.rs
+++ b/cli/proc_state.rs
@@ -274,6 +274,7 @@ impl ProcState {
/// module before attempting to `load()` it from a `JsRuntime`. It will
/// populate `self.graph_data` in memory with the necessary source code, write
/// emits where necessary or report any module graph / type checking errors.
+ #[allow(clippy::too_many_arguments)]
pub async fn prepare_module_load(
&self,
roots: Vec<ModuleSpecifier>,
diff --git a/cli/tests/integration/npm_tests.rs b/cli/tests/integration/npm_tests.rs
index 1eb476287..ced9ad8a3 100644
--- a/cli/tests/integration/npm_tests.rs
+++ b/cli/tests/integration/npm_tests.rs
@@ -103,7 +103,7 @@ itest!(dual_cjs_esm {
});
itest!(child_process_fork_test {
- args: "run --unstable -A --quiet npm/child_process_fork_test/main.ts",
+ args: "run -A --quiet npm/child_process_fork_test/main.ts",
output: "npm/child_process_fork_test/main.out",
envs: env_vars(),
http_server: true,
@@ -621,7 +621,7 @@ itest!(node_modules_dir_with_deps {
});
itest!(node_modules_dir_yargs {
- args: "run --allow-read --allow-env --unstable --node-modules-dir $TESTDATA/npm/cjs_yargs/main.js",
+ args: "run --allow-read --allow-env --node-modules-dir $TESTDATA/npm/cjs_yargs/main.js",
output: "npm/cjs_yargs/main.out",
envs: env_vars(),
http_server: true,
@@ -1050,7 +1050,6 @@ fn peer_deps_with_copied_folders_and_lockfile() {
let deno = util::deno_cmd_with_deno_dir(&deno_dir)
.current_dir(temp_dir.path())
.arg("run")
- .arg("--unstable")
.arg("-A")
.arg("main.ts")
.envs(env_vars())
@@ -1082,7 +1081,6 @@ fn peer_deps_with_copied_folders_and_lockfile() {
let deno = util::deno_cmd_with_deno_dir(&deno_dir)
.current_dir(temp_dir.path())
.arg("run")
- .arg("--unstable")
.arg("-A")
.arg("main.ts")
.envs(env_vars())
@@ -1097,7 +1095,6 @@ fn peer_deps_with_copied_folders_and_lockfile() {
let deno = util::deno_cmd_with_deno_dir(&deno_dir)
.current_dir(temp_dir.path())
.arg("run")
- .arg("--unstable")
.arg("--reload")
.arg("-A")
.arg("main.ts")
@@ -1114,7 +1111,6 @@ fn peer_deps_with_copied_folders_and_lockfile() {
let deno = util::deno_cmd_with_deno_dir(&deno_dir)
.current_dir(temp_dir.path())
.arg("run")
- .arg("--unstable")
.arg("--node-modules-dir")
.arg("-A")
.arg("main.ts")
@@ -1139,7 +1135,6 @@ fn peer_deps_with_copied_folders_and_lockfile() {
let deno = util::deno_cmd_with_deno_dir(&deno_dir)
.current_dir(temp_dir.path())
.arg("run")
- .arg("--unstable")
.arg("--node-modules-dir")
.arg("-A")
.arg("main.ts")
@@ -1156,7 +1151,6 @@ fn peer_deps_with_copied_folders_and_lockfile() {
let deno = util::deno_cmd_with_deno_dir(&deno_dir)
.current_dir(temp_dir.path())
.arg("run")
- .arg("--unstable")
.arg("--node-modules-dir")
.arg("--reload")
.arg("-A")
@@ -1174,7 +1168,6 @@ fn peer_deps_with_copied_folders_and_lockfile() {
let deno = util::deno_cmd_with_deno_dir(&deno_dir)
.current_dir(temp_dir.path())
.arg("run")
- .arg("--unstable")
.arg("--node-modules-dir")
.arg("--no-lock")
.arg("--reload")
diff --git a/ext/flash/01_http.js b/ext/flash/01_http.js
index 4435860ff..7a6b9bc47 100644
--- a/ext/flash/01_http.js
+++ b/ext/flash/01_http.js
@@ -422,239 +422,241 @@
})();
}
- async function serve(arg1, arg2) {
- let options = undefined;
- let handler = undefined;
- if (arg1 instanceof Function) {
- handler = arg1;
- options = arg2;
- } else if (arg2 instanceof Function) {
- handler = arg2;
- options = arg1;
- } else {
- options = arg1;
- }
- if (handler === undefined) {
+ function createServe(opFn) {
+ return async function serve(arg1, arg2) {
+ let options = undefined;
+ let handler = undefined;
+ if (arg1 instanceof Function) {
+ handler = arg1;
+ options = arg2;
+ } else if (arg2 instanceof Function) {
+ handler = arg2;
+ options = arg1;
+ } else {
+ options = arg1;
+ }
+ if (handler === undefined) {
+ if (options === undefined) {
+ throw new TypeError(
+ "No handler was provided, so an options bag is mandatory.",
+ );
+ }
+ handler = options.handler;
+ }
+ if (!(handler instanceof Function)) {
+ throw new TypeError("A handler function must be provided.");
+ }
if (options === undefined) {
- throw new TypeError(
- "No handler was provided, so an options bag is mandatory.",
- );
+ options = {};
}
- handler = options.handler;
- }
- if (!(handler instanceof Function)) {
- throw new TypeError("A handler function must be provided.");
- }
- if (options === undefined) {
- options = {};
- }
- const signal = options.signal;
+ const signal = options.signal;
- const onError = options.onError ?? function (error) {
- console.error(error);
- return new Response("Internal Server Error", { status: 500 });
- };
-
- const onListen = options.onListen ?? function ({ port }) {
- console.log(
- `Listening on http://${
- hostnameForDisplay(listenOpts.hostname)
- }:${port}/`,
- );
- };
+ const onError = options.onError ?? function (error) {
+ console.error(error);
+ return new Response("Internal Server Error", { status: 500 });
+ };
- const listenOpts = {
- hostname: options.hostname ?? "127.0.0.1",
- port: options.port ?? 9000,
- reuseport: options.reusePort ?? false,
- };
- if (options.cert || options.key) {
- if (!options.cert || !options.key) {
- throw new TypeError(
- "Both cert and key must be provided to enable HTTPS.",
+ const onListen = options.onListen ?? function ({ port }) {
+ console.log(
+ `Listening on http://${
+ hostnameForDisplay(listenOpts.hostname)
+ }:${port}/`,
);
+ };
+
+ const listenOpts = {
+ hostname: options.hostname ?? "127.0.0.1",
+ port: options.port ?? 9000,
+ reuseport: options.reusePort ?? false,
+ };
+ if (options.cert || options.key) {
+ if (!options.cert || !options.key) {
+ throw new TypeError(
+ "Both cert and key must be provided to enable HTTPS.",
+ );
+ }
+ listenOpts.cert = options.cert;
+ listenOpts.key = options.key;
}
- listenOpts.cert = options.cert;
- listenOpts.key = options.key;
- }
- const serverId = core.ops.op_flash_serve(listenOpts);
- const serverPromise = core.opAsync("op_flash_drive_server", serverId);
-
- PromisePrototypeCatch(
- PromisePrototypeThen(
- core.opAsync("op_flash_wait_for_listening", serverId),
- (port) => {
- onListen({ hostname: listenOpts.hostname, port });
- },
- ),
- () => {},
- );
- const finishedPromise = PromisePrototypeCatch(serverPromise, () => {});
-
- const server = {
- id: serverId,
- transport: listenOpts.cert && listenOpts.key ? "https" : "http",
- hostname: listenOpts.hostname,
- port: listenOpts.port,
- closed: false,
- finished: finishedPromise,
- async close() {
- if (server.closed) {
- return;
- }
- server.closed = true;
- await core.opAsync("op_flash_close_server", serverId);
- await server.finished;
- },
- async serve() {
- let offset = 0;
- while (true) {
+ const serverId = opFn(listenOpts);
+ const serverPromise = core.opAsync("op_flash_drive_server", serverId);
+
+ PromisePrototypeCatch(
+ PromisePrototypeThen(
+ core.opAsync("op_flash_wait_for_listening", serverId),
+ (port) => {
+ onListen({ hostname: listenOpts.hostname, port });
+ },
+ ),
+ () => {},
+ );
+ const finishedPromise = PromisePrototypeCatch(serverPromise, () => {});
+
+ const server = {
+ id: serverId,
+ transport: listenOpts.cert && listenOpts.key ? "https" : "http",
+ hostname: listenOpts.hostname,
+ port: listenOpts.port,
+ closed: false,
+ finished: finishedPromise,
+ async close() {
if (server.closed) {
- break;
+ return;
}
-
- let tokens = nextRequestSync();
- if (tokens === 0) {
- tokens = await core.opAsync("op_flash_next_async", serverId);
+ server.closed = true;
+ await core.opAsync("op_flash_close_server", serverId);
+ await server.finished;
+ },
+ async serve() {
+ let offset = 0;
+ while (true) {
if (server.closed) {
break;
}
- }
- for (let i = offset; i < offset + tokens; i++) {
- let body = null;
- // There might be a body, but we don't expose it for GET/HEAD requests.
- // It will be closed automatically once the request has been handled and
- // the response has been sent.
- const method = getMethodSync(i);
- let hasBody = method > 2; // Not GET/HEAD/CONNECT
- if (hasBody) {
- body = createRequestBodyStream(serverId, i);
- if (body === null) {
- hasBody = false;
+ let tokens = nextRequestSync();
+ if (tokens === 0) {
+ tokens = await core.opAsync("op_flash_next_async", serverId);
+ if (server.closed) {
+ break;
}
}
- const req = fromFlashRequest(
- serverId,
- /* streamRid */
- i,
- body,
- /* methodCb */
- () => methods[method],
- /* urlCb */
- () => {
- const path = core.ops.op_flash_path(serverId, i);
- return `${server.transport}://${server.hostname}:${server.port}${path}`;
- },
- /* headersCb */
- () => core.ops.op_flash_headers(serverId, i),
- );
+ for (let i = offset; i < offset + tokens; i++) {
+ let body = null;
+ // There might be a body, but we don't expose it for GET/HEAD requests.
+ // It will be closed automatically once the request has been handled and
+ // the response has been sent.
+ const method = getMethodSync(i);
+ let hasBody = method > 2; // Not GET/HEAD/CONNECT
+ if (hasBody) {
+ body = createRequestBodyStream(serverId, i);
+ if (body === null) {
+ hasBody = false;
+ }
+ }
- let resp;
- try {
- resp = handler(req);
- if (resp instanceof Promise) {
- PromisePrototypeCatch(
- PromisePrototypeThen(
- resp,
- (resp) =>
- handleResponse(
- req,
- resp,
- body,
- hasBody,
- method,
- serverId,
- i,
- respondFast,
- respondChunked,
- ),
- ),
- onError,
- );
- continue;
- } else if (typeof resp?.then === "function") {
- resp.then((resp) =>
- handleResponse(
- req,
- resp,
- body,
- hasBody,
- method,
- serverId,
- i,
- respondFast,
- respondChunked,
- )
- ).catch(onError);
- continue;
+ const req = fromFlashRequest(
+ serverId,
+ /* streamRid */
+ i,
+ body,
+ /* methodCb */
+ () => methods[method],
+ /* urlCb */
+ () => {
+ const path = core.ops.op_flash_path(serverId, i);
+ return `${server.transport}://${server.hostname}:${server.port}${path}`;
+ },
+ /* headersCb */
+ () => core.ops.op_flash_headers(serverId, i),
+ );
+
+ let resp;
+ try {
+ resp = handler(req);
+ if (resp instanceof Promise) {
+ PromisePrototypeCatch(
+ PromisePrototypeThen(
+ resp,
+ (resp) =>
+ handleResponse(
+ req,
+ resp,
+ body,
+ hasBody,
+ method,
+ serverId,
+ i,
+ respondFast,
+ respondChunked,
+ ),
+ ),
+ onError,
+ );
+ continue;
+ } else if (typeof resp?.then === "function") {
+ resp.then((resp) =>
+ handleResponse(
+ req,
+ resp,
+ body,
+ hasBody,
+ method,
+ serverId,
+ i,
+ respondFast,
+ respondChunked,
+ )
+ ).catch(onError);
+ continue;
+ }
+ } catch (e) {
+ resp = await onError(e);
}
- } catch (e) {
- resp = await onError(e);
+
+ handleResponse(
+ req,
+ resp,
+ body,
+ hasBody,
+ method,
+ serverId,
+ i,
+ respondFast,
+ respondChunked,
+ );
}
- handleResponse(
- req,
- resp,
- body,
- hasBody,
- method,
- serverId,
- i,
- respondFast,
- respondChunked,
- );
+ offset += tokens;
}
+ await server.finished;
+ },
+ };
+
+ signal?.addEventListener("abort", () => {
+ clearInterval(dateInterval);
+ PromisePrototypeThen(server.close(), () => {}, () => {});
+ }, {
+ once: true,
+ });
+
+ function respondChunked(token, chunk, shutdown) {
+ return core.opAsync(
+ "op_flash_respond_chuncked",
+ serverId,
+ token,
+ chunk,
+ shutdown,
+ );
+ }
- offset += tokens;
- }
- await server.finished;
- },
- };
-
- signal?.addEventListener("abort", () => {
- clearInterval(dateInterval);
- PromisePrototypeThen(server.close(), () => {}, () => {});
- }, {
- once: true,
- });
-
- function respondChunked(token, chunk, shutdown) {
- return core.opAsync(
- "op_flash_respond_chuncked",
- serverId,
- token,
- chunk,
- shutdown,
- );
- }
-
- const fastOp = prepareFastCalls();
- let nextRequestSync = () => fastOp.nextRequest();
- let getMethodSync = (token) => fastOp.getMethod(token);
- let respondFast = (token, response, shutdown) =>
- fastOp.respond(token, response, shutdown);
- if (serverId > 0) {
- nextRequestSync = () => core.ops.op_flash_next_server(serverId);
- getMethodSync = (token) => core.ops.op_flash_method(serverId, token);
- respondFast = (token, response, shutdown) =>
- core.ops.op_flash_respond(serverId, token, response, null, shutdown);
- }
+ const fastOp = prepareFastCalls();
+ let nextRequestSync = () => fastOp.nextRequest();
+ let getMethodSync = (token) => fastOp.getMethod(token);
+ let respondFast = (token, response, shutdown) =>
+ fastOp.respond(token, response, shutdown);
+ if (serverId > 0) {
+ nextRequestSync = () => core.ops.op_flash_next_server(serverId);
+ getMethodSync = (token) => core.ops.op_flash_method(serverId, token);
+ respondFast = (token, response, shutdown) =>
+ core.ops.op_flash_respond(serverId, token, response, null, shutdown);
+ }
- if (!dateInterval) {
- date = new Date().toUTCString();
- dateInterval = setInterval(() => {
+ if (!dateInterval) {
date = new Date().toUTCString();
- }, 1000);
- }
+ dateInterval = setInterval(() => {
+ date = new Date().toUTCString();
+ }, 1000);
+ }
- await SafePromiseAll([
- PromisePrototypeCatch(server.serve(), console.error),
- serverPromise,
- ]);
+ await SafePromiseAll([
+ PromisePrototypeCatch(server.serve(), console.error),
+ serverPromise,
+ ]);
+ };
}
function createRequestBodyStream(serverId, token) {
@@ -722,7 +724,7 @@
}
window.__bootstrap.flash = {
- serve,
+ createServe,
upgradeHttpRaw,
};
})(this);
diff --git a/ext/flash/lib.rs b/ext/flash/lib.rs
index 1f3686760..b077b8d21 100644
--- a/ext/flash/lib.rs
+++ b/ext/flash/lib.rs
@@ -1171,15 +1171,13 @@ pub fn resolve_addr_sync(
Ok(result)
}
-#[op]
-fn op_flash_serve<P>(
+fn flash_serve<P>(
state: &mut OpState,
opts: ListenOpts,
) -> Result<u32, AnyError>
where
P: FlashPermissions + 'static,
{
- check_unstable(state, "Deno.serve");
state
.borrow_mut::<P>()
.check_net(&(&opts.hostname, Some(opts.port)), "Deno.serve()")?;
@@ -1224,6 +1222,29 @@ where
}
#[op]
+fn op_flash_serve<P>(
+ state: &mut OpState,
+ opts: ListenOpts,
+) -> Result<u32, AnyError>
+where
+ P: FlashPermissions + 'static,
+{
+ check_unstable(state, "Deno.serve");
+ flash_serve::<P>(state, opts)
+}
+
+#[op]
+fn op_node_unstable_flash_serve<P>(
+ state: &mut OpState,
+ opts: ListenOpts,
+) -> Result<u32, AnyError>
+where
+ P: FlashPermissions + 'static,
+{
+ flash_serve::<P>(state, opts)
+}
+
+#[op]
fn op_flash_wait_for_listening(
state: &mut OpState,
server_id: u32,
@@ -1445,6 +1466,7 @@ pub fn init<P: FlashPermissions + 'static>(unstable: bool) -> Extension {
))
.ops(vec![
op_flash_serve::decl::<P>(),
+ op_node_unstable_flash_serve::decl::<P>(),
op_flash_respond::decl(),
op_flash_respond_async::decl(),
op_flash_respond_chuncked::decl(),
diff --git a/ext/net/01_net.js b/ext/net/01_net.js
index 765b94035..971ec2e8b 100644
--- a/ext/net/01_net.js
+++ b/ext/net/01_net.js
@@ -319,30 +319,32 @@
}
}
- function listenDatagram(args) {
- switch (args.transport) {
- case "udp": {
- const [rid, addr] = ops.op_net_listen_udp(
- {
- hostname: args.hostname ?? "127.0.0.1",
- port: args.port,
- },
- args.reuseAddress ?? false,
- );
- addr.transport = "udp";
- return new Datagram(rid, addr);
- }
- case "unixpacket": {
- const [rid, path] = ops.op_net_listen_unixpacket(args.path);
- const addr = {
- transport: "unixpacket",
- path,
- };
- return new Datagram(rid, addr);
+ function createListenDatagram(udpOpFn, unixOpFn) {
+ return function listenDatagram(args) {
+ switch (args.transport) {
+ case "udp": {
+ const [rid, addr] = udpOpFn(
+ {
+ hostname: args.hostname ?? "127.0.0.1",
+ port: args.port,
+ },
+ args.reuseAddress ?? false,
+ );
+ addr.transport = "udp";
+ return new Datagram(rid, addr);
+ }
+ case "unixpacket": {
+ const [rid, path] = unixOpFn(args.path);
+ const addr = {
+ transport: "unixpacket",
+ path,
+ };
+ return new Datagram(rid, addr);
+ }
+ default:
+ throw new TypeError(`Unsupported transport: '${transport}'`);
}
- default:
- throw new TypeError(`Unsupported transport: '${transport}'`);
- }
+ };
}
async function connect(args) {
@@ -389,7 +391,7 @@
TcpConn,
UnixConn,
listen,
- listenDatagram,
+ createListenDatagram,
Listener,
shutdown,
Datagram,
diff --git a/ext/net/ops.rs b/ext/net/ops.rs
index e6420bf9e..96de8cff1 100644
--- a/ext/net/ops.rs
+++ b/ext/net/ops.rs
@@ -53,10 +53,13 @@ pub fn init<P: NetPermissions + 'static>() -> Vec<OpDecl> {
crate::ops_unix::op_net_connect_unix::decl::<P>(),
op_net_listen_tcp::decl::<P>(),
op_net_listen_udp::decl::<P>(),
+ op_node_unstable_net_listen_udp::decl::<P>(),
#[cfg(unix)]
crate::ops_unix::op_net_listen_unix::decl::<P>(),
#[cfg(unix)]
crate::ops_unix::op_net_listen_unixpacket::decl::<P>(),
+ #[cfg(unix)]
+ crate::ops_unix::op_node_unstable_net_listen_unixpacket::decl::<P>(),
op_net_recv_udp::decl(),
#[cfg(unix)]
crate::ops_unix::op_net_recv_unixpacket::decl(),
@@ -288,8 +291,7 @@ where
Ok((rid, IpAddr::from(local_addr)))
}
-#[op]
-fn op_net_listen_udp<NP>(
+fn net_listen_udp<NP>(
state: &mut OpState,
addr: IpAddr,
reuse_address: bool,
@@ -297,7 +299,6 @@ fn op_net_listen_udp<NP>(
where
NP: NetPermissions + 'static,
{
- super::check_unstable(state, "Deno.listenDatagram");
state
.borrow_mut::<NP>()
.check_net(&(&addr.hostname, Some(addr.port)), "Deno.listenDatagram()")?;
@@ -343,6 +344,32 @@ where
Ok((rid, IpAddr::from(local_addr)))
}
+#[op]
+fn op_net_listen_udp<NP>(
+ state: &mut OpState,
+ addr: IpAddr,
+ reuse_address: bool,
+) -> Result<(ResourceId, IpAddr), AnyError>
+where
+ NP: NetPermissions + 'static,
+{
+ super::check_unstable(state, "Deno.listenDatagram");
+ net_listen_udp::<NP>(state, addr, reuse_address)
+}
+
+#[op]
+fn op_node_unstable_net_listen_udp<NP>(
+ state: &mut OpState,
+ addr: IpAddr,
+ reuse_address: bool,
+) -> Result<(ResourceId, IpAddr), AnyError>
+where
+ NP: NetPermissions + 'static,
+{
+ super::check_unstable(state, "Deno.listenDatagram");
+ net_listen_udp::<NP>(state, addr, reuse_address)
+}
+
#[derive(Serialize, Eq, PartialEq, Debug)]
#[serde(untagged)]
pub enum DnsReturnRecord {
diff --git a/ext/net/ops_unix.rs b/ext/net/ops_unix.rs
index b45b02343..bf03f4015 100644
--- a/ext/net/ops_unix.rs
+++ b/ext/net/ops_unix.rs
@@ -209,8 +209,7 @@ where
Ok((rid, pathname))
}
-#[op]
-pub fn op_net_listen_unixpacket<NP>(
+pub fn net_listen_unixpacket<NP>(
state: &mut OpState,
path: String,
) -> Result<(ResourceId, Option<String>), AnyError>
@@ -218,7 +217,6 @@ where
NP: NetPermissions + 'static,
{
let address_path = Path::new(&path);
- super::check_unstable(state, "Deno.listenDatagram");
let permissions = state.borrow_mut::<NP>();
permissions.check_read(address_path, "Deno.listenDatagram()")?;
permissions.check_write(address_path, "Deno.listenDatagram()")?;
@@ -233,6 +231,29 @@ where
Ok((rid, pathname))
}
+#[op]
+pub fn op_net_listen_unixpacket<NP>(
+ state: &mut OpState,
+ path: String,
+) -> Result<(ResourceId, Option<String>), AnyError>
+where
+ NP: NetPermissions + 'static,
+{
+ super::check_unstable(state, "Deno.listenDatagram");
+ net_listen_unixpacket::<NP>(state, path)
+}
+
+#[op]
+pub fn op_node_unstable_net_listen_unixpacket<NP>(
+ state: &mut OpState,
+ path: String,
+) -> Result<(ResourceId, Option<String>), AnyError>
+where
+ NP: NetPermissions + 'static,
+{
+ net_listen_unixpacket::<NP>(state, path)
+}
+
pub fn pathstring(pathname: &Path) -> Result<String, AnyError> {
into_string(pathname.into())
}
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
+ },
+ })
+}
diff --git a/test_util/std b/test_util/std
-Subproject 241e7eb8f91a06e75d8e7108b1b35ca202adf92
+Subproject c56a8c4e3245dd9ea1a892d2f2150ddba57f29c