1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-20 20:42:19 -05:00

refactor: add 'deno_os' crate (#27655)

This commit creates "deno_os" extension crate and moves
numerous ops from "runtime/" crate to the new crate.
This commit is contained in:
Bartek Iwańczuk 2025-01-14 16:29:36 +00:00 committed by GitHub
parent c943f56949
commit 974e2f44b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 145 additions and 80 deletions

25
Cargo.lock generated
View file

@ -2140,6 +2140,27 @@ dependencies = [
"thiserror 2.0.3",
]
[[package]]
name = "deno_os"
version = "0.1.0"
dependencies = [
"deno_core",
"deno_error",
"deno_path_util",
"deno_permissions",
"deno_telemetry",
"libc",
"netif",
"ntapi",
"once_cell",
"serde",
"signal-hook",
"signal-hook-registry",
"thiserror 2.0.3",
"tokio",
"winapi",
]
[[package]]
name = "deno_package_json"
version = "0.4.0"
@ -2240,6 +2261,7 @@ dependencies = [
"deno_napi",
"deno_net",
"deno_node",
"deno_os",
"deno_path_util",
"deno_permissions",
"deno_resolver",
@ -2263,7 +2285,6 @@ dependencies = [
"hyper-util",
"libc",
"log",
"netif",
"nix",
"node_resolver",
"notify",
@ -2274,8 +2295,6 @@ dependencies = [
"rustyline",
"same-file",
"serde",
"signal-hook",
"signal-hook-registry",
"sys_traits",
"tempfile",
"test_server",

View file

@ -84,6 +84,7 @@ deno_kv = { version = "0.93.0", path = "./ext/kv" }
deno_napi = { version = "0.116.0", path = "./ext/napi" }
deno_net = { version = "0.177.0", path = "./ext/net" }
deno_node = { version = "0.123.0", path = "./ext/node" }
deno_os = { version = "0.1.0", path = "./ext/os" }
deno_telemetry = { version = "0.7.0", path = "./ext/telemetry" }
deno_tls = { version = "0.172.0", path = "./ext/tls" }
deno_url = { version = "0.185.0", path = "./ext/url" }

View file

@ -8,7 +8,7 @@ import {
restorePermissions,
} from "ext:cli/40_test_common.js";
import { Console } from "ext:deno_console/01_console.js";
import { setExitHandler } from "ext:runtime/30_os.js";
import { setExitHandler } from "ext:deno_os/30_os.js";
const {
op_register_bench,
op_bench_get_origin,

View file

@ -26,7 +26,7 @@ const {
TypeError,
} = primordials;
import { setExitHandler } from "ext:runtime/30_os.js";
import { setExitHandler } from "ext:deno_os/30_os.js";
// Capture `Deno` global so that users deleting or mangling it, won't
// have impact on our sanitizers.

View file

@ -596,7 +596,7 @@ async fn listen_ctrl_c(kill_signal: KillSignal) {
#[cfg(unix)]
async fn listen_and_forward_all_signals(kill_signal: KillSignal) {
use deno_core::futures::FutureExt;
use deno_runtime::signal::SIGNAL_NUMS;
use deno_runtime::deno_os::signal::SIGNAL_NUMS;
// listen and forward every signal we support
let mut futures = Vec::with_capacity(SIGNAL_NUMS.len());

View file

@ -855,7 +855,7 @@ fn create_web_worker_callback(
/// Instead probe for the total memory on the system and use it instead
/// as a default.
pub fn create_isolate_create_params() -> Option<v8::CreateParams> {
let maybe_mem_info = deno_runtime::sys_info::mem_info();
let maybe_mem_info = deno_runtime::deno_os::sys_info::mem_info();
maybe_mem_info.map(|mem_info| {
v8::CreateParams::default()
.heap_limits_from_system_memory(mem_info.total, 0)

View file

@ -35,7 +35,7 @@ import { validateIntegerRange } from "ext:deno_node/_utils.ts";
import process from "node:process";
import { isWindows } from "ext:deno_node/_util/os.ts";
import { os } from "ext:deno_node/internal_binding/constants.ts";
import { osUptime } from "ext:runtime/30_os.js";
import { osUptime } from "ext:deno_os/30_os.js";
import { Buffer } from "ext:deno_node/internal/buffer.mjs";
import { primordials } from "ext:core/mod.js";
const { StringPrototypeEndsWith, StringPrototypeSlice } = primordials;

View file

@ -58,7 +58,7 @@ import {
} from "ext:deno_node/_next_tick.ts";
import { isWindows } from "ext:deno_node/_util/os.ts";
import * as io from "ext:deno_io/12_io.js";
import * as denoOs from "ext:runtime/30_os.js";
import * as denoOs from "ext:deno_os/30_os.js";
export let argv0 = "";

33
ext/os/Cargo.toml Normal file
View file

@ -0,0 +1,33 @@
# Copyright 2018-2025 the Deno authors. MIT license.
[package]
name = "deno_os"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
readme = "README.md"
repository.workspace = true
description = "OS specific APIs for Deno"
[lib]
path = "lib.rs"
[dependencies]
deno_core.workspace = true
deno_error.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
deno_telemetry.workspace = true
libc.workspace = true
netif = "0.1.6"
once_cell.workspace = true
serde.workspace = true
signal-hook = "0.3.17"
signal-hook-registry = "1.4.0"
thiserror.workspace = true
tokio.workspace = true
[target.'cfg(windows)'.dependencies]
winapi = { workspace = true, features = ["commapi", "knownfolders", "mswsock", "objbase", "psapi", "shlobj", "tlhelp32", "winbase", "winerror", "winuser", "winsock2"] }
ntapi = "0.4.0"

View file

@ -1,4 +1,6 @@
## `os` ops
# deno_os
This crate implements OS specific APIs for Deno
`loadavg`

View file

@ -1,19 +1,54 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::collections::HashMap;
use std::collections::HashSet;
use std::env;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use deno_core::op2;
use deno_core::v8;
use deno_core::OpState;
use deno_node::NODE_ENV_VAR_ALLOWLIST;
use deno_path_util::normalize_path;
use deno_permissions::PermissionCheckError;
use deno_permissions::PermissionsContainer;
use once_cell::sync::Lazy;
use serde::Serialize;
use crate::sys_info;
use crate::worker::ExitCode;
mod ops;
pub mod signal;
pub mod sys_info;
pub use ops::signal::SignalError;
pub static NODE_ENV_VAR_ALLOWLIST: Lazy<HashSet<String>> = Lazy::new(|| {
// The full list of environment variables supported by Node.js is available
// at https://nodejs.org/api/cli.html#environment-variables
let mut set = HashSet::new();
set.insert("NODE_DEBUG".to_string());
set.insert("NODE_OPTIONS".to_string());
set
});
#[derive(Clone, Default)]
pub struct ExitCode(Arc<AtomicI32>);
impl ExitCode {
pub fn get(&self) -> i32 {
self.0.load(Ordering::Relaxed)
}
pub fn set(&mut self, code: i32) {
self.0.store(code, Ordering::Relaxed);
}
}
pub fn exit(code: i32) -> ! {
deno_telemetry::flush();
#[allow(clippy::disallowed_methods)]
std::process::exit(code);
}
deno_core::extension!(
deno_os,
@ -35,13 +70,21 @@ deno_core::extension!(
op_system_memory_info,
op_uid,
op_runtime_memory_usage,
ops::signal::op_signal_bind,
ops::signal::op_signal_unbind,
ops::signal::op_signal_poll,
],
esm = ["30_os.js", "40_signals.js"],
options = {
exit_code: ExitCode,
},
state = |state, options| {
state.put::<ExitCode>(options.exit_code);
},
#[cfg(unix)]
{
state.put(ops::signal::SignalState::default());
}
}
);
deno_core::extension!(
@ -64,12 +107,16 @@ deno_core::extension!(
op_system_memory_info,
op_uid,
op_runtime_memory_usage,
ops::signal::op_signal_bind,
ops::signal::op_signal_unbind,
ops::signal::op_signal_poll,
],
esm = ["30_os.js", "40_signals.js"],
middleware = |op| match op.name {
"op_exit" | "op_set_exit_code" | "op_get_exit_code" =>
op.with_implementation_from(&deno_core::op_void_sync()),
_ => op,
},
}
);
#[derive(Debug, thiserror::Error, deno_error::JsError)]
@ -196,7 +243,7 @@ fn op_get_exit_code(state: &mut OpState) -> i32 {
#[op2(fast)]
fn op_exit(state: &mut OpState) {
let code = state.borrow::<ExitCode>().get();
crate::exit(code)
exit(code)
}
#[op2(stack_trace)]
@ -239,7 +286,7 @@ fn op_network_interfaces(
Ok(netif::up()?.map(NetworkInterface::from).collect())
}
#[derive(serde::Serialize)]
#[derive(Serialize)]
struct NetworkInterface {
family: &'static str,
name: String,

3
ext/os/ops/mod.rs Normal file
View file

@ -0,0 +1,3 @@
// Copyright 2018-2025 the Deno authors. MIT license.
pub mod signal;

View file

@ -33,17 +33,6 @@ use tokio::signal::windows::CtrlBreak;
#[cfg(windows)]
use tokio::signal::windows::CtrlC;
deno_core::extension!(
deno_signal,
ops = [op_signal_bind, op_signal_unbind, op_signal_poll],
state = |state| {
#[cfg(unix)]
{
state.put(SignalState::default());
}
}
);
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum SignalError {
#[class(type)]
@ -62,7 +51,7 @@ pub enum SignalError {
#[cfg(unix)]
#[derive(Default)]
struct SignalState {
pub struct SignalState {
enable_default_handlers: BTreeMap<libc::c_int, Arc<AtomicBool>>,
}
@ -164,7 +153,7 @@ impl Resource for SignalStreamResource {
#[cfg(unix)]
#[op2(fast)]
#[smi]
fn op_signal_bind(
pub fn op_signal_bind(
state: &mut OpState,
#[string] sig: &str,
) -> Result<ResourceId, SignalError> {
@ -201,7 +190,7 @@ fn op_signal_bind(
#[cfg(windows)]
#[op2(fast)]
#[smi]
fn op_signal_bind(
pub fn op_signal_bind(
state: &mut OpState,
#[string] sig: &str,
) -> Result<ResourceId, SignalError> {
@ -225,7 +214,7 @@ fn op_signal_bind(
}
#[op2(async)]
async fn op_signal_poll(
pub async fn op_signal_poll(
state: Rc<RefCell<OpState>>,
#[smi] rid: ResourceId,
) -> Result<bool, ResourceError> {

View file

@ -49,6 +49,7 @@ deno_core.workspace = true
deno_cron.workspace = true
deno_crypto.workspace = true
deno_fetch.workspace = true
deno_os.workspace = true
deno_ffi.workspace = true
deno_fs = { workspace = true, features = ["sync_fs"] }
deno_http.workspace = true
@ -89,6 +90,7 @@ deno_kv.workspace = true
deno_napi.workspace = true
deno_net.workspace = true
deno_node.workspace = true
deno_os.workspace = true
deno_path_util.workspace = true
deno_permissions.workspace = true
deno_resolver.workspace = true
@ -114,7 +116,6 @@ hyper-util.workspace = true
hyper_v014 = { workspace = true, features = ["server", "stream", "http1", "http2", "runtime"] }
libc.workspace = true
log.workspace = true
netif = "0.1.6"
notify.workspace = true
once_cell.workspace = true
percent-encoding.workspace = true
@ -122,8 +123,6 @@ regex.workspace = true
rustyline = { workspace = true, features = ["custom-bindings"] }
same-file = "1.0.6"
serde.workspace = true
signal-hook = "0.3.17"
signal-hook-registry = "1.4.0"
sys_traits.workspace = true
tempfile.workspace = true
thiserror.workspace = true

View file

@ -21,10 +21,10 @@ import * as version from "ext:runtime/01_version.ts";
import * as permissions from "ext:runtime/10_permissions.js";
import * as io from "ext:deno_io/12_io.js";
import * as fs from "ext:deno_fs/30_fs.js";
import * as os from "ext:runtime/30_os.js";
import * as os from "ext:deno_os/30_os.js";
import * as fsEvents from "ext:runtime/40_fs_events.js";
import * as process from "ext:runtime/40_process.js";
import * as signals from "ext:runtime/40_signals.js";
import * as signals from "ext:deno_os/40_signals.js";
import * as tty from "ext:runtime/40_tty.js";
import * as kv from "ext:deno_kv/01_db.ts";
import * as cron from "ext:deno_cron/01_cron.ts";

View file

@ -55,7 +55,7 @@ import { registerDeclarativeServer } from "ext:deno_http/00_serve.ts";
import * as event from "ext:deno_web/02_event.js";
import * as location from "ext:deno_web/12_location.js";
import * as version from "ext:runtime/01_version.ts";
import * as os from "ext:runtime/30_os.js";
import * as os from "ext:deno_os/30_os.js";
import * as timers from "ext:deno_web/02_timers.js";
import {
getDefaultInspectOptions,

View file

@ -16,6 +16,7 @@ pub use deno_kv;
pub use deno_napi;
pub use deno_net;
pub use deno_node;
pub use deno_os;
pub use deno_permissions;
pub use deno_terminal::colors;
pub use deno_tls;
@ -33,9 +34,7 @@ pub mod inspector_server;
pub mod js;
pub mod ops;
pub mod permissions;
pub mod signal;
pub mod snapshot;
pub mod sys_info;
pub mod tokio_util;
pub mod web_worker;
pub mod worker;
@ -46,6 +45,7 @@ pub use worker_bootstrap::WorkerExecutionMode;
pub use worker_bootstrap::WorkerLogLevel;
pub mod shared;
pub use deno_os::exit;
pub use shared::runtime;
pub struct UnstableGranularFlag {
@ -147,12 +147,6 @@ pub static UNSTABLE_GRANULAR_FLAGS: &[UnstableGranularFlag] = &[
},
];
pub fn exit(code: i32) -> ! {
deno_telemetry::flush();
#[allow(clippy::disallowed_methods)]
std::process::exit(code);
}
#[cfg(test)]
mod test {
use super::*;

View file

@ -3,11 +3,9 @@
pub mod bootstrap;
pub mod fs_events;
pub mod http;
pub mod os;
pub mod permissions;
pub mod process;
pub mod runtime;
pub mod signal;
pub mod tty;
pub mod web_worker;
pub mod worker_host;

View file

@ -31,14 +31,13 @@ use deno_io::ChildStderrResource;
use deno_io::ChildStdinResource;
use deno_io::ChildStdoutResource;
use deno_io::IntoRawIoHandle;
use deno_os::SignalError;
use deno_permissions::PermissionsContainer;
use deno_permissions::RunQueryDescriptor;
use serde::Deserialize;
use serde::Serialize;
use tokio::process::Command;
use crate::ops::signal::SignalError;
pub const UNSTABLE_FEATURE_NAME: &str = "process";
#[derive(Copy, Clone, Eq, PartialEq, Deserialize)]
@ -296,7 +295,7 @@ impl TryFrom<ExitStatus> for ChildStatus {
success: false,
code: 128 + signal,
#[cfg(unix)]
signal: Some(crate::signal::signal_int_to_str(signal)?.to_string()),
signal: Some(deno_os::signal::signal_int_to_str(signal)?.to_string()),
#[cfg(not(unix))]
signal: None,
}
@ -1116,7 +1115,7 @@ mod deprecated {
#[cfg(unix)]
pub fn kill(pid: i32, signal: &str) -> Result<(), ProcessError> {
let signo = crate::signal::signal_str_to_int(signal)
let signo = deno_os::signal::signal_str_to_int(signal)
.map_err(SignalError::InvalidSignalStr)?;
use nix::sys::signal::kill as unix_kill;
use nix::sys::signal::Signal;
@ -1144,7 +1143,7 @@ mod deprecated {
if !matches!(signal, "SIGKILL" | "SIGTERM") {
Err(
SignalError::InvalidSignalStr(crate::signal::InvalidSignalStrError(
SignalError::InvalidSignalStr(deno_os::signal::InvalidSignalStrError(
signal.to_string(),
))
.into(),

View file

@ -42,10 +42,8 @@ extension!(runtime,
"06_util.js",
"10_permissions.js",
"11_workers.js",
"30_os.js",
"40_fs_events.js",
"40_process.js",
"40_signals.js",
"40_tty.js",
"41_prompt.js",
"90_deno_ns.js",

View file

@ -310,6 +310,7 @@ pub fn create_runtime_snapshot(
),
deno_io::deno_io::init_ops_and_esm(Default::default()),
deno_fs::deno_fs::init_ops_and_esm::<Permissions>(fs.clone()),
deno_os::deno_os::init_ops_and_esm(Default::default()),
deno_node::deno_node::init_ops_and_esm::<
Permissions,
DenoInNpmPackageChecker,
@ -323,10 +324,8 @@ pub fn create_runtime_snapshot(
None,
),
ops::fs_events::deno_fs_events::init_ops(),
ops::os::deno_os::init_ops(Default::default()),
ops::permissions::deno_permissions::init_ops(),
ops::process::deno_process::init_ops(None),
ops::signal::deno_signal::init_ops(),
ops::tty::deno_tty::init_ops(),
ops::http::deno_http_runtime::init_ops(),
ops::bootstrap::deno_bootstrap::init_ops(Some(snapshot_options)),

View file

@ -528,6 +528,7 @@ impl WebWorker {
deno_fs::deno_fs::init_ops_and_esm::<PermissionsContainer>(
services.fs.clone(),
),
deno_os::deno_os_worker::init_ops_and_esm(),
deno_node::deno_node::init_ops_and_esm::<
PermissionsContainer,
TInNpmPackageChecker,
@ -541,12 +542,10 @@ impl WebWorker {
options.format_js_error_fn,
),
ops::fs_events::deno_fs_events::init_ops_and_esm(),
ops::os::deno_os_worker::init_ops_and_esm(),
ops::permissions::deno_permissions::init_ops_and_esm(),
ops::process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,
),
ops::signal::deno_signal::init_ops_and_esm(),
ops::tty::deno_tty::init_ops_and_esm(),
ops::http::deno_http_runtime::init_ops_and_esm(),
ops::bootstrap::deno_bootstrap::init_ops_and_esm(

View file

@ -3,8 +3,6 @@ use std::borrow::Cow;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
@ -40,6 +38,7 @@ use deno_io::Stdio;
use deno_kv::dynamic::MultiBackendDbHandler;
use deno_node::ExtNodeSys;
use deno_node::NodeExtInitServices;
use deno_os::ExitCode;
use deno_permissions::PermissionsContainer;
use deno_tls::RootCertStoreProvider;
use deno_tls::TlsKeys;
@ -97,19 +96,6 @@ pub fn validate_import_attributes_callback(
}
}
#[derive(Clone, Default)]
pub struct ExitCode(Arc<AtomicI32>);
impl ExitCode {
pub fn get(&self) -> i32 {
self.0.load(Relaxed)
}
pub fn set(&mut self, code: i32) {
self.0.store(code, Relaxed);
}
}
/// This worker is created and used by almost all
/// subcommands in Deno executable.
///
@ -363,7 +349,7 @@ impl MainWorker {
// Permissions: many ops depend on this
let enable_testing_features = options.bootstrap.enable_testing_features;
let exit_code = ExitCode(Arc::new(AtomicI32::new(0)));
let exit_code = ExitCode::default();
let create_cache = options.cache_storage_dir.map(|storage_dir| {
let create_cache_fn = move || SqliteBackedCache::new(storage_dir.clone());
CreateCache(Arc::new(create_cache_fn))
@ -441,6 +427,7 @@ impl MainWorker {
deno_fs::deno_fs::init_ops_and_esm::<PermissionsContainer>(
services.fs.clone(),
),
deno_os::deno_os::init_ops_and_esm(exit_code.clone()),
deno_node::deno_node::init_ops_and_esm::<
PermissionsContainer,
TInNpmPackageChecker,
@ -454,12 +441,10 @@ impl MainWorker {
options.format_js_error_fn.clone(),
),
ops::fs_events::deno_fs_events::init_ops_and_esm(),
ops::os::deno_os::init_ops_and_esm(exit_code.clone()),
ops::permissions::deno_permissions::init_ops_and_esm(),
ops::process::deno_process::init_ops_and_esm(
services.npm_process_state_provider,
),
ops::signal::deno_signal::init_ops_and_esm(),
ops::tty::deno_tty::init_ops_and_esm(),
ops::http::deno_http_runtime::init_ops_and_esm(),
ops::bootstrap::deno_bootstrap::init_ops_and_esm(

View file

@ -445,7 +445,7 @@ fn permissions_trace() {
test_util::assertions::assert_wildcard_match(&text, concat!(
"┏ ⚠️ Deno requests sys access to \"hostname\".\r\n",
"┠─ Requested by `Deno.hostname()` API.\r\n",
"┃ ├─ Object.hostname (ext:runtime/30_os.js:43:10)\r\n",
"┃ ├─ Object.hostname (ext:deno_os/30_os.js:43:10)\r\n",
"┃ ├─ foo (file://[WILDCARD]/run/permissions_trace.ts:2:8)\r\n",
"┃ ├─ bar (file://[WILDCARD]/run/permissions_trace.ts:6:3)\r\n",
"┃ └─ file://[WILDCARD]/run/permissions_trace.ts:9:1\r\n",

View file

@ -239,10 +239,10 @@
"ext:runtime/06_util.js": "../runtime/js/06_util.js",
"ext:runtime/10_permissions.js": "../runtime/js/10_permissions.js",
"ext:runtime/11_workers.js": "../runtime/js/11_workers.js",
"ext:runtime/30_os.js": "../runtime/js/30_os.js",
"ext:deno_os/30_os.js": "../ext/os/30_os.js",
"ext:runtime/40_fs_events.js": "../runtime/js/40_fs_events.js",
"ext:runtime/40_process.js": "../runtime/js/40_process.js",
"ext:runtime/40_signals.js": "../runtime/js/40_signals.js",
"ext:deno_os/40_signals.js": "../ext/os/40_signals.js",
"ext:runtime/40_tty.js": "../runtime/js/40_tty.js",
"ext:runtime/41_prompt.js": "../runtime/js/41_prompt.js",
"ext:runtime/90_deno_ns.js": "../runtime/js/90_deno_ns.js",