From 4638caa74044cf5100f515b49c3a86522f013fc9 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Tue, 31 Dec 2024 11:29:07 -0500 Subject: [PATCH] refactor: do not use `deno_fs::FileSystem` everywhere (#27508) This changes the cli to mostly use `std::fs` via `sys_traits` instead of the implemention of `deno_fs::FileSystem`. --- Cargo.lock | 10 +- Cargo.toml | 2 +- cli/Cargo.toml | 3 +- cli/args/lockfile.rs | 21 +- cli/args/mod.rs | 20 +- cli/cache/deno_dir.rs | 13 +- cli/cache/disk_cache.rs | 22 +- cli/cache/emit.rs | 5 +- cli/cache/mod.rs | 13 +- cli/clippy.toml | 1 + cli/factory.rs | 68 ++-- cli/file_fetcher.rs | 58 ++-- cli/graph_util.rs | 12 +- cli/lsp/cache.rs | 11 +- cli/lsp/config.rs | 36 ++- cli/lsp/diagnostics.rs | 4 +- cli/lsp/language_server.rs | 8 +- cli/lsp/registries.rs | 9 +- cli/lsp/resolver.rs | 32 +- cli/main.rs | 1 + cli/mainrt.rs | 7 +- cli/module_loader.rs | 14 +- cli/node.rs | 6 +- cli/npm/byonm.rs | 6 +- cli/npm/managed/mod.rs | 10 +- cli/npm/managed/resolvers/common.rs | 8 +- cli/npm/managed/resolvers/global.rs | 4 +- cli/npm/managed/resolvers/local.rs | 8 +- cli/npm/managed/resolvers/mod.rs | 4 +- cli/npm/mod.rs | 12 +- cli/resolver.rs | 20 +- cli/standalone/binary.rs | 4 - cli/standalone/code_cache.rs | 3 +- cli/standalone/file_system.rs | 450 +++++++++++++++++++++++++- cli/standalone/mod.rs | 27 +- cli/standalone/virtual_fs.rs | 264 +++++++-------- cli/sys.rs | 218 +++++++++++++ cli/task_runner.rs | 6 +- cli/tools/bench/mod.rs | 3 +- cli/tools/check.rs | 6 +- cli/tools/clean.rs | 3 +- cli/tools/compile.rs | 2 +- cli/tools/coverage/mod.rs | 4 +- cli/tools/doc.rs | 6 +- cli/tools/fmt.rs | 6 +- cli/tools/installer.rs | 1 + cli/tools/lint/linter.rs | 4 +- cli/tools/lint/mod.rs | 4 +- cli/tools/registry/paths.rs | 4 +- cli/tools/registry/pm.rs | 1 + cli/tools/registry/pm/outdated.rs | 1 + cli/tools/registry/unfurl.rs | 9 +- cli/tools/task.rs | 4 +- cli/tools/test/mod.rs | 3 +- cli/tsc/mod.rs | 10 +- cli/util/fs.rs | 16 +- cli/worker.rs | 26 +- ext/fs/Cargo.toml | 2 - ext/fs/in_memory_fs.rs | 481 ---------------------------- ext/fs/interface.rs | 342 +------------------- ext/fs/lib.rs | 5 - ext/fs/ops.rs | 55 +--- ext/fs/std_fs.rs | 2 +- ext/node/Cargo.toml | 3 +- ext/node/lib.rs | 58 ++-- ext/node/ops/require.rs | 151 +++++---- ext/node/ops/worker_threads.rs | 31 +- runtime/Cargo.toml | 1 + runtime/errors.rs | 4 +- runtime/examples/extension/main.rs | 7 +- runtime/permissions.rs | 31 +- runtime/snapshot.rs | 5 +- runtime/web_worker.rs | 15 +- runtime/worker.rs | 15 +- 74 files changed, 1304 insertions(+), 1437 deletions(-) create mode 100644 cli/sys.rs delete mode 100644 ext/fs/in_memory_fs.rs diff --git a/Cargo.lock b/Cargo.lock index 0fb9493629..bad4a8ea2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1737,14 +1737,12 @@ dependencies = [ "deno_path_util 0.3.0", "deno_permissions", "filetime", - "getrandom", "junction", "libc", "nix", "rand", "rayon", "serde", - "sys_traits", "thiserror 2.0.3", "winapi", "windows-sys 0.59.0", @@ -2042,6 +2040,7 @@ dependencies = [ "sm3", "spki", "stable_deref_trait", + "sys_traits", "thiserror 2.0.3", "tokio", "tokio-eld", @@ -2261,6 +2260,7 @@ dependencies = [ "serde", "signal-hook", "signal-hook-registry", + "sys_traits", "tempfile", "test_server", "thiserror 2.0.3", @@ -7680,12 +7680,14 @@ dependencies = [ [[package]] name = "sys_traits" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5a12729b699487bb50163466e87be7197871d83d04cc6815d430cf7c893bbd7" +checksum = "6683465f4e1d8fd75069cbc36c646258c05b7d8d6676bcb5d71968b99b7d5ae2" dependencies = [ + "filetime", "getrandom", "libc", + "parking_lot", "windows-sys 0.59.0", ] diff --git a/Cargo.toml b/Cargo.toml index 442680c332..bfd7437441 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -193,7 +193,7 @@ slab = "0.4" smallvec = "1.8" socket2 = { version = "0.5.3", features = ["all"] } spki = "0.7.2" -sys_traits = "=0.1.1" +sys_traits = "=0.1.4" tar = "=0.4.40" tempfile = "3.4.0" termcolor = "1.1.3" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 2cf12f14d4..d05c3fb3e3 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -158,7 +158,7 @@ shell-escape = "=0.1.5" spki = { version = "0.7", features = ["pem"] } sqlformat = "=0.3.2" strsim = "0.11.1" -sys_traits = { workspace = true, features = ["libc", "real", "winapi"] } +sys_traits = { workspace = true, features = ["getrandom", "filetime", "libc", "real", "strip_unc", "winapi"] } tar.workspace = true tempfile.workspace = true text-size = "=1.1.0" @@ -187,6 +187,7 @@ nix.workspace = true [dev-dependencies] deno_bench_util.workspace = true pretty_assertions.workspace = true +sys_traits = { workspace = true, features = ["memory"] } test_util.workspace = true [package.metadata.winres] diff --git a/cli/args/lockfile.rs b/cli/args/lockfile.rs index 0648b6e5ed..7d5fe57bc3 100644 --- a/cli/args/lockfile.rs +++ b/cli/args/lockfile.rs @@ -13,12 +13,12 @@ use deno_core::serde_json; use deno_lockfile::WorkspaceMemberConfig; use deno_package_json::PackageJsonDepValue; use deno_path_util::fs::atomic_write_file_with_retries; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::PackageJson; use deno_semver::jsr::JsrDepPackageReq; use crate::args::deno_json::import_map_deps; use crate::cache; +use crate::sys::CliSys; use crate::Flags; use crate::args::DenoSubcommand; @@ -36,6 +36,7 @@ pub struct CliLockfileReadFromPathOptions { #[derive(Debug)] pub struct CliLockfile { + sys: CliSys, lockfile: Mutex, pub filename: PathBuf, frozen: bool, @@ -92,7 +93,7 @@ impl CliLockfile { // do an atomic write to reduce the chance of multiple deno // processes corrupting the file atomic_write_file_with_retries( - &FsSysTraitsAdapter::new_real(), + &self.sys, &lockfile.filename, &bytes, cache::CACHE_PERM, @@ -103,6 +104,7 @@ impl CliLockfile { } pub fn discover( + sys: &CliSys, flags: &Flags, workspace: &Workspace, maybe_external_import_map: Option<&serde_json::Value>, @@ -165,11 +167,14 @@ impl CliLockfile { .unwrap_or(false) }); - let lockfile = Self::read_from_path(CliLockfileReadFromPathOptions { - file_path, - frozen, - skip_write: flags.internal.lockfile_skip_write, - })?; + let lockfile = Self::read_from_path( + sys, + CliLockfileReadFromPathOptions { + file_path, + frozen, + skip_write: flags.internal.lockfile_skip_write, + }, + )?; // initialize the lockfile with the workspace's configuration let root_url = workspace.root_dir(); @@ -225,6 +230,7 @@ impl CliLockfile { } pub fn read_from_path( + sys: &CliSys, opts: CliLockfileReadFromPathOptions, ) -> Result { let lockfile = match std::fs::read_to_string(&opts.file_path) { @@ -243,6 +249,7 @@ impl CliLockfile { } }; Ok(CliLockfile { + sys: sys.clone(), filename: lockfile.filename.clone(), lockfile: Mutex::new(lockfile), frozen: opts.frozen, diff --git a/cli/args/mod.rs b/cli/args/mod.rs index aa3a251105..a059b07757 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -30,7 +30,6 @@ use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; use deno_npm::NpmSystemInfo; use deno_path_util::normalize_path; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_semver::npm::NpmPackageReqReference; use deno_semver::StackString; use deno_telemetry::OtelConfig; @@ -89,6 +88,7 @@ use thiserror::Error; use crate::cache::DenoDirProvider; use crate::file_fetcher::CliFileFetcher; +use crate::sys::CliSys; use crate::util::fs::canonicalize_path_maybe_not_exists; use crate::version; @@ -573,7 +573,7 @@ fn discover_npmrc( // TODO(bartlomieju): update to read both files - one in the project root and one and // home dir and then merge them. // 3. Try `.npmrc` in the user's home directory - if let Some(home_dir) = sys_traits::impls::RealSys.env_home_dir() { + if let Some(home_dir) = crate::sys::CliSys::default().env_home_dir() { match try_to_read_npmrc(&home_dir) { Ok(Some((source, path))) => { return try_to_parse_npmrc(source, &path).map(|r| (r, Some(path))); @@ -772,7 +772,9 @@ pub struct CliOptions { } impl CliOptions { + #[allow(clippy::too_many_arguments)] pub fn new( + sys: &CliSys, flags: Arc, initial_cwd: PathBuf, maybe_lockfile: Option>, @@ -797,8 +799,10 @@ impl CliOptions { } let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache); - let deno_dir_provider = - Arc::new(DenoDirProvider::new(flags.internal.cache_path.clone())); + let deno_dir_provider = Arc::new(DenoDirProvider::new( + sys.clone(), + flags.internal.cache_path.clone(), + )); let maybe_node_modules_folder = resolve_node_modules_folder( &initial_cwd, &flags, @@ -823,7 +827,7 @@ impl CliOptions { }) } - pub fn from_flags(flags: Arc) -> Result { + pub fn from_flags(sys: &CliSys, flags: Arc) -> Result { let initial_cwd = std::env::current_dir().with_context(|| "Failed getting cwd.")?; let maybe_vendor_override = flags.vendor.map(|v| match v { @@ -867,7 +871,7 @@ impl CliOptions { ConfigFlag::Discover => { if let Some(start_paths) = flags.config_path_args(&initial_cwd) { WorkspaceDirectory::discover( - &FsSysTraitsAdapter::new_real(), + sys, WorkspaceDiscoverStart::Paths(&start_paths), &resolve_workspace_discover_options(), )? @@ -878,7 +882,7 @@ impl CliOptions { ConfigFlag::Path(path) => { let config_path = normalize_path(initial_cwd.join(path)); WorkspaceDirectory::discover( - &FsSysTraitsAdapter::new_real(), + sys, WorkspaceDiscoverStart::ConfigFile(&config_path), &resolve_workspace_discover_options(), )? @@ -917,6 +921,7 @@ impl CliOptions { }; let maybe_lock_file = CliLockfile::discover( + sys, &flags, &start_dir.workspace, external_import_map.as_ref().map(|(_, v)| v), @@ -925,6 +930,7 @@ impl CliOptions { log::debug!("Finished config loading."); Self::new( + sys, flags, initial_cwd, maybe_lock_file.map(Arc::new), diff --git a/cli/cache/deno_dir.rs b/cli/cache/deno_dir.rs index d83ea8ebd5..90a3add54e 100644 --- a/cli/cache/deno_dir.rs +++ b/cli/cache/deno_dir.rs @@ -3,6 +3,8 @@ use deno_cache_dir::DenoDirResolutionError; use once_cell::sync::OnceCell; +use crate::sys::CliSys; + use super::DiskCache; use std::env; @@ -11,13 +13,15 @@ use std::path::PathBuf; /// Lazily creates the deno dir which might be useful in scenarios /// where functionality wants to continue if the DENO_DIR can't be created. pub struct DenoDirProvider { + sys: CliSys, maybe_custom_root: Option, deno_dir: OnceCell>, } impl DenoDirProvider { - pub fn new(maybe_custom_root: Option) -> Self { + pub fn new(sys: CliSys, maybe_custom_root: Option) -> Self { Self { + sys, maybe_custom_root, deno_dir: Default::default(), } @@ -26,7 +30,9 @@ impl DenoDirProvider { pub fn get_or_create(&self) -> Result<&DenoDir, DenoDirResolutionError> { self .deno_dir - .get_or_init(|| DenoDir::new(self.maybe_custom_root.clone())) + .get_or_init(|| { + DenoDir::new(self.sys.clone(), self.maybe_custom_root.clone()) + }) .as_ref() .map_err(|err| match err { DenoDirResolutionError::NoCacheOrHomeDir => { @@ -53,6 +59,7 @@ pub struct DenoDir { impl DenoDir { pub fn new( + sys: CliSys, maybe_custom_root: Option, ) -> Result { let root = deno_cache_dir::resolve_deno_dir( @@ -64,7 +71,7 @@ impl DenoDir { let deno_dir = Self { root, - gen_cache: DiskCache::new(&gen_path), + gen_cache: DiskCache::new(sys, &gen_path), }; Ok(deno_dir) diff --git a/cli/cache/disk_cache.rs b/cli/cache/disk_cache.rs index b22b2e3cc7..c96a3943c0 100644 --- a/cli/cache/disk_cache.rs +++ b/cli/cache/disk_cache.rs @@ -1,12 +1,13 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use crate::sys::CliSys; + use super::CACHE_PERM; use deno_cache_dir::url_to_filename; use deno_core::url::Host; use deno_core::url::Url; use deno_path_util::fs::atomic_write_file_with_retries; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use std::ffi::OsStr; use std::fs; use std::path::Component; @@ -17,14 +18,16 @@ use std::str; #[derive(Debug, Clone)] pub struct DiskCache { + sys: CliSys, pub location: PathBuf, } impl DiskCache { /// `location` must be an absolute path. - pub fn new(location: &Path) -> Self { + pub fn new(sys: CliSys, location: &Path) -> Self { assert!(location.is_absolute()); Self { + sys, location: location.to_owned(), } } @@ -121,12 +124,7 @@ impl DiskCache { pub fn set(&self, filename: &Path, data: &[u8]) -> std::io::Result<()> { let path = self.location.join(filename); - atomic_write_file_with_retries( - &FsSysTraitsAdapter::new_real(), - &path, - data, - CACHE_PERM, - ) + atomic_write_file_with_retries(&self.sys, &path, data, CACHE_PERM) } } @@ -139,7 +137,7 @@ mod tests { fn test_set_get_cache_file() { let temp_dir = TempDir::new(); let sub_dir = temp_dir.path().join("sub_dir"); - let cache = DiskCache::new(&sub_dir.to_path_buf()); + let cache = DiskCache::new(CliSys::default(), &sub_dir.to_path_buf()); let path = PathBuf::from("foo/bar.txt"); cache.set(&path, b"hello").unwrap(); assert_eq!(cache.get(&path).unwrap(), b"hello"); @@ -153,7 +151,7 @@ mod tests { PathBuf::from("/deno_dir/") }; - let cache = DiskCache::new(&cache_location); + let cache = DiskCache::new(CliSys::default(), &cache_location); let mut test_cases = vec![ ( @@ -209,7 +207,7 @@ mod tests { } else { "/foo" }; - let cache = DiskCache::new(&PathBuf::from(p)); + let cache = DiskCache::new(CliSys::default(), &PathBuf::from(p)); let mut test_cases = vec![ ( @@ -257,7 +255,7 @@ mod tests { PathBuf::from("/deno_dir/") }; - let cache = DiskCache::new(&cache_location); + let cache = DiskCache::new(CliSys::default(), &cache_location); let mut test_cases = vec!["unknown://localhost/test.ts"]; diff --git a/cli/cache/emit.rs b/cli/cache/emit.rs index 3c9eecfcbd..b239cc93ba 100644 --- a/cli/cache/emit.rs +++ b/cli/cache/emit.rs @@ -159,12 +159,15 @@ impl EmitFileSerializer { mod test { use test_util::TempDir; + use crate::sys::CliSys; + use super::*; #[test] pub fn emit_cache_general_use() { let temp_dir = TempDir::new(); - let disk_cache = DiskCache::new(temp_dir.path().as_path()); + let disk_cache = + DiskCache::new(CliSys::default(), temp_dir.path().as_path()); let cache = EmitCache { disk_cache: disk_cache.clone(), file_serializer: EmitFileSerializer { diff --git a/cli/cache/mod.rs b/cli/cache/mod.rs index c8b0eacaa4..bc6f792667 100644 --- a/cli/cache/mod.rs +++ b/cli/cache/mod.rs @@ -5,6 +5,7 @@ use crate::file_fetcher::CliFetchNoFollowErrorKind; use crate::file_fetcher::CliFileFetcher; use crate::file_fetcher::FetchNoFollowOptions; use crate::file_fetcher::FetchPermissionsOptionRef; +use crate::sys::CliSys; use deno_ast::MediaType; use deno_cache_dir::file_fetcher::CacheSetting; @@ -18,7 +19,6 @@ use deno_graph::source::CacheInfo; use deno_graph::source::LoadFuture; use deno_graph::source::LoadResponse; use deno_graph::source::Loader; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_permissions::PermissionsContainer; use node_resolver::InNpmPackageChecker; use std::collections::HashMap; @@ -58,10 +58,9 @@ pub use parsed_source::ParsedSourceCache; /// Permissions used to save a file in the disk caches. pub use deno_cache_dir::CACHE_PERM; -pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache; -pub type LocalHttpCache = deno_cache_dir::LocalHttpCache; -pub type LocalLspHttpCache = - deno_cache_dir::LocalLspHttpCache; +pub type GlobalHttpCache = deno_cache_dir::GlobalHttpCache; +pub type LocalHttpCache = deno_cache_dir::LocalHttpCache; +pub type LocalLspHttpCache = deno_cache_dir::LocalLspHttpCache; pub use deno_cache_dir::HttpCache; pub struct FetchCacherOptions { @@ -80,7 +79,7 @@ pub struct FetchCacher { in_npm_pkg_checker: Arc, module_info_cache: Arc, permissions: PermissionsContainer, - sys: FsSysTraitsAdapter, + sys: CliSys, is_deno_publish: bool, cache_info_enabled: bool, } @@ -91,7 +90,7 @@ impl FetchCacher { global_http_cache: Arc, in_npm_pkg_checker: Arc, module_info_cache: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, options: FetchCacherOptions, ) -> Self { Self { diff --git a/cli/clippy.toml b/cli/clippy.toml index f1c25acfb8..21a544aebd 100644 --- a/cli/clippy.toml +++ b/cli/clippy.toml @@ -4,6 +4,7 @@ disallowed-methods = [ ] disallowed-types = [ { path = "reqwest::Client", reason = "use crate::http_util::HttpClient instead" }, + { path = "sys_traits::impls::RealSys", reason = "use crate::sys::CliSys instead" }, ] ignore-interior-mutability = [ "lsp_types::Uri", diff --git a/cli/factory.rs b/cli/factory.rs index 5c73537743..e33b95d235 100644 --- a/cli/factory.rs +++ b/cli/factory.rs @@ -31,6 +31,8 @@ use crate::module_loader::CliModuleLoaderFactory; use crate::module_loader::ModuleLoadPreparer; use crate::node::CliCjsCodeAnalyzer; use crate::node::CliNodeCodeTranslator; +use crate::node::CliNodeResolver; +use crate::node::CliPackageJsonResolver; use crate::npm::create_cli_npm_resolver; use crate::npm::create_in_npm_pkg_checker; use crate::npm::CliByonmNpmResolverCreateOptions; @@ -48,7 +50,8 @@ use crate::resolver::CliResolverOptions; use crate::resolver::CliSloppyImportsResolver; use crate::resolver::NpmModuleLoader; use crate::resolver::SloppyImportsCachedFs; -use crate::standalone::DenoCompileBinaryWriter; +use crate::standalone::binary::DenoCompileBinaryWriter; +use crate::sys::CliSys; use crate::tools::check::TypeChecker; use crate::tools::coverage::CoverageCollector; use crate::tools::lint::LintRuleProvider; @@ -74,9 +77,7 @@ use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::DenoResolverOptions; use deno_resolver::NodeAndNpmReqResolver; use deno_runtime::deno_fs; -use deno_runtime::deno_fs::FsSysTraitsAdapter; -use deno_runtime::deno_node::NodeResolver; -use deno_runtime::deno_node::PackageJsonResolver; +use deno_runtime::deno_fs::RealFs; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; use deno_runtime::deno_permissions::Permissions; use deno_runtime::deno_permissions::PermissionsContainer; @@ -198,13 +199,14 @@ struct CliFactoryServices { module_info_cache: Deferred>, module_load_preparer: Deferred>, node_code_translator: Deferred>, - node_resolver: Deferred>, + node_resolver: Deferred>, npm_cache_dir: Deferred>, npm_req_resolver: Deferred>, npm_resolver: Deferred>, parsed_source_cache: Deferred>, - permission_desc_parser: Deferred>, - pkg_json_resolver: Deferred>, + permission_desc_parser: + Deferred>>, + pkg_json_resolver: Deferred>, resolver: Deferred>, root_cert_store_provider: Deferred>, root_permissions_container: Deferred, @@ -254,7 +256,7 @@ impl CliFactory { pub fn cli_options(&self) -> Result<&Arc, AnyError> { self.services.cli_options.get_or_try_init(|| { - CliOptions::from_flags(self.flags.clone()).map(Arc::new) + CliOptions::from_flags(&self.sys(), self.flags.clone()).map(Arc::new) }) } @@ -317,7 +319,7 @@ impl CliFactory { pub fn global_http_cache(&self) -> Result<&Arc, AnyError> { self.services.global_http_cache.get_or_try_init(|| { Ok(Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter(self.fs().clone()), + self.sys(), self.deno_dir()?.remote_folder_path(), ))) }) @@ -355,6 +357,7 @@ impl CliFactory { Ok(Arc::new(CliFileFetcher::new( self.http_cache()?.clone(), self.http_client_provider().clone(), + self.sys(), self.blob_store().clone(), Some(self.text_only_progress_bar().clone()), !cli_options.no_remote(), @@ -365,7 +368,11 @@ impl CliFactory { } pub fn fs(&self) -> &Arc { - self.services.fs.get_or_init(|| Arc::new(deno_fs::RealFs)) + self.services.fs.get_or_init(|| Arc::new(RealFs)) + } + + pub fn sys(&self) -> CliSys { + CliSys::default() // very cheap to make } pub fn in_npm_pkg_checker( @@ -391,11 +398,10 @@ impl CliFactory { pub fn npm_cache_dir(&self) -> Result<&Arc, AnyError> { self.services.npm_cache_dir.get_or_try_init(|| { - let fs = self.fs(); let global_path = self.deno_dir()?.npm_folder_path(); let cli_options = self.cli_options()?; Ok(Arc::new(NpmCacheDir::new( - &FsSysTraitsAdapter(fs.clone()), + &self.sys(), global_path, cli_options.npmrc().get_all_known_registries_urls(), ))) @@ -410,12 +416,11 @@ impl CliFactory { .npm_resolver .get_or_try_init_async( async { - let fs = self.fs(); let cli_options = self.cli_options()?; create_cli_npm_resolver(if cli_options.use_byonm() { CliNpmResolverCreateOptions::Byonm( CliByonmNpmResolverCreateOptions { - sys: FsSysTraitsAdapter(fs.clone()), + sys: self.sys(), pkg_json_resolver: self.pkg_json_resolver().clone(), root_node_modules_dir: Some( match cli_options.node_modules_dir_path() { @@ -439,7 +444,7 @@ impl CliFactory { cli_options.workspace(), ), ), - sys: FsSysTraitsAdapter(self.fs().clone()), + sys: self.sys(), snapshot: match cli_options.resolve_npm_resolution_snapshot()? { Some(snapshot) => { CliNpmResolverManagedSnapshotOption::Specified(Some( @@ -486,7 +491,7 @@ impl CliFactory { .get_or_try_init(|| { Ok(self.cli_options()?.unstable_sloppy_imports().then(|| { Arc::new(CliSloppyImportsResolver::new(SloppyImportsCachedFs::new( - FsSysTraitsAdapter(self.fs().clone()), + self.sys(), ))) })) }) @@ -647,13 +652,13 @@ impl CliFactory { )) } - pub async fn node_resolver(&self) -> Result<&Arc, AnyError> { + pub async fn node_resolver(&self) -> Result<&Arc, AnyError> { self .services .node_resolver .get_or_try_init_async( async { - Ok(Arc::new(NodeResolver::new( + Ok(Arc::new(CliNodeResolver::new( self.in_npm_pkg_checker()?.clone(), RealIsBuiltInNodeModuleChecker, self @@ -662,7 +667,7 @@ impl CliFactory { .clone() .into_npm_pkg_folder_resolver(), self.pkg_json_resolver().clone(), - FsSysTraitsAdapter(self.fs().clone()), + self.sys(), ))) } .boxed_local(), @@ -698,7 +703,7 @@ impl CliFactory { .clone() .into_npm_pkg_folder_resolver(), self.pkg_json_resolver().clone(), - FsSysTraitsAdapter(self.fs().clone()), + self.sys(), ))) }) .await @@ -714,7 +719,7 @@ impl CliFactory { let npm_resolver = self.npm_resolver().await?; Ok(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions { byonm_resolver: (npm_resolver.clone()).into_maybe_byonm(), - sys: FsSysTraitsAdapter(self.fs().clone()), + sys: self.sys(), in_npm_pkg_checker: self.in_npm_pkg_checker()?.clone(), node_resolver: self.node_resolver().await?.clone(), npm_req_resolver: npm_resolver.clone().into_npm_req_resolver(), @@ -723,12 +728,11 @@ impl CliFactory { .await } - pub fn pkg_json_resolver(&self) -> &Arc { - self.services.pkg_json_resolver.get_or_init(|| { - Arc::new(PackageJsonResolver::new(FsSysTraitsAdapter( - self.fs().clone(), - ))) - }) + pub fn pkg_json_resolver(&self) -> &Arc { + self + .services + .pkg_json_resolver + .get_or_init(|| Arc::new(CliPackageJsonResolver::new(self.sys()))) } pub async fn type_checker(&self) -> Result<&Arc, AnyError> { @@ -774,7 +778,7 @@ impl CliFactory { self.parsed_source_cache().clone(), self.resolver().await?.clone(), self.root_permissions_container()?.clone(), - FsSysTraitsAdapter(self.fs().clone()), + self.sys(), ))) }) .await @@ -864,10 +868,9 @@ impl CliFactory { pub fn permission_desc_parser( &self, - ) -> Result<&Arc, AnyError> { + ) -> Result<&Arc>, AnyError> { self.services.permission_desc_parser.get_or_try_init(|| { - let fs = self.fs().clone(); - Ok(Arc::new(RuntimePermissionDescriptorParser::new(fs))) + Ok(Arc::new(RuntimePermissionDescriptorParser::new(self.sys()))) }) } @@ -974,7 +977,7 @@ impl CliFactory { ), self.parsed_source_cache().clone(), self.resolver().await?.clone(), - FsSysTraitsAdapter(self.fs().clone()), + self.sys(), )), node_resolver.clone(), npm_resolver.clone(), @@ -982,6 +985,7 @@ impl CliFactory { self.root_cert_store_provider().clone(), self.root_permissions_container()?.clone(), StorageKeyResolver::from_options(cli_options), + self.sys(), cli_options.sub_command().clone(), self.create_cli_main_worker_options()?, self.cli_options()?.otel_config(), diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index 38f3dd1847..7e8438d639 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -24,7 +24,6 @@ use deno_core::url::Url; use deno_core::ModuleSpecifier; use deno_error::JsError; use deno_graph::source::LoaderChecksum; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_permissions::CheckSpecifierKind; use deno_runtime::deno_permissions::PermissionCheckError; use deno_runtime::deno_permissions::PermissionsContainer; @@ -38,6 +37,7 @@ use crate::cache::HttpCache; use crate::colors; use crate::http_util::get_response_body_with_progress; use crate::http_util::HttpClientProvider; +use crate::sys::CliSys; use crate::util::progress_bar::ProgressBar; #[derive(Debug, Clone, Eq, PartialEq)] @@ -267,7 +267,7 @@ pub struct FetchNoFollowOptions<'a> { type DenoCacheDirFileFetcher = deno_cache_dir::file_fetcher::FileFetcher< BlobStoreAdapter, - FsSysTraitsAdapter, + CliSys, HttpClientAdapter, >; @@ -279,9 +279,11 @@ pub struct CliFileFetcher { } impl CliFileFetcher { + #[allow(clippy::too_many_arguments)] pub fn new( http_cache: Arc, http_client_provider: Arc, + sys: CliSys, blob_store: Arc, progress_bar: Option, allow_remote: bool, @@ -289,7 +291,6 @@ impl CliFileFetcher { download_log_level: log::Level, ) -> Self { let memory_files = Arc::new(MemoryFiles::default()); - let sys = FsSysTraitsAdapter::new_real(); let auth_tokens = AuthTokens::new_from_sys(&sys); let file_fetcher = DenoCacheDirFileFetcher::new( BlobStoreAdapter(blob_store), @@ -538,13 +539,11 @@ mod tests { let temp_dir = maybe_temp_dir.unwrap_or_default(); let location = temp_dir.path().join("remote").to_path_buf(); let blob_store: Arc = Default::default(); - let cache = Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location, - )); + let cache = Arc::new(GlobalHttpCache::new(CliSys::default(), location)); let file_fetcher = CliFileFetcher::new( cache.clone(), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), blob_store.clone(), None, true, @@ -754,11 +753,9 @@ mod tests { // invocation and indicates to "cache bust". let location = temp_dir.path().join("remote").to_path_buf(); let file_fetcher = CliFileFetcher::new( - Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location, - )), + Arc::new(GlobalHttpCache::new(CliSys::default(), location)), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), Default::default(), None, true, @@ -783,14 +780,13 @@ mod tests { let specifier = resolve_url("http://localhost:4545/subdir/mismatch_ext.ts").unwrap(); - let http_cache = Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location.clone(), - )); + let http_cache = + Arc::new(GlobalHttpCache::new(CliSys::default(), location.clone())); let file_modified_01 = { let file_fetcher = CliFileFetcher::new( http_cache.clone(), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), Default::default(), None, true, @@ -810,11 +806,9 @@ mod tests { let file_modified_02 = { let file_fetcher = CliFileFetcher::new( - Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location, - )), + Arc::new(GlobalHttpCache::new(CliSys::default(), location)), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), Default::default(), None, true, @@ -940,15 +934,14 @@ mod tests { resolve_url("http://localhost:4548/subdir/mismatch_ext.ts").unwrap(); let redirected_specifier = resolve_url("http://localhost:4546/subdir/mismatch_ext.ts").unwrap(); - let http_cache = Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location.clone(), - )); + let http_cache = + Arc::new(GlobalHttpCache::new(CliSys::default(), location.clone())); let metadata_file_modified_01 = { let file_fetcher = CliFileFetcher::new( http_cache.clone(), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), Default::default(), None, true, @@ -971,6 +964,7 @@ mod tests { let file_fetcher = CliFileFetcher::new( http_cache.clone(), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), Default::default(), None, true, @@ -1075,11 +1069,9 @@ mod tests { let temp_dir = TempDir::new(); let location = temp_dir.path().join("remote").to_path_buf(); let file_fetcher = CliFileFetcher::new( - Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location, - )), + Arc::new(GlobalHttpCache::new(CliSys::default(), location)), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), Default::default(), None, false, @@ -1113,11 +1105,9 @@ mod tests { let temp_dir = TempDir::new(); let location = temp_dir.path().join("remote").to_path_buf(); let file_fetcher_01 = CliFileFetcher::new( - Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location.clone(), - )), + Arc::new(GlobalHttpCache::new(CliSys::default(), location.clone())), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), Default::default(), None, true, @@ -1125,11 +1115,9 @@ mod tests { log::Level::Info, ); let file_fetcher_02 = CliFileFetcher::new( - Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location, - )), + Arc::new(GlobalHttpCache::new(CliSys::default(), location)), Arc::new(HttpClientProvider::new(None, None)), + CliSys::default(), Default::default(), None, true, diff --git a/cli/graph_util.rs b/cli/graph_util.rs index a21d055adc..68d48d9bbc 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -29,7 +29,6 @@ use deno_graph::SpecifierError; use deno_graph::WorkspaceFastCheckOption; use deno_path_util::url_to_file_path; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node; use deno_runtime::deno_permissions::PermissionsContainer; use deno_semver::jsr::JsrDepPackageReq; @@ -57,6 +56,7 @@ use crate::resolver::CjsTracker; use crate::resolver::CliResolver; use crate::resolver::CliSloppyImportsResolver; use crate::resolver::SloppyImportsCachedFs; +use crate::sys::CliSys; use crate::tools::check; use crate::tools::check::TypeChecker; use crate::util::file_watcher::WatcherCommunicator; @@ -81,7 +81,7 @@ pub struct GraphValidOptions { /// for the CLI. pub fn graph_valid( graph: &ModuleGraph, - sys: &FsSysTraitsAdapter, + sys: &CliSys, roots: &[ModuleSpecifier], options: GraphValidOptions, ) -> Result<(), AnyError> { @@ -141,7 +141,7 @@ pub struct GraphWalkErrorsOptions { /// and enhances them with CLI information. pub fn graph_walk_errors<'a>( graph: &'a ModuleGraph, - sys: &'a FsSysTraitsAdapter, + sys: &'a CliSys, roots: &'a [ModuleSpecifier], options: GraphWalkErrorsOptions, ) -> impl Iterator + 'a { @@ -443,7 +443,7 @@ pub struct ModuleGraphBuilder { parsed_source_cache: Arc, resolver: Arc, root_permissions_container: PermissionsContainer, - sys: FsSysTraitsAdapter, + sys: CliSys, } impl ModuleGraphBuilder { @@ -462,7 +462,7 @@ impl ModuleGraphBuilder { parsed_source_cache: Arc, resolver: Arc, root_permissions_container: PermissionsContainer, - sys: FsSysTraitsAdapter, + sys: CliSys, ) -> Self { Self { caches, @@ -836,7 +836,7 @@ pub fn enhanced_resolution_error_message(error: &ResolutionError) -> String { } fn enhanced_sloppy_imports_error_message( - sys: &FsSysTraitsAdapter, + sys: &CliSys, error: &ModuleError, ) -> Option { match error { diff --git a/cli/lsp/cache.rs b/cli/lsp/cache.rs index c6d1b39ef4..24a55d495c 100644 --- a/cli/lsp/cache.rs +++ b/cli/lsp/cache.rs @@ -7,11 +7,11 @@ use crate::cache::LocalLspHttpCache; use crate::lsp::config::Config; use crate::lsp::logging::lsp_log; use crate::lsp::logging::lsp_warn; +use crate::sys::CliSys; use deno_core::url::Url; use deno_core::ModuleSpecifier; use deno_path_util::url_to_file_path; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use std::collections::BTreeMap; use std::fs; use std::path::Path; @@ -92,12 +92,11 @@ impl LspCache { }) .ok() }); - let deno_dir = DenoDir::new(global_cache_path) + let sys = CliSys::default(); + let deno_dir = DenoDir::new(sys.clone(), global_cache_path) .expect("should be infallible with absolute custom root"); - let global = Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - deno_dir.remote_folder_path(), - )); + let global = + Arc::new(GlobalHttpCache::new(sys, deno_dir.remote_folder_path())); Self { deno_dir, global, diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index a43e774934..ff4c2978d5 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -36,7 +36,6 @@ use deno_lint::linter::LintConfig as DenoLintConfig; use deno_npm::npm_rc::ResolvedNpmRc; use deno_package_json::PackageJsonCache; use deno_path_util::url_to_file_path; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::PackageJson; use indexmap::IndexSet; use lsp_types::ClientCapabilities; @@ -65,6 +64,7 @@ use crate::file_fetcher::CliFileFetcher; use crate::lsp::logging::lsp_warn; use crate::resolver::CliSloppyImportsResolver; use crate::resolver::SloppyImportsCachedFs; +use crate::sys::CliSys; use crate::tools::lint::CliLinter; use crate::tools::lint::CliLinterOptions; use crate::tools::lint::LintRuleProvider; @@ -1227,7 +1227,7 @@ impl ConfigData { Ok(scope_dir_path) => { let paths = [scope_dir_path]; WorkspaceDirectory::discover( - &FsSysTraitsAdapter::new_real(), + &CliSys::default(), match specified_config { Some(config_path) => { deno_config::workspace::WorkspaceDiscoverStart::ConfigFile( @@ -1615,9 +1615,7 @@ impl ConfigData { || unstable.contains("sloppy-imports"); let sloppy_imports_resolver = unstable_sloppy_imports.then(|| { Arc::new(CliSloppyImportsResolver::new( - SloppyImportsCachedFs::new_without_stat_cache( - FsSysTraitsAdapter::new_real(), - ), + SloppyImportsCachedFs::new_without_stat_cache(CliSys::default()), )) }); let resolver = Arc::new(resolver); @@ -1921,17 +1919,20 @@ impl ConfigTree { #[cfg(test)] pub async fn inject_config_file(&mut self, config_file: ConfigFile) { + use sys_traits::FsCreateDirAll; + use sys_traits::FsWrite; + let scope = config_file.specifier.join(".").unwrap(); let json_text = serde_json::to_string(&config_file.json).unwrap(); - let test_fs = Arc::new(deno_runtime::deno_fs::InMemoryFs::default()); + let memory_sys = sys_traits::impls::InMemorySys::default(); let config_path = url_to_file_path(&config_file.specifier).unwrap(); - test_fs.setup_text_files(vec![( - config_path.to_string_lossy().to_string(), - json_text, - )]); + memory_sys + .fs_create_dir_all(config_path.parent().unwrap()) + .unwrap(); + memory_sys.fs_write(&config_path, json_text).unwrap(); let workspace_dir = Arc::new( WorkspaceDirectory::discover( - &FsSysTraitsAdapter(test_fs.clone()), + &memory_sys, deno_config::workspace::WorkspaceDiscoverStart::ConfigFile( &config_path, ), @@ -2008,11 +2009,14 @@ fn resolve_lockfile_from_path( lockfile_path: PathBuf, frozen: bool, ) -> Option { - match CliLockfile::read_from_path(CliLockfileReadFromPathOptions { - file_path: lockfile_path, - frozen, - skip_write: false, - }) { + match CliLockfile::read_from_path( + &CliSys::default(), + CliLockfileReadFromPathOptions { + file_path: lockfile_path, + frozen, + skip_write: false, + }, + ) { Ok(value) => { if value.filename.exists() { if let Ok(specifier) = ModuleSpecifier::from_file_path(&value.filename) diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index 33fd4897c4..af6fdf53a4 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -21,6 +21,7 @@ use crate::graph_util::enhanced_resolution_error_message; use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams; use crate::resolver::CliSloppyImportsResolver; use crate::resolver::SloppyImportsCachedFs; +use crate::sys::CliSys; use crate::tools::lint::CliLinter; use crate::tools::lint::CliLinterOptions; use crate::tools::lint::LintRuleProvider; @@ -48,7 +49,6 @@ use deno_graph::SpecifierError; use deno_lint::linter::LintConfig as DenoLintConfig; use deno_resolver::sloppy_imports::SloppyImportsResolution; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node; use deno_runtime::tokio_util::create_basic_runtime; use deno_semver::jsr::JsrPackageReqReference; @@ -1281,7 +1281,7 @@ impl DenoDiagnostic { Self::NotInstalledNpm(pkg_req, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("npm package \"{pkg_req}\" is not installed or doesn't exist."), Some(json!({ "specifier": specifier }))), Self::NoLocal(specifier) => { let maybe_sloppy_resolution = CliSloppyImportsResolver::new( - SloppyImportsCachedFs::new(FsSysTraitsAdapter::new_real()) + SloppyImportsCachedFs::new(CliSys::default()) ).resolve(specifier, SloppyImportsResolutionKind::Execution); let data = maybe_sloppy_resolution.as_ref().map(|res| { json!({ diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 1cc26aff58..9ab1d9786c 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -17,7 +17,6 @@ use deno_core::ModuleSpecifier; use deno_graph::GraphKind; use deno_graph::Resolution; use deno_path_util::url_to_file_path; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_tls::RootCertStoreProvider; use deno_semver::jsr::JsrPackageReqReference; @@ -109,6 +108,7 @@ use crate::lsp::config::ConfigWatchedFileType; use crate::lsp::logging::init_log_file; use crate::lsp::tsc::file_text_changes_to_workspace_edit; use crate::lsp::urls::LspUrlKind; +use crate::sys::CliSys; use crate::tools::fmt::format_file; use crate::tools::fmt::format_parsed_source; use crate::tools::upgrade::check_for_upgrades_for_lsp; @@ -280,7 +280,7 @@ impl LanguageServer { .await?; graph_util::graph_valid( &graph, - &FsSysTraitsAdapter(factory.fs().clone()), + &CliSys::default(), &roots, graph_util::GraphValidOptions { kind: GraphKind::All, @@ -962,6 +962,7 @@ impl Inner { let file_fetcher = CliFileFetcher::new( self.cache.global().clone(), self.http_client_provider.clone(), + CliSys::default(), Default::default(), None, true, @@ -3613,7 +3614,7 @@ impl Inner { let workspace = match config_data { Some(d) => d.member_dir.clone(), None => Arc::new(WorkspaceDirectory::discover( - &FsSysTraitsAdapter::new_real(), + &CliSys::default(), deno_config::workspace::WorkspaceDiscoverStart::Paths(&[ initial_cwd.clone() ]), @@ -3634,6 +3635,7 @@ impl Inner { )?), }; let cli_options = CliOptions::new( + &CliSys::default(), Arc::new(Flags { internal: InternalFlags { cache_path: Some(self.cache.deno_dir().root.clone()), diff --git a/cli/lsp/registries.rs b/cli/lsp/registries.rs index 488e333e9d..c8dd7fa1a7 100644 --- a/cli/lsp/registries.rs +++ b/cli/lsp/registries.rs @@ -19,6 +19,7 @@ use crate::file_fetcher::FetchOptions; use crate::file_fetcher::FetchPermissionsOptionRef; use crate::file_fetcher::TextDecodedFile; use crate::http_util::HttpClientProvider; +use crate::sys::CliSys; use deno_cache_dir::file_fetcher::CacheSetting; use deno_core::anyhow::anyhow; @@ -32,7 +33,6 @@ use deno_core::url::Position; use deno_core::url::Url; use deno_core::ModuleSpecifier; use deno_graph::Dependency; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use log::error; use once_cell::sync::Lazy; use std::borrow::Cow; @@ -430,13 +430,12 @@ impl ModuleRegistry { http_client_provider: Arc, ) -> Self { // the http cache should always be the global one for registry completions - let http_cache = Arc::new(GlobalHttpCache::new( - FsSysTraitsAdapter::new_real(), - location.clone(), - )); + let http_cache = + Arc::new(GlobalHttpCache::new(CliSys::default(), location.clone())); let file_fetcher = CliFileFetcher::new( http_cache.clone(), http_client_provider, + CliSys::default(), Default::default(), None, true, diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs index addecc9a61..2dec5266f4 100644 --- a/cli/lsp/resolver.rs +++ b/cli/lsp/resolver.rs @@ -19,9 +19,6 @@ use deno_resolver::cjs::IsCjsResolutionMode; use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::DenoResolverOptions; use deno_resolver::NodeAndNpmReqResolver; -use deno_runtime::deno_fs::FsSysTraitsAdapter; -use deno_runtime::deno_node::NodeResolver; -use deno_runtime::deno_node::PackageJsonResolver; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; use deno_semver::jsr::JsrPackageReqReference; use deno_semver::npm::NpmPackageReqReference; @@ -51,6 +48,8 @@ use crate::http_util::HttpClientProvider; use crate::lsp::config::Config; use crate::lsp::config::ConfigData; use crate::lsp::logging::lsp_warn; +use crate::node::CliNodeResolver; +use crate::node::CliPackageJsonResolver; use crate::npm::create_cli_npm_resolver_for_lsp; use crate::npm::CliByonmNpmResolverCreateOptions; use crate::npm::CliManagedInNpmPkgCheckerCreateOptions; @@ -66,6 +65,7 @@ use crate::resolver::CliResolver; use crate::resolver::CliResolverOptions; use crate::resolver::IsCjsResolver; use crate::resolver::WorkerCliNpmGraphResolver; +use crate::sys::CliSys; use crate::tsc::into_specifier_and_media_type; use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBarStyle; @@ -77,9 +77,9 @@ struct LspScopeResolver { is_cjs_resolver: Arc, jsr_resolver: Option>, npm_resolver: Option>, - node_resolver: Option>, + node_resolver: Option>, npm_pkg_req_resolver: Option>, - pkg_json_resolver: Arc, + pkg_json_resolver: Arc, redirect_resolver: Option>, graph_imports: Arc>, dep_info: Arc>>, @@ -383,7 +383,7 @@ impl LspResolver { pub fn pkg_json_resolver( &self, referrer: &ModuleSpecifier, - ) -> &Arc { + ) -> &Arc { let resolver = self.get_scope_resolver(Some(referrer)); &resolver.pkg_json_resolver } @@ -591,22 +591,22 @@ struct ResolverFactoryServices { cli_resolver: Deferred>, in_npm_pkg_checker: Deferred>, is_cjs_resolver: Deferred>, - node_resolver: Deferred>>, + node_resolver: Deferred>>, npm_pkg_req_resolver: Deferred>>, npm_resolver: Option>, } struct ResolverFactory<'a> { config_data: Option<&'a Arc>, - pkg_json_resolver: Arc, - sys: FsSysTraitsAdapter, + pkg_json_resolver: Arc, + sys: CliSys, services: ResolverFactoryServices, } impl<'a> ResolverFactory<'a> { pub fn new(config_data: Option<&'a Arc>) -> Self { - let sys = FsSysTraitsAdapter::new_real(); - let pkg_json_resolver = Arc::new(PackageJsonResolver::new(sys.clone())); + let sys = CliSys::default(); + let pkg_json_resolver = Arc::new(CliPackageJsonResolver::new(sys.clone())); Self { config_data, pkg_json_resolver, @@ -621,7 +621,7 @@ impl<'a> ResolverFactory<'a> { cache: &LspCache, ) { let enable_byonm = self.config_data.map(|d| d.byonm).unwrap_or(false); - let sys = FsSysTraitsAdapter::new_real(); + let sys = CliSys::default(); let options = if enable_byonm { CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions { sys, @@ -656,7 +656,7 @@ impl<'a> ResolverFactory<'a> { } None => CliNpmResolverManagedSnapshotOption::Specified(None), }, - sys: FsSysTraitsAdapter::new_real(), + sys: CliSys::default(), npm_cache_dir, // Use an "only" cache setting in order to make the // user do an explicit "cache" command and prevent @@ -729,7 +729,7 @@ impl<'a> ResolverFactory<'a> { }) } - pub fn pkg_json_resolver(&self) -> &Arc { + pub fn pkg_json_resolver(&self) -> &Arc { &self.pkg_json_resolver } @@ -770,13 +770,13 @@ impl<'a> ResolverFactory<'a> { }) } - pub fn node_resolver(&self) -> Option<&Arc> { + pub fn node_resolver(&self) -> Option<&Arc> { self .services .node_resolver .get_or_init(|| { let npm_resolver = self.services.npm_resolver.as_ref()?; - Some(Arc::new(NodeResolver::new( + Some(Arc::new(CliNodeResolver::new( self.in_npm_pkg_checker().clone(), RealIsBuiltInNodeModuleChecker, npm_resolver.clone().into_npm_pkg_folder_resolver(), diff --git a/cli/main.rs b/cli/main.rs index d68f27146b..c3c7286e71 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -20,6 +20,7 @@ mod ops; mod resolver; mod shared; mod standalone; +mod sys; mod task_runner; mod tools; mod tsc; diff --git a/cli/mainrt.rs b/cli/mainrt.rs index cba54b044c..2b767ea89c 100644 --- a/cli/mainrt.rs +++ b/cli/mainrt.rs @@ -18,6 +18,7 @@ mod node; mod npm; mod resolver; mod shared; +mod sys; mod task_runner; mod util; mod version; @@ -31,11 +32,13 @@ use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics; pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS; use deno_terminal::colors; use indexmap::IndexMap; +use standalone::DenoCompileFileSystem; use std::borrow::Cow; use std::collections::HashMap; use std::env; use std::env::current_exe; +use std::sync::Arc; use crate::args::Flags; @@ -92,7 +95,9 @@ fn main() { Some(data.metadata.otel_config.clone()), ); load_env_vars(&data.metadata.env_vars_from_env_file); - let exit_code = standalone::run(data).await?; + let fs = DenoCompileFileSystem::new(data.vfs.clone()); + let sys = crate::sys::CliSys::DenoCompile(fs.clone()); + let exit_code = standalone::run(Arc::new(fs), sys, data).await?; deno_runtime::exit(exit_code); } Ok(None) => Ok(()), diff --git a/cli/module_loader.rs b/cli/module_loader.rs index 3e81dbc881..ea40dbe609 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -11,6 +11,8 @@ use std::sync::atomic::AtomicU16; use std::sync::atomic::Ordering; use std::sync::Arc; +use crate::node::CliNodeResolver; +use crate::sys::CliSys; use deno_ast::MediaType; use deno_ast::ModuleKind; use deno_core::anyhow::anyhow; @@ -39,10 +41,8 @@ use deno_graph::ModuleGraph; use deno_graph::Resolution; use deno_graph::WasmModule; use deno_runtime::code_cache; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::create_host_defined_options; use deno_runtime::deno_node::NodeRequireLoader; -use deno_runtime::deno_node::NodeResolver; use deno_runtime::deno_permissions::PermissionsContainer; use deno_semver::npm::NpmPackageReqReference; use node_resolver::errors::ClosestPkgJsonError; @@ -220,13 +220,13 @@ struct SharedCliModuleLoaderState { main_module_graph_container: Arc, module_load_preparer: Arc, node_code_translator: Arc, - node_resolver: Arc, + node_resolver: Arc, npm_req_resolver: Arc, npm_resolver: Arc, npm_module_loader: NpmModuleLoader, parsed_source_cache: Arc, resolver: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, in_flight_loads_tracker: InFlightModuleLoadsTracker, } @@ -280,13 +280,13 @@ impl CliModuleLoaderFactory { main_module_graph_container: Arc, module_load_preparer: Arc, node_code_translator: Arc, - node_resolver: Arc, + node_resolver: Arc, npm_req_resolver: Arc, npm_resolver: Arc, npm_module_loader: NpmModuleLoader, parsed_source_cache: Arc, resolver: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, ) -> Self { Self { shared: Arc::new(SharedCliModuleLoaderState { @@ -1092,7 +1092,7 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit { struct CliNodeRequireLoader { cjs_tracker: Arc, emitter: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, graph_container: TGraphContainer, in_npm_pkg_checker: Arc, npm_resolver: Arc, diff --git a/cli/node.rs b/cli/node.rs index 480da506c8..4a87d26ee0 100644 --- a/cli/node.rs +++ b/cli/node.rs @@ -8,7 +8,6 @@ use deno_ast::ModuleSpecifier; use deno_core::error::AnyError; use deno_graph::ParsedSourceStore; use deno_runtime::deno_fs; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis; use node_resolver::analyze::CjsAnalysisExports; @@ -21,12 +20,15 @@ use crate::cache::CacheDBHash; use crate::cache::NodeAnalysisCache; use crate::cache::ParsedSourceCache; use crate::resolver::CjsTracker; +use crate::sys::CliSys; pub type CliNodeCodeTranslator = NodeCodeTranslator< CliCjsCodeAnalyzer, RealIsBuiltInNodeModuleChecker, - FsSysTraitsAdapter, + CliSys, >; +pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver; +pub type CliPackageJsonResolver = node_resolver::PackageJsonResolver; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum CliCjsAnalysis { diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index 218f33989d..ca89a7399e 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -4,12 +4,12 @@ use std::borrow::Cow; use std::path::Path; use std::sync::Arc; +use crate::sys::CliSys; use deno_core::error::AnyError; use deno_core::serde_json; use deno_resolver::npm::ByonmNpmResolver; use deno_resolver::npm::ByonmNpmResolverCreateOptions; use deno_resolver::npm::CliNpmReqResolver; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::NodePermissions; use deno_runtime::ops::process::NpmProcessStateProvider; use node_resolver::NpmPackageFolderResolver; @@ -21,8 +21,8 @@ use super::CliNpmResolver; use super::InnerCliNpmResolverRef; pub type CliByonmNpmResolverCreateOptions = - ByonmNpmResolverCreateOptions; -pub type CliByonmNpmResolver = ByonmNpmResolver; + ByonmNpmResolverCreateOptions; +pub type CliByonmNpmResolver = ByonmNpmResolver; // todo(dsherret): the services hanging off `CliNpmResolver` doesn't seem ideal. We should probably decouple. #[derive(Debug)] diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs index 5b0a304de8..97a87dd9b8 100644 --- a/cli/npm/managed/mod.rs +++ b/cli/npm/managed/mod.rs @@ -5,6 +5,7 @@ use std::path::Path; use std::path::PathBuf; use std::sync::Arc; +use crate::sys::CliSys; use deno_ast::ModuleSpecifier; use deno_cache_dir::npm::NpmCacheDir; use deno_core::anyhow::Context; @@ -24,7 +25,6 @@ use deno_npm_cache::NpmCacheSetting; use deno_path_util::fs::canonicalize_path_maybe_not_exists; use deno_resolver::npm::CliNpmReqResolver; use deno_runtime::colors; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::NodePermissions; use deno_runtime::ops::process::NpmProcessStateProvider; use deno_semver::package::PackageNv; @@ -70,7 +70,7 @@ pub struct CliManagedNpmResolverCreateOptions { pub maybe_lockfile: Option>, pub http_client_provider: Arc, pub npm_cache_dir: Arc, - pub sys: FsSysTraitsAdapter, + pub sys: CliSys, pub cache_setting: deno_cache_dir::file_fetcher::CacheSetting, pub text_only_progress_bar: crate::util::progress_bar::ProgressBar, pub maybe_node_modules_path: Option, @@ -149,7 +149,7 @@ fn create_inner( npm_cache: Arc, npm_install_deps_provider: Arc, registry_info_provider: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, text_only_progress_bar: crate::util::progress_bar::ProgressBar, maybe_lockfile: Option>, npm_rc: Arc, @@ -307,7 +307,7 @@ pub struct ManagedCliNpmResolver { registry_info_provider: Arc, npm_cache: Arc, npm_install_deps_provider: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, resolution: Arc, tarball_cache: Arc, text_only_progress_bar: ProgressBar, @@ -333,7 +333,7 @@ impl ManagedCliNpmResolver { npm_cache: Arc, npm_install_deps_provider: Arc, resolution: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, tarball_cache: Arc, text_only_progress_bar: ProgressBar, npm_system_info: NpmSystemInfo, diff --git a/cli/npm/managed/resolvers/common.rs b/cli/npm/managed/resolvers/common.rs index 83081d3b8e..26f6d8516d 100644 --- a/cli/npm/managed/resolvers/common.rs +++ b/cli/npm/managed/resolvers/common.rs @@ -20,13 +20,13 @@ use deno_core::futures::StreamExt; use deno_npm::NpmPackageCacheFolderId; use deno_npm::NpmPackageId; use deno_npm::NpmResolutionPackage; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::NodePermissions; use node_resolver::errors::PackageFolderResolveError; use sys_traits::FsCanonicalize; use super::super::PackageCaching; use crate::npm::CliNpmTarballCache; +use crate::sys::CliSys; /// Part of the resolution that interacts with the file system. #[async_trait(?Send)] @@ -74,15 +74,15 @@ pub trait NpmPackageFsResolver: Send + Sync { #[derive(Debug)] pub struct RegistryReadPermissionChecker { - sys: FsSysTraitsAdapter, + sys: CliSys, cache: Mutex>, registry_path: PathBuf, } impl RegistryReadPermissionChecker { - pub fn new(fs: FsSysTraitsAdapter, registry_path: PathBuf) -> Self { + pub fn new(sys: CliSys, registry_path: PathBuf) -> Self { Self { - sys: fs, + sys, registry_path, cache: Default::default(), } diff --git a/cli/npm/managed/resolvers/global.rs b/cli/npm/managed/resolvers/global.rs index f56f012407..77e0d0ea3e 100644 --- a/cli/npm/managed/resolvers/global.rs +++ b/cli/npm/managed/resolvers/global.rs @@ -11,6 +11,7 @@ use crate::colors; use crate::npm::managed::PackageCaching; use crate::npm::CliNpmCache; use crate::npm::CliNpmTarballCache; +use crate::sys::CliSys; use async_trait::async_trait; use deno_ast::ModuleSpecifier; use deno_core::error::AnyError; @@ -18,7 +19,6 @@ use deno_npm::NpmPackageCacheFolderId; use deno_npm::NpmPackageId; use deno_npm::NpmResolutionPackage; use deno_npm::NpmSystemInfo; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::NodePermissions; use node_resolver::errors::PackageFolderResolveError; use node_resolver::errors::PackageNotFoundError; @@ -49,7 +49,7 @@ impl GlobalNpmPackageResolver { cache: Arc, tarball_cache: Arc, resolution: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, system_info: NpmSystemInfo, lifecycle_scripts: LifecycleScriptsConfig, ) -> Self { diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs index 8bbaf6c51c..5c93c228e8 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/managed/resolvers/local.rs @@ -32,7 +32,6 @@ use deno_npm::NpmSystemInfo; use deno_path_util::fs::atomic_write_file_with_retries; use deno_path_util::fs::canonicalize_path_maybe_not_exists; use deno_resolver::npm::normalize_pkg_name_for_node_modules_deno_folder; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::NodePermissions; use deno_semver::package::PackageNv; use deno_semver::StackString; @@ -51,6 +50,7 @@ use crate::colors; use crate::npm::managed::PackageCaching; use crate::npm::CliNpmCache; use crate::npm::CliNpmTarballCache; +use crate::sys::CliSys; use crate::util::fs::clone_dir_recursive; use crate::util::fs::symlink_dir; use crate::util::fs::LaxSingleProcessFsFlag; @@ -70,7 +70,7 @@ pub struct LocalNpmPackageResolver { npm_install_deps_provider: Arc, progress_bar: ProgressBar, resolution: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, tarball_cache: Arc, root_node_modules_path: PathBuf, root_node_modules_url: Url, @@ -86,7 +86,7 @@ impl LocalNpmPackageResolver { npm_install_deps_provider: Arc, progress_bar: ProgressBar, resolution: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, tarball_cache: Arc, node_modules_folder: PathBuf, system_info: NpmSystemInfo, @@ -926,7 +926,7 @@ impl SetupCache { bincode::serialize(&self.current).ok().and_then(|data| { atomic_write_file_with_retries( - &FsSysTraitsAdapter::new_real(), + &CliSys::default(), &self.file_path, &data, CACHE_PERM, diff --git a/cli/npm/managed/resolvers/mod.rs b/cli/npm/managed/resolvers/mod.rs index 2d6d37798f..c2fc8d2d92 100644 --- a/cli/npm/managed/resolvers/mod.rs +++ b/cli/npm/managed/resolvers/mod.rs @@ -7,8 +7,8 @@ mod local; use std::path::PathBuf; use std::sync::Arc; +use crate::sys::CliSys; use deno_npm::NpmSystemInfo; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use crate::args::LifecycleScriptsConfig; use crate::args::NpmInstallDepsProvider; @@ -29,7 +29,7 @@ pub fn create_npm_fs_resolver( npm_install_deps_provider: &Arc, progress_bar: &ProgressBar, resolution: Arc, - sys: FsSysTraitsAdapter, + sys: CliSys, tarball_cache: Arc, maybe_node_modules_path: Option, system_info: NpmSystemInfo, diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index 6f686c3553..34eaf21419 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -7,6 +7,7 @@ use std::borrow::Cow; use std::path::Path; use std::sync::Arc; +use crate::sys::CliSys; use dashmap::DashMap; use deno_core::error::AnyError; use deno_core::serde_json; @@ -17,7 +18,6 @@ use deno_resolver::npm::ByonmInNpmPackageChecker; use deno_resolver::npm::ByonmNpmResolver; use deno_resolver::npm::CliNpmReqResolver; use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::NodePermissions; use deno_runtime::ops::process::NpmProcessStateProvider; use deno_semver::package::PackageNv; @@ -41,12 +41,10 @@ pub use self::managed::ManagedCliNpmResolver; pub use self::managed::PackageCaching; pub type CliNpmTarballCache = - deno_npm_cache::TarballCache; -pub type CliNpmCache = deno_npm_cache::NpmCache; -pub type CliNpmRegistryInfoProvider = deno_npm_cache::RegistryInfoProvider< - CliNpmCacheHttpClient, - FsSysTraitsAdapter, ->; + deno_npm_cache::TarballCache; +pub type CliNpmCache = deno_npm_cache::NpmCache; +pub type CliNpmRegistryInfoProvider = + deno_npm_cache::RegistryInfoProvider; #[derive(Debug)] pub struct CliNpmCacheHttpClient { diff --git a/cli/resolver.rs b/cli/resolver.rs index 0a4fd78686..c4c8ef8b36 100644 --- a/cli/resolver.rs +++ b/cli/resolver.rs @@ -5,6 +5,7 @@ use std::path::Path; use std::path::PathBuf; use std::sync::Arc; +use crate::sys::CliSys; use async_trait::async_trait; use dashmap::DashMap; use dashmap::DashSet; @@ -25,7 +26,6 @@ use deno_npm::resolution::NpmResolutionError; use deno_resolver::sloppy_imports::SloppyImportsResolver; use deno_runtime::colors; use deno_runtime::deno_fs; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use deno_runtime::deno_node::is_builtin_node_module; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; use deno_semver::package::PackageReq; @@ -43,19 +43,17 @@ use crate::npm::InnerCliNpmResolverRef; use crate::util::sync::AtomicFlag; use crate::util::text_encoding::from_utf8_lossy_cow; -pub type CjsTracker = deno_resolver::cjs::CjsTracker; -pub type IsCjsResolver = deno_resolver::cjs::IsCjsResolver; +pub type CjsTracker = deno_resolver::cjs::CjsTracker; +pub type IsCjsResolver = deno_resolver::cjs::IsCjsResolver; pub type CliSloppyImportsResolver = SloppyImportsResolver; pub type CliDenoResolver = deno_resolver::DenoResolver< RealIsBuiltInNodeModuleChecker, SloppyImportsCachedFs, - FsSysTraitsAdapter, ->; -pub type CliNpmReqResolver = deno_resolver::npm::NpmReqResolver< - RealIsBuiltInNodeModuleChecker, - FsSysTraitsAdapter, + CliSys, >; +pub type CliNpmReqResolver = + deno_resolver::npm::NpmReqResolver; pub struct ModuleCodeStringSource { pub code: ModuleSourceCode, @@ -397,7 +395,7 @@ impl<'a> deno_graph::source::NpmResolver for WorkerCliNpmGraphResolver<'a> { #[derive(Debug)] pub struct SloppyImportsCachedFs { - sys: FsSysTraitsAdapter, + sys: CliSys, cache: Option< DashMap< PathBuf, @@ -407,14 +405,14 @@ pub struct SloppyImportsCachedFs { } impl SloppyImportsCachedFs { - pub fn new(sys: FsSysTraitsAdapter) -> Self { + pub fn new(sys: CliSys) -> Self { Self { sys, cache: Some(Default::default()), } } - pub fn new_without_stat_cache(fs: FsSysTraitsAdapter) -> Self { + pub fn new_without_stat_cache(fs: CliSys) -> Self { Self { sys: fs, cache: None, diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs index 91187c48d1..48af787f18 100644 --- a/cli/standalone/binary.rs +++ b/cli/standalone/binary.rs @@ -259,7 +259,6 @@ pub fn is_standalone_binary(exe_path: &Path) -> bool { } pub struct StandaloneData { - pub fs: Arc, pub metadata: Metadata, pub modules: StandaloneModules, pub npm_snapshot: Option, @@ -382,10 +381,7 @@ pub fn extract_standalone( }; Arc::new(FileBackedVfs::new(Cow::Borrowed(vfs_files_data), fs_root)) }; - let fs: Arc = - Arc::new(DenoCompileFileSystem::new(vfs.clone())); Ok(Some(StandaloneData { - fs, metadata, modules: StandaloneModules { remote_modules, diff --git a/cli/standalone/code_cache.rs b/cli/standalone/code_cache.rs index a44c920328..ec89c3ab1b 100644 --- a/cli/standalone/code_cache.rs +++ b/cli/standalone/code_cache.rs @@ -18,7 +18,6 @@ use deno_core::unsync::sync::AtomicFlag; use deno_path_util::get_atomic_path; use deno_runtime::code_cache::CodeCache; use deno_runtime::code_cache::CodeCacheType; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use crate::cache::FastInsecureHasher; use crate::worker::CliCodeCache; @@ -191,7 +190,7 @@ impl FirstRunCodeCacheStrategy { ) { let count = cache_data.len(); let temp_file = - get_atomic_path(&FsSysTraitsAdapter::new_real(), &self.file_path); + get_atomic_path(&sys_traits::impls::RealSys, &self.file_path); match serialize(&temp_file, self.cache_key, cache_data) { Ok(()) => { if let Err(err) = std::fs::rename(&temp_file, &self.file_path) { diff --git a/cli/standalone/file_system.rs b/cli/standalone/file_system.rs index 4b1024db6a..0a11d4550f 100644 --- a/cli/standalone/file_system.rs +++ b/cli/standalone/file_system.rs @@ -1,23 +1,34 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::borrow::Cow; +use std::io::ErrorKind; use std::path::Path; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; +use std::time::Duration; +use std::time::SystemTime; use deno_runtime::deno_fs::AccessCheckCb; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_fs::FsDirEntry; use deno_runtime::deno_fs::FsFileType; -use deno_runtime::deno_fs::FsStatSlim; use deno_runtime::deno_fs::OpenOptions; use deno_runtime::deno_fs::RealFs; use deno_runtime::deno_io::fs::File; use deno_runtime::deno_io::fs::FsError; use deno_runtime::deno_io::fs::FsResult; use deno_runtime::deno_io::fs::FsStat; +use sys_traits::boxed::BoxedFsDirEntry; +use sys_traits::boxed::BoxedFsMetadataValue; +use sys_traits::boxed::FsMetadataBoxed; +use sys_traits::boxed::FsReadDirBoxed; +use sys_traits::FsMetadata; use super::virtual_fs::FileBackedVfs; +use super::virtual_fs::FileBackedVfsDirEntry; +use super::virtual_fs::FileBackedVfsFile; +use super::virtual_fs::FileBackedVfsMetadata; use super::virtual_fs::VfsFileSubDataKind; #[derive(Debug, Clone)] @@ -83,7 +94,7 @@ impl FileSystem for DenoCompileFileSystem { access_check: Option, ) -> FsResult> { if self.0.is_path_within(path) { - Ok(self.0.open_file(path)?) + Ok(Rc::new(self.0.open_file(path)?)) } else { RealFs.open_sync(path, options, access_check) } @@ -95,7 +106,7 @@ impl FileSystem for DenoCompileFileSystem { access_check: Option>, ) -> FsResult> { if self.0.is_path_within(&path) { - Ok(self.0.open_file(&path)?) + Ok(Rc::new(self.0.open_file(&path)?)) } else { RealFs.open_async(path, options, access_check).await } @@ -215,14 +226,14 @@ impl FileSystem for DenoCompileFileSystem { fn stat_sync(&self, path: &Path) -> FsResult { if self.0.is_path_within(path) { - Ok(self.0.stat(path)?) + Ok(self.0.stat(path)?.as_fs_stat()) } else { RealFs.stat_sync(path) } } async fn stat_async(&self, path: PathBuf) -> FsResult { if self.0.is_path_within(&path) { - Ok(self.0.stat(&path)?) + Ok(self.0.stat(&path)?.as_fs_stat()) } else { RealFs.stat_async(path).await } @@ -230,14 +241,14 @@ impl FileSystem for DenoCompileFileSystem { fn lstat_sync(&self, path: &Path) -> FsResult { if self.0.is_path_within(path) { - Ok(self.0.lstat(path)?) + Ok(self.0.lstat(path)?.as_fs_stat()) } else { RealFs.lstat_sync(path) } } async fn lstat_async(&self, path: PathBuf) -> FsResult { if self.0.is_path_within(&path) { - Ok(self.0.lstat(&path)?) + Ok(self.0.lstat(&path)?.as_fs_stat()) } else { RealFs.lstat_async(path).await } @@ -398,3 +409,428 @@ impl FileSystem for DenoCompileFileSystem { .await } } + +impl sys_traits::BaseFsHardLink for DenoCompileFileSystem { + #[inline] + fn base_fs_hard_link(&self, src: &Path, dst: &Path) -> std::io::Result<()> { + self.link_sync(src, dst).map_err(|err| err.into_io_error()) + } +} + +impl sys_traits::BaseFsRead for DenoCompileFileSystem { + #[inline] + fn base_fs_read(&self, path: &Path) -> std::io::Result> { + self + .read_file_sync(path, None) + .map_err(|err| err.into_io_error()) + } +} + +impl sys_traits::FsMetadataValue for FileBackedVfsMetadata { + fn file_type(&self) -> sys_traits::FileType { + self.file_type + } + + fn len(&self) -> u64 { + self.len + } + + fn accessed(&self) -> std::io::Result { + Err(not_supported("accessed time")) + } + + fn created(&self) -> std::io::Result { + Err(not_supported("created time")) + } + + fn changed(&self) -> std::io::Result { + Err(not_supported("changed time")) + } + + fn modified(&self) -> std::io::Result { + Err(not_supported("modified time")) + } + + fn dev(&self) -> std::io::Result { + Ok(0) + } + + fn ino(&self) -> std::io::Result { + Ok(0) + } + + fn mode(&self) -> std::io::Result { + Ok(0) + } + + fn nlink(&self) -> std::io::Result { + Ok(0) + } + + fn uid(&self) -> std::io::Result { + Ok(0) + } + + fn gid(&self) -> std::io::Result { + Ok(0) + } + + fn rdev(&self) -> std::io::Result { + Ok(0) + } + + fn blksize(&self) -> std::io::Result { + Ok(0) + } + + fn blocks(&self) -> std::io::Result { + Ok(0) + } + + fn is_block_device(&self) -> std::io::Result { + Ok(false) + } + + fn is_char_device(&self) -> std::io::Result { + Ok(false) + } + + fn is_fifo(&self) -> std::io::Result { + Ok(false) + } + + fn is_socket(&self) -> std::io::Result { + Ok(false) + } + + fn file_attributes(&self) -> std::io::Result { + Ok(0) + } +} + +fn not_supported(name: &str) -> std::io::Error { + std::io::Error::new( + ErrorKind::Unsupported, + format!( + "{} is not supported for an embedded deno compile file", + name + ), + ) +} + +impl sys_traits::FsDirEntry for FileBackedVfsDirEntry { + type Metadata = BoxedFsMetadataValue; + + fn file_name(&self) -> Cow { + Cow::Borrowed(self.metadata.name.as_ref()) + } + + fn file_type(&self) -> std::io::Result { + Ok(self.metadata.file_type) + } + + fn metadata(&self) -> std::io::Result { + Ok(BoxedFsMetadataValue(Box::new(self.metadata.clone()))) + } + + fn path(&self) -> Cow { + Cow::Owned(self.parent_path.join(&self.metadata.name)) + } +} + +impl sys_traits::BaseFsReadDir for DenoCompileFileSystem { + type ReadDirEntry = BoxedFsDirEntry; + + fn base_fs_read_dir( + &self, + path: &Path, + ) -> std::io::Result< + Box> + '_>, + > { + if self.0.is_path_within(path) { + let entries = self.0.read_dir_with_metadata(path)?; + Ok(Box::new( + entries.map(|entry| Ok(BoxedFsDirEntry::new(entry))), + )) + } else { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.fs_read_dir_boxed(path) + } + } +} + +impl sys_traits::BaseFsCanonicalize for DenoCompileFileSystem { + #[inline] + fn base_fs_canonicalize(&self, path: &Path) -> std::io::Result { + self.realpath_sync(path).map_err(|err| err.into_io_error()) + } +} + +impl sys_traits::BaseFsMetadata for DenoCompileFileSystem { + type Metadata = BoxedFsMetadataValue; + + #[inline] + fn base_fs_metadata(&self, path: &Path) -> std::io::Result { + if self.0.is_path_within(path) { + Ok(BoxedFsMetadataValue::new(self.0.stat(path)?)) + } else { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.fs_metadata_boxed(path) + } + } + + #[inline] + fn base_fs_symlink_metadata( + &self, + path: &Path, + ) -> std::io::Result { + if self.0.is_path_within(path) { + Ok(BoxedFsMetadataValue::new(self.0.lstat(path)?)) + } else { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.fs_symlink_metadata_boxed(path) + } + } +} + +impl sys_traits::BaseFsCreateDir for DenoCompileFileSystem { + #[inline] + fn base_fs_create_dir( + &self, + path: &Path, + options: &sys_traits::CreateDirOptions, + ) -> std::io::Result<()> { + self + .mkdir_sync(path, options.recursive, options.mode) + .map_err(|err| err.into_io_error()) + } +} + +impl sys_traits::BaseFsRemoveFile for DenoCompileFileSystem { + #[inline] + fn base_fs_remove_file(&self, path: &Path) -> std::io::Result<()> { + self + .remove_sync(path, false) + .map_err(|err| err.into_io_error()) + } +} + +impl sys_traits::BaseFsRename for DenoCompileFileSystem { + #[inline] + fn base_fs_rename(&self, from: &Path, to: &Path) -> std::io::Result<()> { + self + .rename_sync(from, to) + .map_err(|err| err.into_io_error()) + } +} + +pub enum FsFileAdapter { + Real(sys_traits::impls::RealFsFile), + Vfs(FileBackedVfsFile), +} + +impl sys_traits::FsFile for FsFileAdapter {} + +impl sys_traits::FsFileAsRaw for FsFileAdapter { + #[cfg(windows)] + fn fs_file_as_raw_handle(&self) -> Option { + match self { + Self::Real(file) => file.fs_file_as_raw_handle(), + Self::Vfs(_) => None, + } + } + + #[cfg(unix)] + fn fs_file_as_raw_fd(&self) -> Option { + match self { + Self::Real(file) => file.fs_file_as_raw_fd(), + Self::Vfs(_) => None, + } + } +} + +impl sys_traits::FsFileSyncData for FsFileAdapter { + fn fs_file_sync_data(&mut self) -> std::io::Result<()> { + match self { + Self::Real(file) => file.fs_file_sync_data(), + Self::Vfs(_) => Ok(()), + } + } +} + +impl sys_traits::FsFileSyncAll for FsFileAdapter { + fn fs_file_sync_all(&mut self) -> std::io::Result<()> { + match self { + Self::Real(file) => file.fs_file_sync_all(), + Self::Vfs(_) => Ok(()), + } + } +} + +impl sys_traits::FsFileSetPermissions for FsFileAdapter { + #[inline] + fn fs_file_set_permissions(&mut self, mode: u32) -> std::io::Result<()> { + match self { + Self::Real(file) => file.fs_file_set_permissions(mode), + Self::Vfs(_) => Ok(()), + } + } +} + +impl std::io::Read for FsFileAdapter { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + match self { + Self::Real(file) => file.read(buf), + Self::Vfs(file) => file.read_to_buf(buf), + } + } +} + +impl std::io::Seek for FsFileAdapter { + fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { + match self { + Self::Real(file) => file.seek(pos), + Self::Vfs(file) => file.seek(pos), + } + } +} + +impl std::io::Write for FsFileAdapter { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + match self { + Self::Real(file) => file.write(buf), + Self::Vfs(_) => Err(not_supported("writing files")), + } + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + match self { + Self::Real(file) => file.flush(), + Self::Vfs(_) => Err(not_supported("writing files")), + } + } +} + +impl sys_traits::FsFileSetLen for FsFileAdapter { + #[inline] + fn fs_file_set_len(&mut self, len: u64) -> std::io::Result<()> { + match self { + Self::Real(file) => file.fs_file_set_len(len), + Self::Vfs(_) => Err(not_supported("setting file length")), + } + } +} + +impl sys_traits::FsFileSetTimes for FsFileAdapter { + fn fs_file_set_times( + &mut self, + times: sys_traits::FsFileTimes, + ) -> std::io::Result<()> { + match self { + Self::Real(file) => file.fs_file_set_times(times), + Self::Vfs(_) => Err(not_supported("setting file times")), + } + } +} + +impl sys_traits::FsFileLock for FsFileAdapter { + fn fs_file_lock( + &mut self, + mode: sys_traits::FsFileLockMode, + ) -> std::io::Result<()> { + match self { + Self::Real(file) => file.fs_file_lock(mode), + Self::Vfs(_) => Err(not_supported("locking files")), + } + } + + fn fs_file_try_lock( + &mut self, + mode: sys_traits::FsFileLockMode, + ) -> std::io::Result<()> { + match self { + Self::Real(file) => file.fs_file_try_lock(mode), + Self::Vfs(_) => Err(not_supported("locking files")), + } + } + + fn fs_file_unlock(&mut self) -> std::io::Result<()> { + match self { + Self::Real(file) => file.fs_file_unlock(), + Self::Vfs(_) => Err(not_supported("unlocking files")), + } + } +} + +impl sys_traits::FsFileIsTerminal for FsFileAdapter { + #[inline] + fn fs_file_is_terminal(&self) -> bool { + match self { + Self::Real(file) => file.fs_file_is_terminal(), + Self::Vfs(_) => false, + } + } +} + +impl sys_traits::BaseFsOpen for DenoCompileFileSystem { + type File = FsFileAdapter; + + fn base_fs_open( + &self, + path: &Path, + options: &sys_traits::OpenOptions, + ) -> std::io::Result { + if self.0.is_path_within(path) { + Ok(FsFileAdapter::Vfs(self.0.open_file(path)?)) + } else { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + Ok(FsFileAdapter::Real( + sys_traits::impls::RealSys.base_fs_open(path, options)?, + )) + } + } +} + +impl sys_traits::SystemRandom for DenoCompileFileSystem { + #[inline] + fn sys_random(&self, buf: &mut [u8]) -> std::io::Result<()> { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.sys_random(buf) + } +} + +impl sys_traits::SystemTimeNow for DenoCompileFileSystem { + #[inline] + fn sys_time_now(&self) -> SystemTime { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.sys_time_now() + } +} + +impl sys_traits::ThreadSleep for DenoCompileFileSystem { + #[inline] + fn thread_sleep(&self, dur: Duration) { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.thread_sleep(dur) + } +} + +impl sys_traits::EnvCurrentDir for DenoCompileFileSystem { + fn env_current_dir(&self) -> std::io::Result { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.env_current_dir() + } +} + +impl sys_traits::BaseEnvVar for DenoCompileFileSystem { + fn base_env_var_os( + &self, + key: &std::ffi::OsStr, + ) -> Option { + #[allow(clippy::disallowed_types)] // ok because we're implementing the fs + sys_traits::impls::RealSys.base_env_var_os(key) + } +} diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index 0ce25ff62f..0fe6de0b9a 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -36,11 +36,10 @@ use deno_package_json::PackageJsonDepValue; use deno_resolver::cjs::IsCjsResolutionMode; use deno_resolver::npm::NpmReqResolverOptions; use deno_runtime::deno_fs; -use deno_runtime::deno_fs::FsSysTraitsAdapter; +use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node::create_host_defined_options; use deno_runtime::deno_node::NodeRequireLoader; use deno_runtime::deno_node::NodeResolver; -use deno_runtime::deno_node::PackageJsonResolver; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; use deno_runtime::deno_permissions::Permissions; use deno_runtime::deno_permissions::PermissionsContainer; @@ -77,6 +76,8 @@ use crate::cache::NodeAnalysisCache; use crate::http_util::HttpClientProvider; use crate::node::CliCjsCodeAnalyzer; use crate::node::CliNodeCodeTranslator; +use crate::node::CliNodeResolver; +use crate::node::CliPackageJsonResolver; use crate::npm::create_cli_npm_resolver; use crate::npm::create_in_npm_pkg_checker; use crate::npm::CliByonmNpmResolverCreateOptions; @@ -89,6 +90,7 @@ use crate::npm::CreateInNpmPkgCheckerOptions; use crate::resolver::CjsTracker; use crate::resolver::CliNpmReqResolver; use crate::resolver::NpmModuleLoader; +use crate::sys::CliSys; use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBarStyle; use crate::util::text_encoding::from_utf8_lossy_cow; @@ -105,12 +107,12 @@ mod file_system; mod serialization; mod virtual_fs; +pub use self::file_system::DenoCompileFileSystem; pub use binary::extract_standalone; pub use binary::is_standalone_binary; pub use binary::DenoCompileBinaryWriter; use self::binary::Metadata; -use self::file_system::DenoCompileFileSystem; struct SharedModuleLoaderState { cjs_tracker: Arc, @@ -118,7 +120,7 @@ struct SharedModuleLoaderState { fs: Arc, modules: StandaloneModules, node_code_translator: Arc, - node_resolver: Arc, + node_resolver: Arc, npm_module_loader: Arc, npm_req_resolver: Arc, npm_resolver: Arc, @@ -627,9 +629,12 @@ impl RootCertStoreProvider for StandaloneRootCertStoreProvider { } } -pub async fn run(data: StandaloneData) -> Result { +pub async fn run( + fs: Arc, + sys: CliSys, + data: StandaloneData, +) -> Result { let StandaloneData { - fs, metadata, modules, npm_snapshot, @@ -637,7 +642,7 @@ pub async fn run(data: StandaloneData) -> Result { source_maps, vfs, } = data; - let deno_dir_provider = Arc::new(DenoDirProvider::new(None)); + let deno_dir_provider = Arc::new(DenoDirProvider::new(sys.clone(), None)); let root_cert_store_provider = Arc::new(StandaloneRootCertStoreProvider { ca_stores: metadata.ca_stores, ca_data: metadata.ca_data.map(CaData::Bytes), @@ -655,8 +660,7 @@ pub async fn run(data: StandaloneData) -> Result { let main_module = root_dir_url.join(&metadata.entrypoint_key).unwrap(); let npm_global_cache_dir = root_path.join(".deno_compile_node_modules"); let cache_setting = CacheSetting::Only; - let sys = FsSysTraitsAdapter(fs.clone()); - let pkg_json_resolver = Arc::new(PackageJsonResolver::new(sys.clone())); + let pkg_json_resolver = Arc::new(CliPackageJsonResolver::new(sys.clone())); let (in_npm_pkg_checker, npm_resolver) = match metadata.node_modules { Some(binary::NodeModules::Managed { node_modules_dir }) => { // create an npmrc that uses the fake npm_registry_url to resolve packages @@ -807,7 +811,7 @@ pub async fn run(data: StandaloneData) -> Result { node_resolver.clone(), npm_resolver.clone().into_npm_pkg_folder_resolver(), pkg_json_resolver.clone(), - sys, + sys.clone(), )); let workspace_resolver = { let import_map = match metadata.workspace_resolver.import_map { @@ -910,7 +914,7 @@ pub async fn run(data: StandaloneData) -> Result { } let desc_parser = - Arc::new(RuntimePermissionDescriptorParser::new(fs.clone())); + Arc::new(RuntimePermissionDescriptorParser::new(sys.clone())); let permissions = Permissions::from_options(desc_parser.as_ref(), &permissions)?; PermissionsContainer::new(desc_parser, permissions) @@ -940,6 +944,7 @@ pub async fn run(data: StandaloneData) -> Result { root_cert_store_provider, permissions, StorageKeyResolver::empty(), + sys, crate::args::DenoSubcommand::Run(Default::default()), CliMainWorkerOptions { argv: metadata.argv, diff --git a/cli/standalone/virtual_fs.rs b/cli/standalone/virtual_fs.rs index 522fe47dd9..370d07a488 100644 --- a/cli/standalone/virtual_fs.rs +++ b/cli/standalone/virtual_fs.rs @@ -51,8 +51,16 @@ pub enum WindowsSystemRootablePath { impl WindowsSystemRootablePath { pub fn join(&self, name_component: &str) -> PathBuf { // this method doesn't handle multiple components - debug_assert!(!name_component.contains('\\')); - debug_assert!(!name_component.contains('/')); + debug_assert!( + !name_component.contains('\\'), + "Invalid component: {}", + name_component + ); + debug_assert!( + !name_component.contains('/'), + "Invalid component: {}", + name_component + ); match self { WindowsSystemRootablePath::WindowSystemRoot => { @@ -847,78 +855,28 @@ enum VfsEntryRef<'a> { Symlink(&'a VirtualSymlink), } -impl<'a> VfsEntryRef<'a> { - pub fn as_fs_stat(&self) -> FsStat { +impl VfsEntryRef<'_> { + pub fn as_metadata(&self) -> FileBackedVfsMetadata { + FileBackedVfsMetadata { + file_type: match self { + Self::Dir(_) => sys_traits::FileType::Dir, + Self::File(_) => sys_traits::FileType::File, + Self::Symlink(_) => sys_traits::FileType::Symlink, + }, + name: self.name().to_string(), + len: match self { + Self::Dir(_) => 0, + Self::File(file) => file.offset.len, + Self::Symlink(_) => 0, + }, + } + } + + pub fn name(&self) -> &str { match self { - VfsEntryRef::Dir(_) => FsStat { - is_directory: true, - is_file: false, - is_symlink: false, - atime: None, - birthtime: None, - mtime: None, - ctime: None, - blksize: 0, - size: 0, - dev: 0, - ino: 0, - mode: 0, - nlink: 0, - uid: 0, - gid: 0, - rdev: 0, - blocks: 0, - is_block_device: false, - is_char_device: false, - is_fifo: false, - is_socket: false, - }, - VfsEntryRef::File(file) => FsStat { - is_directory: false, - is_file: true, - is_symlink: false, - atime: None, - birthtime: None, - mtime: None, - ctime: None, - blksize: 0, - size: file.offset.len, - dev: 0, - ino: 0, - mode: 0, - nlink: 0, - uid: 0, - gid: 0, - rdev: 0, - blocks: 0, - is_block_device: false, - is_char_device: false, - is_fifo: false, - is_socket: false, - }, - VfsEntryRef::Symlink(_) => FsStat { - is_directory: false, - is_file: false, - is_symlink: true, - atime: None, - birthtime: None, - mtime: None, - ctime: None, - blksize: 0, - size: 0, - dev: 0, - ino: 0, - mode: 0, - nlink: 0, - uid: 0, - gid: 0, - rdev: 0, - blocks: 0, - is_block_device: false, - is_char_device: false, - is_fifo: false, - is_socket: false, - }, + Self::Dir(dir) => &dir.name, + Self::File(file) => &file.name, + Self::Symlink(symlink) => &symlink.name, } } } @@ -934,9 +892,9 @@ pub enum VfsEntry { impl VfsEntry { pub fn name(&self) -> &str { match self { - VfsEntry::Dir(dir) => &dir.name, - VfsEntry::File(file) => &file.name, - VfsEntry::Symlink(symlink) => &symlink.name, + Self::Dir(dir) => &dir.name, + Self::File(file) => &file.name, + Self::Symlink(symlink) => &symlink.name, } } @@ -1180,14 +1138,14 @@ impl VfsRoot { } } -struct FileBackedVfsFile { +pub struct FileBackedVfsFile { file: VirtualFile, pos: RefCell, vfs: Arc, } impl FileBackedVfsFile { - fn seek(&self, pos: SeekFrom) -> FsResult { + pub fn seek(&self, pos: SeekFrom) -> std::io::Result { match pos { SeekFrom::Start(pos) => { *self.pos.borrow_mut() = pos; @@ -1196,10 +1154,10 @@ impl FileBackedVfsFile { SeekFrom::End(offset) => { if offset < 0 && -offset as u64 > self.file.offset.len { let msg = "An attempt was made to move the file pointer before the beginning of the file."; - Err( - std::io::Error::new(std::io::ErrorKind::PermissionDenied, msg) - .into(), - ) + Err(std::io::Error::new( + std::io::ErrorKind::PermissionDenied, + msg, + )) } else { let mut current_pos = self.pos.borrow_mut(); *current_pos = if offset >= 0 { @@ -1215,7 +1173,7 @@ impl FileBackedVfsFile { if offset >= 0 { *current_pos += offset as u64; } else if -offset as u64 > *current_pos { - return Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "An attempt was made to move the file pointer before the beginning of the file.").into()); + return Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "An attempt was made to move the file pointer before the beginning of the file.")); } else { *current_pos -= -offset as u64; } @@ -1224,7 +1182,7 @@ impl FileBackedVfsFile { } } - fn read_to_buf(&self, buf: &mut [u8]) -> FsResult { + pub fn read_to_buf(&self, buf: &mut [u8]) -> std::io::Result { let read_pos = { let mut pos = self.pos.borrow_mut(); let read_pos = *pos; @@ -1232,10 +1190,7 @@ impl FileBackedVfsFile { *pos = std::cmp::min(self.file.offset.len, *pos + buf.len() as u64); read_pos }; - self - .vfs - .read_file(&self.file, read_pos, buf) - .map_err(|err| err.into()) + self.vfs.read_file(&self.file, read_pos, buf) } fn read_to_end(&self) -> FsResult> { @@ -1270,7 +1225,7 @@ impl FileBackedVfsFile { #[async_trait::async_trait(?Send)] impl deno_io::fs::File for FileBackedVfsFile { fn read_sync(self: Rc, buf: &mut [u8]) -> FsResult { - self.read_to_buf(buf) + self.read_to_buf(buf).map_err(Into::into) } async fn read_byob( self: Rc, @@ -1314,10 +1269,10 @@ impl deno_io::fs::File for FileBackedVfsFile { } fn seek_sync(self: Rc, pos: SeekFrom) -> FsResult { - self.seek(pos) + self.seek(pos).map_err(|err| err.into()) } async fn seek_async(self: Rc, pos: SeekFrom) -> FsResult { - self.seek(pos) + self.seek(pos).map_err(|err| err.into()) } fn datasync_sync(self: Rc) -> FsResult<()> { @@ -1393,6 +1348,47 @@ impl deno_io::fs::File for FileBackedVfsFile { } } +#[derive(Debug, Clone)] +pub struct FileBackedVfsDirEntry { + pub parent_path: PathBuf, + pub metadata: FileBackedVfsMetadata, +} + +#[derive(Debug, Clone)] +pub struct FileBackedVfsMetadata { + pub name: String, + pub file_type: sys_traits::FileType, + pub len: u64, +} + +impl FileBackedVfsMetadata { + pub fn as_fs_stat(&self) -> FsStat { + FsStat { + is_directory: self.file_type == sys_traits::FileType::Dir, + is_file: self.file_type == sys_traits::FileType::File, + is_symlink: self.file_type == sys_traits::FileType::Symlink, + atime: None, + birthtime: None, + mtime: None, + ctime: None, + blksize: 0, + size: self.len, + dev: 0, + ino: 0, + mode: 0, + nlink: 0, + uid: 0, + gid: 0, + rdev: 0, + blocks: 0, + is_block_device: false, + is_char_device: false, + is_fifo: false, + is_socket: false, + } + } +} + #[derive(Debug)] pub struct FileBackedVfs { vfs_data: Cow<'static, [u8]>, @@ -1418,13 +1414,13 @@ impl FileBackedVfs { pub fn open_file( self: &Arc, path: &Path, - ) -> std::io::Result> { + ) -> std::io::Result { let file = self.file_entry(path)?; - Ok(Rc::new(FileBackedVfsFile { + Ok(FileBackedVfsFile { file: file.clone(), vfs: self.clone(), pos: Default::default(), - })) + }) } pub fn read_dir(&self, path: &Path) -> std::io::Result> { @@ -1443,6 +1439,18 @@ impl FileBackedVfs { ) } + pub fn read_dir_with_metadata<'a>( + &'a self, + path: &Path, + ) -> std::io::Result + 'a> { + let dir = self.dir_entry(path)?; + let path = path.to_path_buf(); + Ok(dir.entries.iter().map(move |entry| FileBackedVfsDirEntry { + parent_path: path.to_path_buf(), + metadata: entry.as_ref().as_metadata(), + })) + } + pub fn read_link(&self, path: &Path) -> std::io::Result { let (_, entry) = self.fs_root.find_entry_no_follow(path)?; match entry { @@ -1456,14 +1464,14 @@ impl FileBackedVfs { } } - pub fn lstat(&self, path: &Path) -> std::io::Result { + pub fn lstat(&self, path: &Path) -> std::io::Result { let (_, entry) = self.fs_root.find_entry_no_follow(path)?; - Ok(entry.as_fs_stat()) + Ok(entry.as_metadata()) } - pub fn stat(&self, path: &Path) -> std::io::Result { + pub fn stat(&self, path: &Path) -> std::io::Result { let (_, entry) = self.fs_root.find_entry(path)?; - Ok(entry.as_fs_stat()) + Ok(entry.as_metadata()) } pub fn canonicalize(&self, path: &Path) -> std::io::Result { @@ -1556,6 +1564,7 @@ impl FileBackedVfs { #[cfg(test)] mod test { use console_static_text::ansi::strip_ansi_codes; + use deno_io::fs::File; use std::io::Write; use test_util::assert_contains; use test_util::TempDir; @@ -1641,25 +1650,31 @@ mod test { ); // metadata - assert!( + assert_eq!( virtual_fs .lstat(&dest_path.join("sub_dir").join("e.txt")) .unwrap() - .is_symlink + .file_type, + sys_traits::FileType::Symlink, ); - assert!( + assert_eq!( virtual_fs .stat(&dest_path.join("sub_dir").join("e.txt")) .unwrap() - .is_file + .file_type, + sys_traits::FileType::File, ); - assert!( + assert_eq!( virtual_fs .stat(&dest_path.join("sub_dir")) .unwrap() - .is_directory, + .file_type, + sys_traits::FileType::Dir, + ); + assert_eq!( + virtual_fs.stat(&dest_path.join("e.txt")).unwrap().file_type, + sys_traits::FileType::File ); - assert!(virtual_fs.stat(&dest_path.join("e.txt")).unwrap().is_file,); } #[test] @@ -1696,11 +1711,12 @@ mod test { read_file(&virtual_fs, &dest_path.join("sub_dir_link").join("c.txt")), "c", ); - assert!( + assert_eq!( virtual_fs .lstat(&dest_path.join("sub_dir_link")) .unwrap() - .is_symlink + .file_type, + sys_traits::FileType::Symlink, ); assert_eq!( @@ -1772,37 +1788,35 @@ mod test { let (dest_path, virtual_fs) = into_virtual_fs(builder, &temp_dir); let virtual_fs = Arc::new(virtual_fs); let file = virtual_fs.open_file(&dest_path.join("a.txt")).unwrap(); - file.clone().seek_sync(SeekFrom::Current(2)).unwrap(); + file.seek(SeekFrom::Current(2)).unwrap(); let mut buf = vec![0; 2]; - file.clone().read_sync(&mut buf).unwrap(); + file.read_to_buf(&mut buf).unwrap(); assert_eq!(buf, b"23"); - file.clone().read_sync(&mut buf).unwrap(); + file.read_to_buf(&mut buf).unwrap(); assert_eq!(buf, b"45"); - file.clone().seek_sync(SeekFrom::Current(-4)).unwrap(); - file.clone().read_sync(&mut buf).unwrap(); + file.seek(SeekFrom::Current(-4)).unwrap(); + file.read_to_buf(&mut buf).unwrap(); assert_eq!(buf, b"23"); - file.clone().seek_sync(SeekFrom::Start(2)).unwrap(); - file.clone().read_sync(&mut buf).unwrap(); + file.seek(SeekFrom::Start(2)).unwrap(); + file.read_to_buf(&mut buf).unwrap(); assert_eq!(buf, b"23"); - file.clone().seek_sync(SeekFrom::End(2)).unwrap(); - file.clone().read_sync(&mut buf).unwrap(); + file.seek(SeekFrom::End(2)).unwrap(); + file.read_to_buf(&mut buf).unwrap(); assert_eq!(buf, b"89"); - file.clone().seek_sync(SeekFrom::Current(-8)).unwrap(); - file.clone().read_sync(&mut buf).unwrap(); + file.seek(SeekFrom::Current(-8)).unwrap(); + file.read_to_buf(&mut buf).unwrap(); assert_eq!(buf, b"23"); assert_eq!( file - .clone() - .seek_sync(SeekFrom::Current(-5)) - .err() - .unwrap() - .into_io_error() + .seek(SeekFrom::Current(-5)) + .unwrap_err() .to_string(), "An attempt was made to move the file pointer before the beginning of the file." ); // go beyond the file length, then back - file.clone().seek_sync(SeekFrom::Current(40)).unwrap(); - file.clone().seek_sync(SeekFrom::Current(-38)).unwrap(); + file.seek(SeekFrom::Current(40)).unwrap(); + file.seek(SeekFrom::Current(-38)).unwrap(); + let file = Rc::new(file); let read_buf = file.clone().read(2).await.unwrap(); assert_eq!(read_buf.to_vec(), b"67"); file.clone().seek_sync(SeekFrom::Current(-2)).unwrap(); diff --git a/cli/sys.rs b/cli/sys.rs new file mode 100644 index 0000000000..55b50a199d --- /dev/null +++ b/cli/sys.rs @@ -0,0 +1,218 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +// todo(dsherret): this should instead use conditional compilation and directly +// surface the underlying implementation. +// +// The problem atm is that there's no way to have conditional compilation for +// denort or the deno binary. We should extract out denort to a separate binary. + +use std::borrow::Cow; + +use sys_traits::boxed::BoxedFsDirEntry; +use sys_traits::boxed::BoxedFsFile; +use sys_traits::boxed::BoxedFsMetadataValue; +use sys_traits::boxed::FsMetadataBoxed; +use sys_traits::boxed::FsOpenBoxed; +use sys_traits::boxed::FsReadDirBoxed; +use sys_traits::CreateDirOptions; + +use crate::standalone::DenoCompileFileSystem; + +#[derive(Debug, Clone)] +pub enum CliSys { + #[allow(dead_code)] // will be dead code for denort + #[allow(clippy::disallowed_types)] // ok because sys impl + Real(sys_traits::impls::RealSys), + #[allow(dead_code)] // will be dead code for deno + DenoCompile(DenoCompileFileSystem), +} + +impl Default for CliSys { + fn default() -> Self { + Self::Real(sys_traits::impls::RealSys) + } +} + +impl deno_runtime::deno_node::ExtNodeSys for CliSys {} + +impl sys_traits::BaseFsHardLink for CliSys { + fn base_fs_hard_link( + &self, + src: &std::path::Path, + dst: &std::path::Path, + ) -> std::io::Result<()> { + match self { + Self::Real(sys) => sys.base_fs_hard_link(src, dst), + Self::DenoCompile(sys) => sys.base_fs_hard_link(src, dst), + } + } +} + +impl sys_traits::BaseFsRead for CliSys { + fn base_fs_read( + &self, + p: &std::path::Path, + ) -> std::io::Result> { + match self { + Self::Real(sys) => sys.base_fs_read(p), + Self::DenoCompile(sys) => sys.base_fs_read(p), + } + } +} + +impl sys_traits::BaseFsReadDir for CliSys { + type ReadDirEntry = BoxedFsDirEntry; + + fn base_fs_read_dir( + &self, + p: &std::path::Path, + ) -> std::io::Result< + Box> + '_>, + > { + match self { + Self::Real(sys) => sys.fs_read_dir_boxed(p), + Self::DenoCompile(sys) => sys.fs_read_dir_boxed(p), + } + } +} + +impl sys_traits::BaseFsCanonicalize for CliSys { + fn base_fs_canonicalize( + &self, + p: &std::path::Path, + ) -> std::io::Result { + match self { + Self::Real(sys) => sys.base_fs_canonicalize(p), + Self::DenoCompile(sys) => sys.base_fs_canonicalize(p), + } + } +} + +impl sys_traits::BaseFsMetadata for CliSys { + type Metadata = BoxedFsMetadataValue; + + fn base_fs_metadata( + &self, + path: &std::path::Path, + ) -> std::io::Result { + match self { + Self::Real(sys) => sys.fs_metadata_boxed(path), + Self::DenoCompile(sys) => sys.fs_metadata_boxed(path), + } + } + + fn base_fs_symlink_metadata( + &self, + path: &std::path::Path, + ) -> std::io::Result { + match self { + Self::Real(sys) => sys.fs_symlink_metadata_boxed(path), + Self::DenoCompile(sys) => sys.fs_symlink_metadata_boxed(path), + } + } +} + +impl sys_traits::BaseFsCreateDir for CliSys { + fn base_fs_create_dir( + &self, + p: &std::path::Path, + options: &CreateDirOptions, + ) -> std::io::Result<()> { + match self { + Self::Real(sys) => sys.base_fs_create_dir(p, options), + Self::DenoCompile(sys) => sys.base_fs_create_dir(p, options), + } + } +} + +impl sys_traits::BaseFsOpen for CliSys { + type File = BoxedFsFile; + + fn base_fs_open( + &self, + path: &std::path::Path, + options: &sys_traits::OpenOptions, + ) -> std::io::Result { + match self { + Self::Real(sys) => sys.fs_open_boxed(path, options), + Self::DenoCompile(sys) => sys.fs_open_boxed(path, options), + } + } +} + +impl sys_traits::BaseFsRemoveFile for CliSys { + fn base_fs_remove_file(&self, p: &std::path::Path) -> std::io::Result<()> { + match self { + Self::Real(sys) => sys.base_fs_remove_file(p), + Self::DenoCompile(sys) => sys.base_fs_remove_file(p), + } + } +} + +impl sys_traits::BaseFsRename for CliSys { + fn base_fs_rename( + &self, + old: &std::path::Path, + new: &std::path::Path, + ) -> std::io::Result<()> { + match self { + Self::Real(sys) => sys.base_fs_rename(old, new), + Self::DenoCompile(sys) => sys.base_fs_rename(old, new), + } + } +} + +impl sys_traits::SystemRandom for CliSys { + fn sys_random(&self, buf: &mut [u8]) -> std::io::Result<()> { + match self { + Self::Real(sys) => sys.sys_random(buf), + Self::DenoCompile(sys) => sys.sys_random(buf), + } + } +} + +impl sys_traits::SystemTimeNow for CliSys { + fn sys_time_now(&self) -> std::time::SystemTime { + match self { + Self::Real(sys) => sys.sys_time_now(), + Self::DenoCompile(sys) => sys.sys_time_now(), + } + } +} + +impl sys_traits::ThreadSleep for CliSys { + fn thread_sleep(&self, dur: std::time::Duration) { + match self { + Self::Real(sys) => sys.thread_sleep(dur), + Self::DenoCompile(sys) => sys.thread_sleep(dur), + } + } +} + +impl sys_traits::EnvCurrentDir for CliSys { + fn env_current_dir(&self) -> std::io::Result { + match self { + Self::Real(sys) => sys.env_current_dir(), + Self::DenoCompile(sys) => sys.env_current_dir(), + } + } +} + +impl sys_traits::BaseEnvVar for CliSys { + fn base_env_var_os( + &self, + key: &std::ffi::OsStr, + ) -> Option { + match self { + Self::Real(sys) => sys.base_env_var_os(key), + Self::DenoCompile(sys) => sys.base_env_var_os(key), + } + } +} + +impl sys_traits::EnvHomeDir for CliSys { + fn env_home_dir(&self) -> Option { + #[allow(clippy::disallowed_types)] // ok because sys impl + sys_traits::impls::RealSys.env_home_dir() + } +} diff --git a/cli/task_runner.rs b/cli/task_runner.rs index d6589a1832..c7232387ca 100644 --- a/cli/task_runner.rs +++ b/cli/task_runner.rs @@ -10,7 +10,6 @@ use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::futures; use deno_core::futures::future::LocalBoxFuture; -use deno_runtime::deno_node::NodeResolver; use deno_semver::package::PackageNv; use deno_task_shell::ExecutableCommand; use deno_task_shell::ExecuteResult; @@ -25,6 +24,7 @@ use tokio::task::JoinHandle; use tokio::task::LocalSet; use tokio_util::sync::CancellationToken; +use crate::node::CliNodeResolver; use crate::npm::CliNpmResolver; use crate::npm::InnerCliNpmResolverRef; use crate::npm::ManagedCliNpmResolver; @@ -415,7 +415,7 @@ impl ShellCommand for NodeModulesFileRunCommand { pub fn resolve_custom_commands( npm_resolver: &dyn CliNpmResolver, - node_resolver: &NodeResolver, + node_resolver: &CliNodeResolver, ) -> Result>, AnyError> { let mut commands = match npm_resolver.as_inner() { InnerCliNpmResolverRef::Byonm(npm_resolver) => { @@ -522,7 +522,7 @@ fn resolve_execution_path_from_npx_shim( fn resolve_managed_npm_commands( npm_resolver: &ManagedCliNpmResolver, - node_resolver: &NodeResolver, + node_resolver: &CliNodeResolver, ) -> Result>, AnyError> { let mut result = HashMap::new(); let snapshot = npm_resolver.snapshot(); diff --git a/cli/tools/bench/mod.rs b/cli/tools/bench/mod.rs index 5983590531..1b47c9bfb0 100644 --- a/cli/tools/bench/mod.rs +++ b/cli/tools/bench/mod.rs @@ -7,6 +7,7 @@ use crate::display::write_json_to_stdout; use crate::factory::CliFactory; use crate::graph_util::has_graph_root_local_dependent_changed; use crate::ops; +use crate::sys::CliSys; use crate::tools::test::format_test_error; use crate::tools::test::TestFilter; use crate::util::file_watcher; @@ -265,7 +266,7 @@ async fn bench_specifier_inner( async fn bench_specifiers( worker_factory: Arc, permissions: &Permissions, - permissions_desc_parser: &Arc, + permissions_desc_parser: &Arc>, specifiers: Vec, options: BenchSpecifierOptions, ) -> Result<(), AnyError> { diff --git a/cli/tools/check.rs b/cli/tools/check.rs index 9af084806f..acfff70401 100644 --- a/cli/tools/check.rs +++ b/cli/tools/check.rs @@ -9,7 +9,6 @@ use deno_ast::ModuleSpecifier; use deno_core::error::AnyError; use deno_graph::Module; use deno_graph::ModuleGraph; -use deno_runtime::deno_node::NodeResolver; use deno_terminal::colors; use once_cell::sync::Lazy; use regex::Regex; @@ -29,6 +28,7 @@ use crate::cache::TypeCheckCache; use crate::factory::CliFactory; use crate::graph_util::BuildFastCheckGraphOptions; use crate::graph_util::ModuleGraphBuilder; +use crate::node::CliNodeResolver; use crate::npm::CliNpmResolver; use crate::tsc; use crate::tsc::Diagnostics; @@ -103,7 +103,7 @@ pub struct TypeChecker { cjs_tracker: Arc, cli_options: Arc, module_graph_builder: Arc, - node_resolver: Arc, + node_resolver: Arc, npm_resolver: Arc, } @@ -113,7 +113,7 @@ impl TypeChecker { cjs_tracker: Arc, cli_options: Arc, module_graph_builder: Arc, - node_resolver: Arc, + node_resolver: Arc, npm_resolver: Arc, ) -> Self { Self { diff --git a/cli/tools/clean.rs b/cli/tools/clean.rs index 2a77434f88..cdc1c51dcd 100644 --- a/cli/tools/clean.rs +++ b/cli/tools/clean.rs @@ -7,6 +7,7 @@ use std::path::Path; use crate::cache::DenoDir; use crate::colors; use crate::display; +use crate::sys::CliSys; use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressMessagePrompt; @@ -28,7 +29,7 @@ impl CleanState { } pub fn clean() -> Result<(), AnyError> { - let deno_dir = DenoDir::new(None)?; + let deno_dir = DenoDir::new(CliSys::default(), None)?; if deno_dir.root.exists() { let no_of_files = walkdir::WalkDir::new(&deno_dir.root).into_iter().count(); let progress_bar = ProgressBar::new(ProgressBarStyle::ProgressBars); diff --git a/cli/tools/compile.rs b/cli/tools/compile.rs index 7a463a7b09..cbd376bae2 100644 --- a/cli/tools/compile.rs +++ b/cli/tools/compile.rs @@ -5,8 +5,8 @@ use crate::args::CompileFlags; use crate::args::Flags; use crate::factory::CliFactory; use crate::http_util::HttpClientProvider; +use crate::standalone::binary::is_standalone_binary; use crate::standalone::binary::WriteBinOptions; -use crate::standalone::is_standalone_binary; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_core::anyhow::bail; diff --git a/cli/tools/coverage/mod.rs b/cli/tools/coverage/mod.rs index 4736bdab41..a9054207b0 100644 --- a/cli/tools/coverage/mod.rs +++ b/cli/tools/coverage/mod.rs @@ -7,6 +7,7 @@ use crate::args::Flags; use crate::cdp; use crate::factory::CliFactory; use crate::file_fetcher::TextDecodedFile; +use crate::sys::CliSys; use crate::tools::fmt::format_json; use crate::tools::test::is_supported_test_path; use crate::util::text_encoding::source_map_from_code; @@ -26,7 +27,6 @@ use deno_core::serde_json; use deno_core::sourcemap::SourceMap; use deno_core::url::Url; use deno_core::LocalInspectorSession; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use node_resolver::InNpmPackageChecker; use regex::Regex; use std::fs; @@ -429,7 +429,7 @@ fn collect_coverages( .ignore_git_folder() .ignore_node_modules() .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) - .collect_file_patterns(&FsSysTraitsAdapter::new_real(), file_patterns)?; + .collect_file_patterns(&CliSys::default(), file_patterns)?; let coverage_patterns = FilePatterns { base: initial_cwd.to_path_buf(), diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index c33b988de0..0ff1806a9e 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -10,6 +10,7 @@ use crate::factory::CliFactory; use crate::graph_util::graph_exit_integrity_errors; use crate::graph_util::graph_walk_errors; use crate::graph_util::GraphWalkErrorsOptions; +use crate::sys::CliSys; use crate::tsc::get_types_declaration_file_text; use crate::util::fs::collect_specifiers; use deno_ast::diagnostics::Diagnostic; @@ -28,7 +29,6 @@ use deno_graph::EsParser; use deno_graph::GraphKind; use deno_graph::ModuleAnalyzer; use deno_graph::ModuleSpecifier; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use doc::html::ShortPath; use doc::DocDiagnostic; use indexmap::IndexMap; @@ -115,7 +115,7 @@ pub async fn doc( } DocSourceFileFlag::Paths(ref source_files) => { let module_graph_creator = factory.module_graph_creator().await?; - let fs = FsSysTraitsAdapter(factory.fs().clone()); + let sys = CliSys::default(); let module_specifiers = collect_specifiers( FilePatterns { @@ -142,7 +142,7 @@ pub async fn doc( graph_exit_integrity_errors(&graph); let errors = graph_walk_errors( &graph, - &fs, + &sys, &module_specifiers, GraphWalkErrorsOptions { check_js: false, diff --git a/cli/tools/fmt.rs b/cli/tools/fmt.rs index 55046155c0..7f9a15f4b2 100644 --- a/cli/tools/fmt.rs +++ b/cli/tools/fmt.rs @@ -17,6 +17,7 @@ use crate::args::UnstableFmtOptions; use crate::cache::Caches; use crate::colors; use crate::factory::CliFactory; +use crate::sys::CliSys; use crate::util::diff::diff; use crate::util::file_watcher; use crate::util::fs::canonicalize_path; @@ -34,7 +35,6 @@ use deno_core::futures; use deno_core::parking_lot::Mutex; use deno_core::unsync::spawn_blocking; use deno_core::url::Url; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use log::debug; use log::info; use log::warn; @@ -58,7 +58,7 @@ pub async fn format( fmt_flags: FmtFlags, ) -> Result<(), AnyError> { if fmt_flags.is_stdin() { - let cli_options = CliOptions::from_flags(flags)?; + let cli_options = CliOptions::from_flags(&CliSys::default(), flags)?; let start_dir = &cli_options.start_dir; let fmt_config = start_dir .to_fmt_config(FilePatterns::new_with_base(start_dir.dir_path()))?; @@ -231,7 +231,7 @@ fn collect_fmt_files( .ignore_node_modules() .use_gitignore() .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) - .collect_file_patterns(&FsSysTraitsAdapter::new_real(), files) + .collect_file_patterns(&CliSys::default(), files) } /// Formats markdown (using ) and its code blocks diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs index ec538ecb0a..1bfd17f30d 100644 --- a/cli/tools/installer.rs +++ b/cli/tools/installer.rs @@ -364,6 +364,7 @@ async fn install_global( let deps_file_fetcher = CliFileFetcher::new( deps_http_cache.clone(), http_client.clone(), + factory.sys(), Default::default(), None, true, diff --git a/cli/tools/lint/linter.rs b/cli/tools/lint/linter.rs index a10ad6479e..6bb3c628fa 100644 --- a/cli/tools/lint/linter.rs +++ b/cli/tools/lint/linter.rs @@ -16,8 +16,8 @@ use deno_lint::linter::LintFileOptions; use deno_lint::linter::Linter as DenoLintLinter; use deno_lint::linter::LinterOptions; use deno_path_util::fs::atomic_write_file_with_retries; -use deno_runtime::deno_fs::FsSysTraitsAdapter; +use crate::sys::CliSys; use crate::util::fs::specifier_from_file_path; use super::rules::FileOrPackageLintRule; @@ -177,7 +177,7 @@ impl CliLinter { if fix_iterations > 0 { // everything looks good and the file still parses, so write it out atomic_write_file_with_retries( - &FsSysTraitsAdapter::new_real(), + &CliSys::default(), file_path, source.text().as_bytes(), crate::cache::CACHE_PERM, diff --git a/cli/tools/lint/mod.rs b/cli/tools/lint/mod.rs index 4071f30e7e..6d3997ac3b 100644 --- a/cli/tools/lint/mod.rs +++ b/cli/tools/lint/mod.rs @@ -21,7 +21,6 @@ use deno_core::unsync::future::SharedLocal; use deno_graph::ModuleGraph; use deno_lint::diagnostic::LintDiagnostic; use deno_lint::linter::LintConfig as DenoLintConfig; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use log::debug; use reporters::create_reporter; use reporters::LintReporter; @@ -44,6 +43,7 @@ use crate::cache::IncrementalCache; use crate::colors; use crate::factory::CliFactory; use crate::graph_util::ModuleGraphCreator; +use crate::sys::CliSys; use crate::tools::fmt::run_parallelized; use crate::util::display; use crate::util::file_watcher; @@ -453,7 +453,7 @@ fn collect_lint_files( .ignore_node_modules() .use_gitignore() .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) - .collect_file_patterns(&FsSysTraitsAdapter::new_real(), files) + .collect_file_patterns(&CliSys::default(), files) } #[allow(clippy::print_stdout)] diff --git a/cli/tools/registry/paths.rs b/cli/tools/registry/paths.rs index b607c0924c..1c675982df 100644 --- a/cli/tools/registry/paths.rs +++ b/cli/tools/registry/paths.rs @@ -6,12 +6,12 @@ use std::collections::HashSet; use std::path::Path; use std::path::PathBuf; +use crate::sys::CliSys; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_config::glob::FileCollector; use deno_config::glob::FilePatterns; use deno_core::error::AnyError; -use deno_runtime::deno_fs::FsSysTraitsAdapter; use thiserror::Error; use crate::args::CliOptions; @@ -346,5 +346,5 @@ fn collect_paths( .ignore_node_modules() .set_vendor_folder(cli_options.vendor_dir_path().map(ToOwned::to_owned)) .use_gitignore() - .collect_file_patterns(&FsSysTraitsAdapter::new_real(), file_patterns) + .collect_file_patterns(&CliSys::default(), file_patterns) } diff --git a/cli/tools/registry/pm.rs b/cli/tools/registry/pm.rs index afa9b0222c..ab4d92762f 100644 --- a/cli/tools/registry/pm.rs +++ b/cli/tools/registry/pm.rs @@ -415,6 +415,7 @@ pub async fn add( let deps_file_fetcher = CliFileFetcher::new( deps_http_cache.clone(), http_client.clone(), + cli_factory.sys(), Default::default(), None, true, diff --git a/cli/tools/registry/pm/outdated.rs b/cli/tools/registry/pm/outdated.rs index 20a6043f26..bb4c60fde8 100644 --- a/cli/tools/registry/pm/outdated.rs +++ b/cli/tools/registry/pm/outdated.rs @@ -185,6 +185,7 @@ pub async fn outdated( let file_fetcher = CliFileFetcher::new( deps_http_cache.clone(), http_client.clone(), + factory.sys(), Default::default(), None, true, diff --git a/cli/tools/registry/unfurl.rs b/cli/tools/registry/unfurl.rs index ca50775717..989a6e1ed4 100644 --- a/cli/tools/registry/unfurl.rs +++ b/cli/tools/registry/unfurl.rs @@ -658,13 +658,12 @@ mod tests { use crate::resolver::SloppyImportsCachedFs; use super::*; + use crate::sys::CliSys; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_config::workspace::ResolverWorkspaceJsrPackage; use deno_core::serde_json::json; use deno_core::url::Url; - use deno_runtime::deno_fs::FsSysTraitsAdapter; - use deno_runtime::deno_fs::RealFs; use deno_runtime::deno_node::PackageJson; use deno_semver::Version; use import_map::ImportMapWithDiagnostics; @@ -725,7 +724,7 @@ mod tests { ); let unfurler = SpecifierUnfurler::new( Some(Arc::new(CliSloppyImportsResolver::new( - SloppyImportsCachedFs::new(FsSysTraitsAdapter::new_real()), + SloppyImportsCachedFs::new(CliSys::default()), ))), Arc::new(workspace_resolver), true, @@ -863,10 +862,10 @@ const warn2 = await import(`${expr}`); ], deno_config::workspace::PackageJsonDepResolution::Enabled, ); - let fs = FsSysTraitsAdapter(Arc::new(RealFs)); + let sys = CliSys::default(); let unfurler = SpecifierUnfurler::new( Some(Arc::new(CliSloppyImportsResolver::new( - SloppyImportsCachedFs::new(fs), + SloppyImportsCachedFs::new(sys), ))), Arc::new(workspace_resolver), true, diff --git a/cli/tools/task.rs b/cli/tools/task.rs index 740b0ce843..4d83cc98fd 100644 --- a/cli/tools/task.rs +++ b/cli/tools/task.rs @@ -25,7 +25,6 @@ use deno_core::futures::FutureExt; use deno_core::futures::StreamExt; use deno_core::url::Url; use deno_path_util::normalize_path; -use deno_runtime::deno_node::NodeResolver; use deno_task_shell::KillSignal; use deno_task_shell::ShellCommand; use indexmap::IndexMap; @@ -36,6 +35,7 @@ use crate::args::Flags; use crate::args::TaskFlags; use crate::colors; use crate::factory::CliFactory; +use crate::node::CliNodeResolver; use crate::npm::CliNpmResolver; use crate::task_runner; use crate::task_runner::run_future_forwarding_signals; @@ -267,7 +267,7 @@ struct RunSingleOptions<'a> { struct TaskRunner<'a> { task_flags: &'a TaskFlags, npm_resolver: &'a dyn CliNpmResolver, - node_resolver: &'a NodeResolver, + node_resolver: &'a CliNodeResolver, env_vars: HashMap, cli_options: &'a CliOptions, concurrency: usize, diff --git a/cli/tools/test/mod.rs b/cli/tools/test/mod.rs index 3164b8ae59..3745d7c7ec 100644 --- a/cli/tools/test/mod.rs +++ b/cli/tools/test/mod.rs @@ -10,6 +10,7 @@ use crate::factory::CliFactory; use crate::file_fetcher::CliFileFetcher; use crate::graph_util::has_graph_root_local_dependent_changed; use crate::ops; +use crate::sys::CliSys; use crate::util::extract::extract_doc_tests; use crate::util::file_watcher; use crate::util::fs::collect_specifiers; @@ -1194,7 +1195,7 @@ static HAS_TEST_RUN_SIGINT_HANDLER: AtomicBool = AtomicBool::new(false); async fn test_specifiers( worker_factory: Arc, permissions: &Permissions, - permission_desc_parser: &Arc, + permission_desc_parser: &Arc>, specifiers: Vec, options: TestSpecifiersOptions, ) -> Result<(), AnyError> { diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index 26cf385734..4c84050b5e 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -4,8 +4,10 @@ use crate::args::TsConfig; use crate::args::TypeCheckMode; use crate::cache::FastInsecureHasher; use crate::cache::ModuleInfoCache; +use crate::node::CliNodeResolver; use crate::npm::CliNpmResolver; use crate::resolver::CjsTracker; +use crate::sys::CliSys; use crate::util::checksum; use crate::util::path::mapped_specifier_for_tsc; use crate::worker::create_isolate_create_params; @@ -34,8 +36,6 @@ use deno_graph::Module; use deno_graph::ModuleGraph; use deno_graph::ResolutionResolved; use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; -use deno_runtime::deno_fs::FsSysTraitsAdapter; -use deno_runtime::deno_node::NodeResolver; use deno_semver::npm::NpmPackageReqReference; use node_resolver::errors::NodeJsErrorCode; use node_resolver::errors::NodeJsErrorCoded; @@ -380,7 +380,7 @@ impl TypeCheckingCjsTracker { #[derive(Debug)] pub struct RequestNpmState { pub cjs_tracker: Arc, - pub node_resolver: Arc, + pub node_resolver: Arc, pub npm_resolver: Arc, } @@ -661,7 +661,7 @@ fn op_load_inner( } else { // means it's Deno code importing an npm module let specifier = resolve_specifier_into_node_modules( - &FsSysTraitsAdapter::new_real(), + &CliSys::default(), &module.specifier, ); Some(Cow::Owned(load_from_node_modules( @@ -925,7 +925,7 @@ fn resolve_graph_specifier_types( // we currently only use "External" for when the module is in an npm package Ok(state.maybe_npm.as_ref().map(|_| { let specifier = resolve_specifier_into_node_modules( - &FsSysTraitsAdapter::new_real(), + &CliSys::default(), &module.specifier, ); into_specifier_and_media_type(Some(specifier)) diff --git a/cli/util/fs.rs b/cli/util/fs.rs index 58b5fc72c6..e0b9a6f4ee 100644 --- a/cli/util/fs.rs +++ b/cli/util/fs.rs @@ -17,8 +17,8 @@ use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::unsync::spawn_blocking; use deno_core::ModuleSpecifier; -use deno_runtime::deno_fs::FsSysTraitsAdapter; +use crate::sys::CliSys; use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressMessagePrompt; @@ -76,7 +76,7 @@ pub fn canonicalize_path_maybe_not_exists( path: &Path, ) -> Result { deno_path_util::fs::canonicalize_path_maybe_not_exists( - &FsSysTraitsAdapter::new_real(), + &CliSys::default(), path, ) } @@ -126,7 +126,7 @@ pub fn collect_specifiers( .ignore_git_folder() .ignore_node_modules() .set_vendor_folder(vendor_folder) - .collect_file_patterns(&FsSysTraitsAdapter::new_real(), files)?; + .collect_file_patterns(&CliSys::default(), files)?; let mut collected_files_as_urls = collected_files .iter() .map(|f| specifier_from_file_path(f).unwrap()) @@ -198,13 +198,11 @@ mod clone_dir_imp { from: &std::path::Path, to: &std::path::Path, ) -> Result<(), deno_core::error::AnyError> { - use deno_runtime::deno_fs::FsSysTraitsAdapter; + use crate::sys::CliSys; - if let Err(e) = deno_npm_cache::hard_link_dir_recursive( - &FsSysTraitsAdapter::new_real(), - from, - to, - ) { + if let Err(e) = + deno_npm_cache::hard_link_dir_recursive(&CliSys::default(), from, to) + { log::debug!("Failed to hard link dir {:?} to {:?}: {}", from, to, e); super::copy_dir_recursive(from, to)?; } diff --git a/cli/worker.rs b/cli/worker.rs index 7653e72b75..ef519c7278 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -23,8 +23,6 @@ use deno_runtime::deno_fs; use deno_runtime::deno_node::NodeExtInitServices; use deno_runtime::deno_node::NodeRequireLoader; use deno_runtime::deno_node::NodeRequireLoaderRc; -use deno_runtime::deno_node::NodeResolver; -use deno_runtime::deno_node::PackageJsonResolver; use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::deno_tls::RootCertStoreProvider; use deno_runtime::deno_web::BlobStore; @@ -53,7 +51,10 @@ use crate::args::DenoSubcommand; use crate::args::NpmCachingStrategy; use crate::args::StorageKeyResolver; use crate::errors; +use crate::node::CliNodeResolver; +use crate::node::CliPackageJsonResolver; use crate::npm::CliNpmResolver; +use crate::sys::CliSys; use crate::util::checksum; use crate::util::file_watcher::WatcherCommunicator; use crate::util::file_watcher::WatcherRestartMode; @@ -145,13 +146,14 @@ struct SharedWorkerState { maybe_inspector_server: Option>, maybe_lockfile: Option>, module_loader_factory: Box, - node_resolver: Arc, + node_resolver: Arc, npm_resolver: Arc, - pkg_json_resolver: Arc, + pkg_json_resolver: Arc, root_cert_store_provider: Arc, root_permissions: PermissionsContainer, shared_array_buffer_store: SharedArrayBufferStore, storage_key_resolver: StorageKeyResolver, + sys: CliSys, options: CliMainWorkerOptions, subcommand: DenoSubcommand, otel_config: OtelConfig, @@ -162,12 +164,13 @@ impl SharedWorkerState { pub fn create_node_init_services( &self, node_require_loader: NodeRequireLoaderRc, - ) -> NodeExtInitServices { + ) -> NodeExtInitServices { NodeExtInitServices { node_require_loader, node_resolver: self.node_resolver.clone(), npm_resolver: self.npm_resolver.clone().into_npm_pkg_folder_resolver(), pkg_json_resolver: self.pkg_json_resolver.clone(), + sys: self.sys.clone(), } } @@ -418,12 +421,13 @@ impl CliMainWorkerFactory { maybe_inspector_server: Option>, maybe_lockfile: Option>, module_loader_factory: Box, - node_resolver: Arc, + node_resolver: Arc, npm_resolver: Arc, - pkg_json_resolver: Arc, + pkg_json_resolver: Arc, root_cert_store_provider: Arc, root_permissions: PermissionsContainer, storage_key_resolver: StorageKeyResolver, + sys: CliSys, subcommand: DenoSubcommand, options: CliMainWorkerOptions, otel_config: OtelConfig, @@ -448,6 +452,7 @@ impl CliMainWorkerFactory { root_permissions, shared_array_buffer_store: Default::default(), storage_key_resolver, + sys, options, subcommand, otel_config, @@ -869,14 +874,15 @@ mod tests { let main_module = resolve_path("./hello.js", &std::env::current_dir().unwrap()).unwrap(); let fs = Arc::new(RealFs); - let permission_desc_parser = - Arc::new(RuntimePermissionDescriptorParser::new(fs.clone())); + let permission_desc_parser = Arc::new( + RuntimePermissionDescriptorParser::new(crate::sys::CliSys::default()), + ); let options = WorkerOptions { startup_snapshot: crate::js::deno_isolate_init(), ..Default::default() }; - MainWorker::bootstrap_from_options( + MainWorker::bootstrap_from_options::( main_module, WorkerServiceOptions { module_loader: Rc::new(FsModuleLoader), diff --git a/ext/fs/Cargo.toml b/ext/fs/Cargo.toml index 8692f04a73..1d0b623718 100644 --- a/ext/fs/Cargo.toml +++ b/ext/fs/Cargo.toml @@ -25,12 +25,10 @@ deno_io.workspace = true deno_path_util.workspace = true deno_permissions.workspace = true filetime.workspace = true -getrandom = "0.2" libc.workspace = true rand.workspace = true rayon = "1.8.0" serde.workspace = true -sys_traits.workspace = true thiserror.workspace = true [target.'cfg(unix)'.dependencies] diff --git a/ext/fs/in_memory_fs.rs b/ext/fs/in_memory_fs.rs deleted file mode 100644 index b79b0ae984..0000000000 --- a/ext/fs/in_memory_fs.rs +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -// Allow using Arc for this module. -#![allow(clippy::disallowed_types)] - -use std::borrow::Cow; -use std::collections::hash_map::Entry; -use std::collections::HashMap; -use std::io::Error; -use std::io::ErrorKind; -use std::path::Path; -use std::path::PathBuf; -use std::rc::Rc; -use std::sync::Arc; - -use deno_core::parking_lot::Mutex; -use deno_io::fs::File; -use deno_io::fs::FsError; -use deno_io::fs::FsResult; -use deno_io::fs::FsStat; -use deno_path_util::normalize_path; - -use crate::interface::AccessCheckCb; -use crate::interface::FsDirEntry; -use crate::interface::FsFileType; -use crate::FileSystem; -use crate::OpenOptions; - -#[derive(Debug)] -enum PathEntry { - Dir, - File(Vec), -} - -/// A very basic in-memory file system useful for swapping out in -/// the place of a RealFs for testing purposes. -/// -/// Please develop this out as you need functionality. -#[derive(Debug, Default)] -pub struct InMemoryFs { - entries: Mutex>>, -} - -impl InMemoryFs { - pub fn setup_text_files(&self, files: Vec<(String, String)>) { - for (path, text) in files { - let path = PathBuf::from(path); - self.mkdir_sync(path.parent().unwrap(), true, None).unwrap(); - self - .write_file_sync( - &path, - OpenOptions::write(true, false, false, None), - None, - &text.into_bytes(), - ) - .unwrap(); - } - } - - fn get_entry(&self, path: &Path) -> Option> { - let path = normalize_path(path); - self.entries.lock().get(&path).cloned() - } -} - -#[async_trait::async_trait(?Send)] -impl FileSystem for InMemoryFs { - fn cwd(&self) -> FsResult { - Err(FsError::NotSupported) - } - - fn tmp_dir(&self) -> FsResult { - Err(FsError::NotSupported) - } - - fn chdir(&self, _path: &Path) -> FsResult<()> { - Err(FsError::NotSupported) - } - - fn umask(&self, _mask: Option) -> FsResult { - Err(FsError::NotSupported) - } - - fn open_sync( - &self, - _path: &Path, - _options: OpenOptions, - _access_check: Option, - ) -> FsResult> { - Err(FsError::NotSupported) - } - async fn open_async<'a>( - &'a self, - path: PathBuf, - options: OpenOptions, - access_check: Option>, - ) -> FsResult> { - self.open_sync(&path, options, access_check) - } - - fn mkdir_sync( - &self, - path: &Path, - recursive: bool, - _mode: Option, - ) -> FsResult<()> { - let path = normalize_path(path); - - if let Some(parent) = path.parent() { - let entry = self.entries.lock().get(parent).cloned(); - match entry { - Some(entry) => match &*entry { - PathEntry::File(_) => { - return Err(FsError::Io(Error::new( - ErrorKind::InvalidInput, - "Parent is a file", - ))) - } - PathEntry::Dir => {} - }, - None => { - if recursive { - self.mkdir_sync(parent, true, None)?; - } else { - return Err(FsError::Io(Error::new( - ErrorKind::NotFound, - "Not found", - ))); - } - } - } - } - - let entry = self.entries.lock().get(&path).cloned(); - match entry { - Some(entry) => match &*entry { - PathEntry::File(_) => Err(FsError::Io(Error::new( - ErrorKind::InvalidInput, - "Is a file", - ))), - PathEntry::Dir => Ok(()), - }, - None => { - self.entries.lock().insert(path, Arc::new(PathEntry::Dir)); - Ok(()) - } - } - } - async fn mkdir_async( - &self, - path: PathBuf, - recursive: bool, - mode: Option, - ) -> FsResult<()> { - self.mkdir_sync(&path, recursive, mode) - } - - fn chmod_sync(&self, _path: &Path, _mode: u32) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn chmod_async(&self, path: PathBuf, mode: u32) -> FsResult<()> { - self.chmod_sync(&path, mode) - } - - fn chown_sync( - &self, - _path: &Path, - _uid: Option, - _gid: Option, - ) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn chown_async( - &self, - path: PathBuf, - uid: Option, - gid: Option, - ) -> FsResult<()> { - self.chown_sync(&path, uid, gid) - } - - fn lchown_sync( - &self, - _path: &Path, - _uid: Option, - _gid: Option, - ) -> FsResult<()> { - Err(FsError::NotSupported) - } - - async fn lchown_async( - &self, - path: PathBuf, - uid: Option, - gid: Option, - ) -> FsResult<()> { - self.lchown_sync(&path, uid, gid) - } - - fn remove_sync(&self, _path: &Path, _recursive: bool) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn remove_async(&self, path: PathBuf, recursive: bool) -> FsResult<()> { - self.remove_sync(&path, recursive) - } - - fn copy_file_sync(&self, _from: &Path, _to: &Path) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn copy_file_async(&self, from: PathBuf, to: PathBuf) -> FsResult<()> { - self.copy_file_sync(&from, &to) - } - - fn cp_sync(&self, _from: &Path, _to: &Path) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn cp_async(&self, from: PathBuf, to: PathBuf) -> FsResult<()> { - self.cp_sync(&from, &to) - } - - fn stat_sync(&self, path: &Path) -> FsResult { - let entry = self.get_entry(path); - match entry { - Some(entry) => match &*entry { - PathEntry::Dir => Ok(FsStat { - is_file: false, - is_directory: true, - is_symlink: false, - size: 0, - mtime: None, - atime: None, - birthtime: None, - ctime: None, - dev: 0, - ino: 0, - mode: 0, - nlink: 0, - uid: 0, - gid: 0, - rdev: 0, - blksize: 0, - blocks: 0, - is_block_device: false, - is_char_device: false, - is_fifo: false, - is_socket: false, - }), - PathEntry::File(data) => Ok(FsStat { - is_file: true, - is_directory: false, - is_symlink: false, - size: data.len() as u64, - mtime: None, - atime: None, - birthtime: None, - ctime: None, - dev: 0, - ino: 0, - mode: 0, - nlink: 0, - uid: 0, - gid: 0, - rdev: 0, - blksize: 0, - blocks: 0, - is_block_device: false, - is_char_device: false, - is_fifo: false, - is_socket: false, - }), - }, - None => Err(FsError::Io(Error::new(ErrorKind::NotFound, "Not found"))), - } - } - async fn stat_async(&self, path: PathBuf) -> FsResult { - self.stat_sync(&path) - } - - fn lstat_sync(&self, _path: &Path) -> FsResult { - Err(FsError::NotSupported) - } - async fn lstat_async(&self, path: PathBuf) -> FsResult { - self.lstat_sync(&path) - } - - fn realpath_sync(&self, _path: &Path) -> FsResult { - Err(FsError::NotSupported) - } - async fn realpath_async(&self, path: PathBuf) -> FsResult { - self.realpath_sync(&path) - } - - fn read_dir_sync(&self, _path: &Path) -> FsResult> { - Err(FsError::NotSupported) - } - async fn read_dir_async(&self, path: PathBuf) -> FsResult> { - self.read_dir_sync(&path) - } - - fn rename_sync(&self, _oldpath: &Path, _newpath: &Path) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn rename_async( - &self, - oldpath: PathBuf, - newpath: PathBuf, - ) -> FsResult<()> { - self.rename_sync(&oldpath, &newpath) - } - - fn link_sync(&self, _oldpath: &Path, _newpath: &Path) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn link_async( - &self, - oldpath: PathBuf, - newpath: PathBuf, - ) -> FsResult<()> { - self.link_sync(&oldpath, &newpath) - } - - fn symlink_sync( - &self, - _oldpath: &Path, - _newpath: &Path, - _file_type: Option, - ) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn symlink_async( - &self, - oldpath: PathBuf, - newpath: PathBuf, - file_type: Option, - ) -> FsResult<()> { - self.symlink_sync(&oldpath, &newpath, file_type) - } - - fn read_link_sync(&self, _path: &Path) -> FsResult { - Err(FsError::NotSupported) - } - async fn read_link_async(&self, path: PathBuf) -> FsResult { - self.read_link_sync(&path) - } - - fn truncate_sync(&self, _path: &Path, _len: u64) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn truncate_async(&self, path: PathBuf, len: u64) -> FsResult<()> { - self.truncate_sync(&path, len) - } - - fn utime_sync( - &self, - _path: &Path, - _atime_secs: i64, - _atime_nanos: u32, - _mtime_secs: i64, - _mtime_nanos: u32, - ) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn utime_async( - &self, - path: PathBuf, - atime_secs: i64, - atime_nanos: u32, - mtime_secs: i64, - mtime_nanos: u32, - ) -> FsResult<()> { - self.utime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos) - } - - fn lutime_sync( - &self, - _path: &Path, - _atime_secs: i64, - _atime_nanos: u32, - _mtime_secs: i64, - _mtime_nanos: u32, - ) -> FsResult<()> { - Err(FsError::NotSupported) - } - async fn lutime_async( - &self, - path: PathBuf, - atime_secs: i64, - atime_nanos: u32, - mtime_secs: i64, - mtime_nanos: u32, - ) -> FsResult<()> { - self.lutime_sync(&path, atime_secs, atime_nanos, mtime_secs, mtime_nanos) - } - - fn write_file_sync( - &self, - path: &Path, - options: OpenOptions, - _access_check: Option, - data: &[u8], - ) -> FsResult<()> { - let path = normalize_path(path); - let has_parent_dir = path - .parent() - .and_then(|parent| self.get_entry(parent)) - .map(|e| matches!(*e, PathEntry::Dir)) - .unwrap_or(false); - if !has_parent_dir { - return Err(FsError::Io(Error::new( - ErrorKind::NotFound, - "Parent directory does not exist", - ))); - } - let mut entries = self.entries.lock(); - let entry = entries.entry(path.clone()); - match entry { - Entry::Occupied(mut entry) => { - if let PathEntry::File(existing_data) = &**entry.get() { - if options.create_new { - return Err(FsError::Io(Error::new( - ErrorKind::AlreadyExists, - "File already exists", - ))); - } - if options.append { - let mut new_data = existing_data.clone(); - new_data.extend_from_slice(data); - entry.insert(Arc::new(PathEntry::File(new_data))); - } else { - entry.insert(Arc::new(PathEntry::File(data.to_vec()))); - } - Ok(()) - } else { - Err(FsError::Io(Error::new( - ErrorKind::InvalidInput, - "Not a file", - ))) - } - } - Entry::Vacant(entry) => { - entry.insert(Arc::new(PathEntry::File(data.to_vec()))); - Ok(()) - } - } - } - - async fn write_file_async<'a>( - &'a self, - path: PathBuf, - options: OpenOptions, - access_check: Option>, - data: Vec, - ) -> FsResult<()> { - self.write_file_sync(&path, options, access_check, &data) - } - - fn read_file_sync( - &self, - path: &Path, - _access_check: Option, - ) -> FsResult> { - let entry = self.get_entry(path); - match entry { - Some(entry) => match &*entry { - PathEntry::File(data) => Ok(Cow::Owned(data.clone())), - PathEntry::Dir => Err(FsError::Io(Error::new( - ErrorKind::InvalidInput, - "Is a directory", - ))), - }, - None => Err(FsError::Io(Error::new(ErrorKind::NotFound, "Not found"))), - } - } - async fn read_file_async<'a>( - &'a self, - path: PathBuf, - access_check: Option>, - ) -> FsResult> { - self.read_file_sync(&path, access_check) - } -} diff --git a/ext/fs/interface.rs b/ext/fs/interface.rs index 304c263614..0e753d684c 100644 --- a/ext/fs/interface.rs +++ b/ext/fs/interface.rs @@ -5,8 +5,6 @@ use std::borrow::Cow; use std::path::Path; use std::path::PathBuf; use std::rc::Rc; -use std::time::Duration; -use std::time::SystemTime; use serde::Deserialize; use serde::Serialize; @@ -14,8 +12,6 @@ use serde::Serialize; use deno_io::fs::File; use deno_io::fs::FsResult; use deno_io::fs::FsStat; -use sys_traits::FsFile; -use sys_traits::FsFileSetPermissions; use crate::sync::MaybeSend; use crate::sync::MaybeSync; @@ -75,7 +71,7 @@ pub enum FsFileType { } /// WARNING: This is part of the public JS Deno API. -#[derive(Debug, Serialize)] +#[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] pub struct FsDirEntry { pub name: String, @@ -104,56 +100,6 @@ impl AccessCheckFn for T where { } -#[derive(Debug)] -pub struct FsStatSlim { - file_type: sys_traits::FileType, - modified: Result, -} - -impl FsStatSlim { - pub fn from_std(metadata: &std::fs::Metadata) -> Self { - Self { - file_type: metadata.file_type().into(), - modified: metadata.modified(), - } - } - - pub fn from_deno_fs_stat(data: &FsStat) -> Self { - FsStatSlim { - file_type: if data.is_file { - sys_traits::FileType::File - } else if data.is_directory { - sys_traits::FileType::Dir - } else if data.is_symlink { - sys_traits::FileType::Symlink - } else { - sys_traits::FileType::Unknown - }, - modified: data - .mtime - .map(|ms| SystemTime::UNIX_EPOCH + Duration::from_millis(ms)) - .ok_or_else(|| { - std::io::Error::new(std::io::ErrorKind::InvalidData, "No mtime") - }), - } - } -} - -impl sys_traits::FsMetadataValue for FsStatSlim { - #[inline] - fn file_type(&self) -> sys_traits::FileType { - self.file_type - } - - fn modified(&self) -> Result { - self - .modified - .as_ref() - .copied() - .map_err(|err| std::io::Error::new(err.kind(), err.to_string())) - } -} - pub type AccessCheckCb<'a> = &'a mut (dyn AccessCheckFn + 'a); #[async_trait::async_trait(?Send)] @@ -415,289 +361,3 @@ fn string_from_utf8_lossy(buf: Vec) -> String { Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(buf) }, } } - -// todo(dsherret): this is temporary. Instead of using the `FileSystem` trait implementation -// in the CLI, the CLI should instead create it's own file system using `sys_traits` traits -// then that can implement the `FileSystem` trait. Then this `FileSystem` trait can stay here -// for use only for `ext/fs` and not the entire CLI. -#[derive(Debug, Clone)] -pub struct FsSysTraitsAdapter(pub FileSystemRc); - -impl FsSysTraitsAdapter { - pub fn new_real() -> Self { - Self(crate::sync::new_rc(crate::RealFs)) - } -} - -impl sys_traits::BaseFsHardLink for FsSysTraitsAdapter { - #[inline] - fn base_fs_hard_link(&self, src: &Path, dst: &Path) -> std::io::Result<()> { - self - .0 - .link_sync(src, dst) - .map_err(|err| err.into_io_error()) - } -} - -impl sys_traits::BaseFsRead for FsSysTraitsAdapter { - #[inline] - fn base_fs_read(&self, path: &Path) -> std::io::Result> { - self - .0 - .read_file_sync(path, None) - .map_err(|err| err.into_io_error()) - } -} - -#[derive(Debug)] -pub struct FsSysTraitsAdapterReadDirEntry { - path: PathBuf, - entry: FsDirEntry, -} - -impl sys_traits::FsDirEntry for FsSysTraitsAdapterReadDirEntry { - type Metadata = FsStatSlim; - - fn file_name(&self) -> Cow { - Cow::Borrowed(self.entry.name.as_ref()) - } - - fn file_type(&self) -> std::io::Result { - if self.entry.is_file { - Ok(sys_traits::FileType::File) - } else if self.entry.is_directory { - Ok(sys_traits::FileType::Dir) - } else if self.entry.is_symlink { - Ok(sys_traits::FileType::Symlink) - } else { - Ok(sys_traits::FileType::Unknown) - } - } - - fn metadata(&self) -> std::io::Result { - Ok(FsStatSlim { - file_type: self.file_type().unwrap(), - modified: Err(std::io::Error::new( - std::io::ErrorKind::Other, - "not supported", - )), - }) - } - - fn path(&self) -> Cow { - Cow::Borrowed(&self.path) - } -} - -impl sys_traits::BaseFsReadDir for FsSysTraitsAdapter { - type ReadDirEntry = FsSysTraitsAdapterReadDirEntry; - - fn base_fs_read_dir( - &self, - path: &Path, - ) -> std::io::Result< - Box>>, - > { - // todo(dsherret): needs to actually be iterable and not allocate a vector - let entries = self - .0 - .read_dir_sync(path) - .map_err(|err| err.into_io_error())?; - let parent_dir = path.to_path_buf(); - Ok(Box::new(entries.into_iter().map(move |entry| { - Ok(FsSysTraitsAdapterReadDirEntry { - path: parent_dir.join(&entry.name), - entry, - }) - }))) - } -} - -impl sys_traits::BaseFsCanonicalize for FsSysTraitsAdapter { - #[inline] - fn base_fs_canonicalize(&self, path: &Path) -> std::io::Result { - self - .0 - .realpath_sync(path) - .map_err(|err| err.into_io_error()) - } -} - -impl sys_traits::BaseFsMetadata for FsSysTraitsAdapter { - type Metadata = FsStatSlim; - - #[inline] - fn base_fs_metadata(&self, path: &Path) -> std::io::Result { - self - .0 - .stat_sync(path) - .map(|data| FsStatSlim::from_deno_fs_stat(&data)) - .map_err(|err| err.into_io_error()) - } - - #[inline] - fn base_fs_symlink_metadata( - &self, - path: &Path, - ) -> std::io::Result { - self - .0 - .lstat_sync(path) - .map(|data| FsStatSlim::from_deno_fs_stat(&data)) - .map_err(|err| err.into_io_error()) - } -} - -impl sys_traits::BaseFsCreateDir for FsSysTraitsAdapter { - #[inline] - fn base_fs_create_dir( - &self, - path: &Path, - options: &sys_traits::CreateDirOptions, - ) -> std::io::Result<()> { - self - .0 - .mkdir_sync(path, options.recursive, options.mode) - .map_err(|err| err.into_io_error()) - } -} - -impl sys_traits::BaseFsRemoveFile for FsSysTraitsAdapter { - #[inline] - fn base_fs_remove_file(&self, path: &Path) -> std::io::Result<()> { - self - .0 - .remove_sync(path, false) - .map_err(|err| err.into_io_error()) - } -} - -impl sys_traits::BaseFsRename for FsSysTraitsAdapter { - #[inline] - fn base_fs_rename(&self, from: &Path, to: &Path) -> std::io::Result<()> { - self - .0 - .rename_sync(from, to) - .map_err(|err| err.into_io_error()) - } -} - -pub struct FsFileAdapter(pub Rc); - -impl FsFile for FsFileAdapter {} - -impl FsFileSetPermissions for FsFileAdapter { - #[inline] - fn fs_file_set_permissions(&mut self, mode: u32) -> std::io::Result<()> { - if cfg!(windows) { - Ok(()) // ignore - } else { - self - .0 - .clone() - .chmod_sync(mode) - .map_err(|err| err.into_io_error()) - } - } -} - -impl std::io::Read for FsFileAdapter { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - self - .0 - .clone() - .read_sync(buf) - .map_err(|err| err.into_io_error()) - } -} - -impl std::io::Seek for FsFileAdapter { - fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { - self - .0 - .clone() - .seek_sync(pos) - .map_err(|err| err.into_io_error()) - } -} - -impl std::io::Write for FsFileAdapter { - #[inline] - fn write(&mut self, buf: &[u8]) -> std::io::Result { - self - .0 - .clone() - .write_sync(buf) - .map_err(|err| err.into_io_error()) - } - - #[inline] - fn flush(&mut self) -> std::io::Result<()> { - self - .0 - .clone() - .sync_sync() - .map_err(|err| err.into_io_error()) - } -} - -impl sys_traits::BaseFsOpen for FsSysTraitsAdapter { - type File = FsFileAdapter; - - fn base_fs_open( - &self, - path: &Path, - options: &sys_traits::OpenOptions, - ) -> std::io::Result { - self - .0 - .open_sync( - path, - OpenOptions { - read: options.read, - write: options.write, - create: options.create, - truncate: options.truncate, - append: options.append, - create_new: options.create_new, - mode: options.mode, - }, - None, - ) - .map(FsFileAdapter) - .map_err(|err| err.into_io_error()) - } -} - -impl sys_traits::SystemRandom for FsSysTraitsAdapter { - #[inline] - fn sys_random(&self, buf: &mut [u8]) -> std::io::Result<()> { - getrandom::getrandom(buf).map_err(|err| { - std::io::Error::new(std::io::ErrorKind::Other, err.to_string()) - }) - } -} - -impl sys_traits::SystemTimeNow for FsSysTraitsAdapter { - #[inline] - fn sys_time_now(&self) -> SystemTime { - SystemTime::now() - } -} - -impl sys_traits::ThreadSleep for FsSysTraitsAdapter { - #[inline] - fn thread_sleep(&self, dur: Duration) { - std::thread::sleep(dur); - } -} - -impl sys_traits::BaseEnvVar for FsSysTraitsAdapter { - fn base_env_var_os( - &self, - key: &std::ffi::OsStr, - ) -> Option { - std::env::var_os(key) - } -} diff --git a/ext/fs/lib.rs b/ext/fs/lib.rs index cfcf249783..360400df0d 100644 --- a/ext/fs/lib.rs +++ b/ext/fs/lib.rs @@ -1,25 +1,20 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -mod in_memory_fs; mod interface; mod ops; mod std_fs; pub mod sync; -pub use crate::in_memory_fs::InMemoryFs; pub use crate::interface::AccessCheckCb; pub use crate::interface::AccessCheckFn; pub use crate::interface::FileSystem; pub use crate::interface::FileSystemRc; pub use crate::interface::FsDirEntry; pub use crate::interface::FsFileType; -pub use crate::interface::FsStatSlim; -pub use crate::interface::FsSysTraitsAdapter; pub use crate::interface::OpenOptions; pub use crate::ops::FsOpsError; pub use crate::ops::FsOpsErrorKind; pub use crate::ops::OperationError; -pub use crate::ops::V8MaybeStaticStr; pub use crate::std_fs::RealFs; pub use crate::sync::MaybeSend; pub use crate::sync::MaybeSync; diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs index 521ff65471..ac0a8901d7 100644 --- a/ext/fs/ops.rs +++ b/ext/fs/ops.rs @@ -19,7 +19,6 @@ use crate::FsPermissions; use crate::OpenOptions; use boxed_error::Boxed; use deno_core::op2; -use deno_core::v8; use deno_core::CancelFuture; use deno_core::CancelHandle; use deno_core::FastString; @@ -27,7 +26,6 @@ use deno_core::JsBuffer; use deno_core::OpState; use deno_core::ResourceId; use deno_core::ToJsBuffer; -use deno_core::ToV8; use deno_io::fs::FileResource; use deno_io::fs::FsError; use deno_io::fs::FsStat; @@ -1384,51 +1382,12 @@ where Ok(buf.into_owned().into_boxed_slice().into()) } -// todo(https://github.com/denoland/deno_core/pull/986): remove -// when upgrading deno_core -#[derive(Debug)] -pub struct FastStringV8AllocationError; - -impl std::error::Error for FastStringV8AllocationError {} - -impl std::fmt::Display for FastStringV8AllocationError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "failed to allocate string; buffer exceeds maximum length" - ) - } -} - -/// Maintains a static reference to the string if possible. -pub struct V8MaybeStaticStr(pub Cow<'static, str>); - -impl<'s> ToV8<'s> for V8MaybeStaticStr { - type Error = FastStringV8AllocationError; - - #[inline] - fn to_v8( - self, - scope: &mut v8::HandleScope<'s>, - ) -> Result, Self::Error> { - Ok( - match self.0 { - Cow::Borrowed(text) => FastString::from_static(text), - Cow::Owned(value) => value.into(), - } - .v8_string(scope) - .map_err(|_| FastStringV8AllocationError)? - .into(), - ) - } -} - #[op2(stack_trace)] #[to_v8] pub fn op_fs_read_file_text_sync

( state: &mut OpState, #[string] path: String, -) -> Result +) -> Result where P: FsPermissions + 'static, { @@ -1440,7 +1399,10 @@ where let str = fs .read_text_file_lossy_sync(&path, Some(&mut access_check)) .map_err(|error| map_permission_error("readfile", error, &path))?; - Ok(V8MaybeStaticStr(str)) + Ok(match str { + Cow::Borrowed(text) => FastString::from_static(text), + Cow::Owned(value) => value.into(), + }) } #[op2(async, stack_trace)] @@ -1449,7 +1411,7 @@ pub async fn op_fs_read_file_text_async

( state: Rc>, #[string] path: String, #[smi] cancel_rid: Option, -) -> Result +) -> Result where P: FsPermissions + 'static, { @@ -1483,7 +1445,10 @@ where .map_err(|error| map_permission_error("readfile", error, &path))? }; - Ok(V8MaybeStaticStr(str)) + Ok(match str { + Cow::Borrowed(text) => FastString::from_static(text), + Cow::Owned(value) => value.into(), + }) } fn to_seek_from(offset: i64, whence: i32) -> Result { diff --git a/ext/fs/std_fs.rs b/ext/fs/std_fs.rs index 76d37e430c..a1549196dd 100644 --- a/ext/fs/std_fs.rs +++ b/ext/fs/std_fs.rs @@ -26,7 +26,7 @@ use crate::interface::FsFileType; use crate::FileSystem; use crate::OpenOptions; -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct RealFs; #[async_trait::async_trait(?Send)] diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 50e72dfcbe..82478e7f7c 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -14,7 +14,7 @@ description = "Node compatibility for Deno" path = "lib.rs" [features] -sync_fs = ["deno_package_json/sync", "node_resolver/sync"] +sync_fs = ["deno_fs/sync_fs", "deno_package_json/sync", "node_resolver/sync"] [dependencies] aead-gcm-stream = "0.4" @@ -93,6 +93,7 @@ simd-json = "0.14.0" sm3 = "0.4.2" spki.workspace = true stable_deref_trait = "1.2.0" +sys_traits = { workspace = true, features = ["real"] } thiserror.workspace = true tokio.workspace = true tokio-eld = "0.2" diff --git a/ext/node/lib.rs b/ext/node/lib.rs index 0c4791eb72..740cc3c136 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -14,10 +14,10 @@ use deno_core::url::Url; #[allow(unused_imports)] use deno_core::v8; use deno_core::v8::ExternalReference; -use deno_fs::FsSysTraitsAdapter; use node_resolver::errors::ClosestPkgJsonError; use node_resolver::IsBuiltInNodeModuleChecker; use node_resolver::NpmPackageFolderResolverRc; +use node_resolver::PackageJsonResolverRc; use once_cell::sync::Lazy; extern crate libz_sys as zlib; @@ -185,16 +185,17 @@ fn op_node_build_os() -> String { } #[derive(Clone)] -pub struct NodeExtInitServices { +pub struct NodeExtInitServices { pub node_require_loader: NodeRequireLoaderRc, - pub node_resolver: NodeResolverRc, + pub node_resolver: NodeResolverRc, pub npm_resolver: NpmPackageFolderResolverRc, - pub pkg_json_resolver: PackageJsonResolverRc, + pub pkg_json_resolver: PackageJsonResolverRc, + pub sys: TSys, } deno_core::extension!(deno_node, deps = [ deno_io, deno_fs ], - parameters = [P: NodePermissions], + parameters = [P: NodePermissions, TSys: ExtNodeSys], ops = [ ops::blocklist::op_socket_address_parse, ops::blocklist::op_socket_address_get_serialization, @@ -392,29 +393,29 @@ deno_core::extension!(deno_node, op_node_build_os, ops::require::op_require_can_parse_as_esm, ops::require::op_require_init_paths, - ops::require::op_require_node_module_paths

, + ops::require::op_require_node_module_paths, ops::require::op_require_proxy_path, - ops::require::op_require_is_deno_dir_package, + ops::require::op_require_is_deno_dir_package, ops::require::op_require_resolve_deno_dir, ops::require::op_require_is_maybe_cjs, ops::require::op_require_is_request_relative, ops::require::op_require_resolve_lookup_paths, - ops::require::op_require_try_self_parent_path

, - ops::require::op_require_try_self

, - ops::require::op_require_real_path

, + ops::require::op_require_try_self_parent_path, + ops::require::op_require_try_self, + ops::require::op_require_real_path, ops::require::op_require_path_is_absolute, ops::require::op_require_path_dirname, - ops::require::op_require_stat

, + ops::require::op_require_stat, ops::require::op_require_path_resolve, ops::require::op_require_path_basename, ops::require::op_require_read_file

, ops::require::op_require_as_file_path, - ops::require::op_require_resolve_exports

, - ops::require::op_require_read_package_scope

, - ops::require::op_require_package_imports_resolve

, + ops::require::op_require_resolve_exports, + ops::require::op_require_read_package_scope, + ops::require::op_require_package_imports_resolve, ops::require::op_require_break_on_next_statement, ops::util::op_node_guess_handle_type, - ops::worker_threads::op_worker_threads_filename

, + ops::worker_threads::op_worker_threads_filename, ops::ipc::op_node_child_ipc_pipe, ops::ipc::op_node_ipc_write, ops::ipc::op_node_ipc_read, @@ -680,13 +681,14 @@ deno_core::extension!(deno_node, "node:zlib" = "zlib.ts", ], options = { - maybe_init: Option, + maybe_init: Option>, fs: deno_fs::FileSystemRc, }, state = |state, options| { state.put(options.fs.clone()); if let Some(init) = &options.maybe_init { + state.put(init.sys.clone()); state.put(init.node_require_loader.clone()); state.put(init.node_resolver.clone()); state.put(init.npm_resolver.clone()); @@ -820,18 +822,22 @@ impl IsBuiltInNodeModuleChecker for RealIsBuiltInNodeModuleChecker { } } -pub type NodeResolver = node_resolver::NodeResolver< - RealIsBuiltInNodeModuleChecker, - FsSysTraitsAdapter, ->; +pub trait ExtNodeSys: + sys_traits::BaseFsCanonicalize + + sys_traits::BaseFsMetadata + + sys_traits::BaseFsRead + + sys_traits::EnvCurrentDir + + Clone +{ +} + +impl ExtNodeSys for sys_traits::impls::RealSys {} + +pub type NodeResolver = + node_resolver::NodeResolver; #[allow(clippy::disallowed_types)] -pub type NodeResolverRc = deno_fs::sync::MaybeArc; -pub type PackageJsonResolver = - node_resolver::PackageJsonResolver; +pub type NodeResolverRc = deno_fs::sync::MaybeArc>; #[allow(clippy::disallowed_types)] -pub type PackageJsonResolverRc = deno_fs::sync::MaybeArc< - node_resolver::PackageJsonResolver, ->; pub fn create_host_defined_options<'s>( scope: &mut v8::HandleScope<'s>, diff --git a/ext/node/ops/require.rs b/ext/node/ops/require.rs index ddcdec0bbd..c5e3afa87d 100644 --- a/ext/node/ops/require.rs +++ b/ext/node/ops/require.rs @@ -1,14 +1,19 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::borrow::Cow; +use std::cell::RefCell; +use std::path::Path; +use std::path::PathBuf; +use std::rc::Rc; + use boxed_error::Boxed; use deno_core::error::AnyError; use deno_core::op2; use deno_core::url::Url; use deno_core::v8; +use deno_core::FastString; use deno_core::JsRuntimeInspector; use deno_core::OpState; -use deno_fs::FileSystemRc; -use deno_fs::V8MaybeStaticStr; use deno_package_json::PackageJsonRc; use deno_path_util::normalize_path; use deno_path_util::url_from_file_path; @@ -17,12 +22,11 @@ use node_resolver::errors::ClosestPkgJsonError; use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; use node_resolver::REQUIRE_CONDITIONS; -use std::borrow::Cow; -use std::cell::RefCell; -use std::path::Path; -use std::path::PathBuf; -use std::rc::Rc; +use sys_traits::FsCanonicalize; +use sys_traits::FsMetadata; +use sys_traits::FsMetadataValue; +use crate::ExtNodeSys; use crate::NodePermissions; use crate::NodeRequireLoaderRc; use crate::NodeResolverRc; @@ -68,11 +72,11 @@ pub enum RequireErrorKind { #[error(transparent)] UrlConversion(#[from] deno_path_util::PathToUrlError), #[error(transparent)] - Fs(#[from] deno_io::fs::FsError), + Fs(#[from] std::io::Error), #[error(transparent)] ReadModule(deno_core::error::AnyError), #[error("Unable to get CWD: {0}")] - UnableToGetCwd(deno_io::fs::FsError), + UnableToGetCwd(std::io::Error), } #[op2] @@ -128,19 +132,21 @@ pub fn op_require_init_paths() -> Vec { #[op2(stack_trace)] #[serde] -pub fn op_require_node_module_paths

( +pub fn op_require_node_module_paths< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] from: String, -) -> Result, RequireError> -where - P: NodePermissions + 'static, -{ - let fs = state.borrow::(); +) -> Result, RequireError> { + let sys = state.borrow::(); // Guarantee that "from" is absolute. let from = if from.starts_with("file:///") { url_to_file_path(&Url::parse(&from)?)? } else { - let current_dir = &fs.cwd().map_err(RequireErrorKind::UnableToGetCwd)?; + let current_dir = &sys + .env_current_dir() + .map_err(RequireErrorKind::UnableToGetCwd)?; normalize_path(current_dir.join(from)) }; @@ -238,11 +244,11 @@ pub fn op_require_resolve_deno_dir( } #[op2(fast)] -pub fn op_require_is_deno_dir_package( +pub fn op_require_is_deno_dir_package( state: &mut OpState, #[string] path: String, ) -> bool { - let resolver = state.borrow::(); + let resolver = state.borrow::>(); match deno_path_util::url_from_file_path(&PathBuf::from(path)) { Ok(specifier) => resolver.in_npm_package(&specifier), Err(_) => false, @@ -297,18 +303,18 @@ pub fn op_require_path_is_absolute(#[string] p: String) -> bool { } #[op2(fast, stack_trace)] -pub fn op_require_stat

( +pub fn op_require_stat< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] path: String, -) -> Result -where - P: NodePermissions + 'static, -{ +) -> Result { let path = PathBuf::from(path); let path = ensure_read_permission::

(state, &path)?; - let fs = state.borrow::(); - if let Ok(metadata) = fs.stat_sync(&path) { - if metadata.is_file { + let sys = state.borrow::(); + if let Ok(metadata) = sys.fs_metadata(&path) { + if metadata.file_type().is_file() { return Ok(0); } else { return Ok(1); @@ -320,19 +326,19 @@ where #[op2(stack_trace)] #[string] -pub fn op_require_real_path

( +pub fn op_require_real_path< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] request: String, -) -> Result -where - P: NodePermissions + 'static, -{ +) -> Result { let path = PathBuf::from(request); let path = ensure_read_permission::

(state, &path) .map_err(RequireErrorKind::Permission)?; - let fs = state.borrow::(); + let sys = state.borrow::(); let canonicalized_path = - deno_path_util::strip_unc_prefix(fs.realpath_sync(&path)?); + deno_path_util::strip_unc_prefix(sys.fs_canonicalize(&path)?); Ok(canonicalized_path.to_string_lossy().into_owned()) } @@ -384,15 +390,15 @@ pub fn op_require_path_basename( #[op2(stack_trace)] #[string] -pub fn op_require_try_self_parent_path

( +pub fn op_require_try_self_parent_path< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, has_parent: bool, #[string] maybe_parent_filename: Option, #[string] maybe_parent_id: Option, -) -> Result, deno_core::error::AnyError> -where - P: NodePermissions + 'static, -{ +) -> Result, deno_core::error::AnyError> { if !has_parent { return Ok(None); } @@ -403,8 +409,8 @@ where if let Some(parent_id) = maybe_parent_id { if parent_id == "" || parent_id == "internal/preload" { - let fs = state.borrow::(); - if let Ok(cwd) = fs.cwd() { + let sys = state.borrow::(); + if let Ok(cwd) = sys.env_current_dir() { let cwd = ensure_read_permission::

(state, &cwd)?; return Ok(Some(cwd.to_string_lossy().into_owned())); } @@ -415,19 +421,19 @@ where #[op2(stack_trace)] #[string] -pub fn op_require_try_self

( +pub fn op_require_try_self< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] parent_path: Option, #[string] request: String, -) -> Result, RequireError> -where - P: NodePermissions + 'static, -{ +) -> Result, RequireError> { if parent_path.is_none() { return Ok(None); } - let pkg_json_resolver = state.borrow::(); + let pkg_json_resolver = state.borrow::>(); let pkg = pkg_json_resolver .get_closest_package_json_from_file_path(&PathBuf::from( parent_path.unwrap(), @@ -459,7 +465,7 @@ where let referrer = deno_core::url::Url::from_file_path(&pkg.path).unwrap(); if let Some(exports) = &pkg.exports { - let node_resolver = state.borrow::(); + let node_resolver = state.borrow::>(); let r = node_resolver.package_exports_resolve( &pkg.path, &expansion, @@ -484,7 +490,7 @@ where pub fn op_require_read_file

( state: &mut OpState, #[string] file_path: String, -) -> Result +) -> Result where P: NodePermissions + 'static, { @@ -495,7 +501,10 @@ where let loader = state.borrow::(); loader .load_text_file_lossy(&file_path) - .map(V8MaybeStaticStr) + .map(|s| match s { + Cow::Borrowed(s) => FastString::from_static(s), + Cow::Owned(s) => s.into(), + }) .map_err(|e| RequireErrorKind::ReadModule(e).into_box()) } @@ -513,7 +522,10 @@ pub fn op_require_as_file_path(#[string] file_or_url: String) -> String { #[op2(stack_trace)] #[string] -pub fn op_require_resolve_exports

( +pub fn op_require_resolve_exports< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, uses_local_node_modules_dir: bool, #[string] modules_path_str: String, @@ -521,13 +533,10 @@ pub fn op_require_resolve_exports

( #[string] name: String, #[string] expansion: String, #[string] parent_path: String, -) -> Result, RequireError> -where - P: NodePermissions + 'static, -{ - let fs = state.borrow::(); - let node_resolver = state.borrow::(); - let pkg_json_resolver = state.borrow::(); +) -> Result, RequireError> { + let sys = state.borrow::(); + let node_resolver = state.borrow::>(); + let pkg_json_resolver = state.borrow::>(); let modules_path = PathBuf::from(&modules_path_str); let modules_specifier = deno_path_util::url_from_file_path(&modules_path)?; @@ -538,7 +547,7 @@ where } else { let mod_dir = path_resolve([modules_path_str.as_str(), name.as_str()].into_iter()); - if fs.is_dir_sync(&mod_dir) { + if sys.fs_is_dir_no_err(&mod_dir) { mod_dir } else { modules_path @@ -589,14 +598,14 @@ pub fn op_require_is_maybe_cjs( #[op2(stack_trace)] #[serde] -pub fn op_require_read_package_scope

( +pub fn op_require_read_package_scope< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] package_json_path: String, -) -> Option -where - P: NodePermissions + 'static, -{ - let pkg_json_resolver = state.borrow::(); +) -> Option { + let pkg_json_resolver = state.borrow::>(); let package_json_path = PathBuf::from(package_json_path); if package_json_path.file_name() != Some("package.json".as_ref()) { // permissions: do not allow reading a non-package.json file @@ -610,18 +619,18 @@ where #[op2(stack_trace)] #[string] -pub fn op_require_package_imports_resolve

( +pub fn op_require_package_imports_resolve< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] referrer_filename: String, #[string] request: String, -) -> Result, RequireError> -where - P: NodePermissions + 'static, -{ +) -> Result, RequireError> { let referrer_path = PathBuf::from(&referrer_filename); let referrer_path = ensure_read_permission::

(state, &referrer_path) .map_err(RequireErrorKind::Permission)?; - let pkg_json_resolver = state.borrow::(); + let pkg_json_resolver = state.borrow::>(); let Some(pkg) = pkg_json_resolver .get_closest_package_json_from_file_path(&referrer_path)? else { @@ -629,7 +638,7 @@ where }; if pkg.imports.is_some() { - let node_resolver = state.borrow::(); + let node_resolver = state.borrow::>(); let referrer_url = Url::from_file_path(&referrer_filename).unwrap(); let url = node_resolver.package_imports_resolve( &request, diff --git a/ext/node/ops/worker_threads.rs b/ext/node/ops/worker_threads.rs index 37a7b477d0..48683be1e7 100644 --- a/ext/node/ops/worker_threads.rs +++ b/ext/node/ops/worker_threads.rs @@ -1,13 +1,16 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::op2; -use deno_core::url::Url; -use deno_core::OpState; -use deno_fs::FileSystemRc; use std::borrow::Cow; use std::path::Path; use std::path::PathBuf; +use deno_core::op2; +use deno_core::url::Url; +use deno_core::OpState; +use sys_traits::FsCanonicalize; +use sys_traits::FsMetadata; + +use crate::ExtNodeSys; use crate::NodePermissions; use crate::NodeRequireLoaderRc; @@ -41,19 +44,19 @@ pub enum WorkerThreadsFilenameError { #[error("File not found [{0:?}]")] FileNotFound(PathBuf), #[error(transparent)] - Fs(#[from] deno_io::fs::FsError), + Fs(#[from] std::io::Error), } // todo(dsherret): we should remove this and do all this work inside op_create_worker #[op2(stack_trace)] #[string] -pub fn op_worker_threads_filename

( +pub fn op_worker_threads_filename< + P: NodePermissions + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] specifier: String, -) -> Result -where - P: NodePermissions + 'static, -{ +) -> Result { if specifier.starts_with("data:") { return Ok(specifier); } @@ -66,9 +69,9 @@ where } let path = ensure_read_permission::

(state, &path) .map_err(WorkerThreadsFilenameError::Permission)?; - let fs = state.borrow::(); + let sys = state.borrow::(); let canonicalized_path = - deno_path_util::strip_unc_prefix(fs.realpath_sync(&path)?); + deno_path_util::strip_unc_prefix(sys.fs_canonicalize(&path)?); Url::from_file_path(canonicalized_path) .map_err(|_| WorkerThreadsFilenameError::UrlFromPathString)? }; @@ -77,8 +80,8 @@ where .map_err(|_| WorkerThreadsFilenameError::UrlToPathString)?; let url_path = ensure_read_permission::

(state, &url_path) .map_err(WorkerThreadsFilenameError::Permission)?; - let fs = state.borrow::(); - if !fs.exists_sync(&url_path) { + let sys = state.borrow::(); + if !sys.fs_exists_no_err(&url_path) { return Err(WorkerThreadsFilenameError::FileNotFound( url_path.to_path_buf(), )); diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 4612e87887..ca21547efc 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -122,6 +122,7 @@ 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 tokio.workspace = true diff --git a/runtime/errors.rs b/runtime/errors.rs index 3f8e900851..01588c593b 100644 --- a/runtime/errors.rs +++ b/runtime/errors.rs @@ -1157,7 +1157,7 @@ mod node { WorkerThreadsFilenameError::UrlToPathString => "Error", WorkerThreadsFilenameError::UrlToPath => "Error", WorkerThreadsFilenameError::FileNotFound(_) => "Error", - WorkerThreadsFilenameError::Fs(e) => super::get_fs_error(e), + WorkerThreadsFilenameError::Fs(e) => super::get_io_error_class(e), } } @@ -1173,7 +1173,7 @@ mod node { | UrlConversion(_) | ReadModule(_) | PackageImportsResolve(_) => "Error", - Fs(e) | UnableToGetCwd(e) => super::get_fs_error(e), + Fs(e) | UnableToGetCwd(e) => super::get_io_error_class(e), } } diff --git a/runtime/examples/extension/main.rs b/runtime/examples/extension/main.rs index 1ff16ec83f..a4ac85bf5e 100644 --- a/runtime/examples/extension/main.rs +++ b/runtime/examples/extension/main.rs @@ -37,11 +37,12 @@ async fn main() -> Result<(), AnyError> { let main_module = ModuleSpecifier::from_file_path(js_path).unwrap(); eprintln!("Running {main_module}..."); let fs = Arc::new(RealFs); - let permission_desc_parser = - Arc::new(RuntimePermissionDescriptorParser::new(fs.clone())); + let permission_desc_parser = Arc::new( + RuntimePermissionDescriptorParser::new(sys_traits::impls::RealSys), + ); let mut worker = MainWorker::bootstrap_from_options( main_module.clone(), - WorkerServiceOptions { + WorkerServiceOptions:: { module_loader: Rc::new(FsModuleLoader), permissions: PermissionsContainer::allow_all(permission_desc_parser), blob_store: Default::default(), diff --git a/runtime/permissions.rs b/runtime/permissions.rs index e8460e03f8..968c41560c 100644 --- a/runtime/permissions.rs +++ b/runtime/permissions.rs @@ -21,13 +21,17 @@ use deno_permissions::SysDescriptorParseError; use deno_permissions::WriteDescriptor; #[derive(Debug)] -pub struct RuntimePermissionDescriptorParser { - fs: deno_fs::FileSystemRc, +pub struct RuntimePermissionDescriptorParser< + TSys: sys_traits::EnvCurrentDir + Send + Sync, +> { + sys: TSys, } -impl RuntimePermissionDescriptorParser { - pub fn new(fs: deno_fs::FileSystemRc) -> Self { - Self { fs } +impl + RuntimePermissionDescriptorParser +{ + pub fn new(sys: TSys) -> Self { + Self { sys } } fn resolve_from_cwd(&self, path: &str) -> Result { @@ -45,14 +49,15 @@ impl RuntimePermissionDescriptorParser { fn resolve_cwd(&self) -> Result { self - .fs - .cwd() - .map_err(|e| PathResolveError::CwdResolve(e.into_io_error())) + .sys + .env_current_dir() + .map_err(PathResolveError::CwdResolve) } } -impl deno_permissions::PermissionDescriptorParser - for RuntimePermissionDescriptorParser +impl + deno_permissions::PermissionDescriptorParser + for RuntimePermissionDescriptorParser { fn parse_read_descriptor( &self, @@ -151,16 +156,14 @@ impl deno_permissions::PermissionDescriptorParser #[cfg(test)] mod test { - use std::sync::Arc; - - use deno_fs::RealFs; use deno_permissions::PermissionDescriptorParser; use super::*; #[test] fn test_handle_empty_value() { - let parser = RuntimePermissionDescriptorParser::new(Arc::new(RealFs)); + let parser = + RuntimePermissionDescriptorParser::new(sys_traits::impls::RealSys); assert!(parser.parse_read_descriptor("").is_err()); assert!(parser.parse_write_descriptor("").is_err()); assert!(parser.parse_env_descriptor("").is_err()); diff --git a/runtime/snapshot.rs b/runtime/snapshot.rs index 48c500ef74..ad73f485ad 100644 --- a/runtime/snapshot.rs +++ b/runtime/snapshot.rs @@ -306,7 +306,10 @@ pub fn create_runtime_snapshot( ), deno_io::deno_io::init_ops_and_esm(Default::default()), deno_fs::deno_fs::init_ops_and_esm::(fs.clone()), - deno_node::deno_node::init_ops_and_esm::(None, fs.clone()), + deno_node::deno_node::init_ops_and_esm::< + Permissions, + sys_traits::impls::RealSys, + >(None, fs.clone()), runtime::init_ops_and_esm(), ops::runtime::deno_runtime::init_ops("deno:runtime".parse().unwrap()), ops::worker_host::deno_worker_host::init_ops( diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index faf4f3fc52..2b46d9a2ff 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -33,6 +33,7 @@ use deno_fs::FileSystem; use deno_http::DefaultHttpPropertyExtractor; use deno_io::Stdio; use deno_kv::dynamic::MultiBackendDbHandler; +use deno_node::ExtNodeSys; use deno_node::NodeExtInitServices; use deno_permissions::PermissionsContainer; use deno_terminal::colors; @@ -337,7 +338,7 @@ fn create_handles( (internal_handle, external_handle) } -pub struct WebWorkerServiceOptions { +pub struct WebWorkerServiceOptions { pub blob_store: Arc, pub broadcast_channel: InMemoryBroadcastChannel, pub compiled_wasm_module_store: Option, @@ -345,7 +346,7 @@ pub struct WebWorkerServiceOptions { pub fs: Arc, pub maybe_inspector_server: Option>, pub module_loader: Rc, - pub node_services: Option, + pub node_services: Option>, pub npm_process_state_provider: Option, pub permissions: PermissionsContainer, pub root_cert_store_provider: Option>, @@ -402,8 +403,8 @@ impl Drop for WebWorker { } impl WebWorker { - pub fn bootstrap_from_options( - services: WebWorkerServiceOptions, + pub fn bootstrap_from_options( + services: WebWorkerServiceOptions, options: WebWorkerOptions, ) -> (Self, SendableWebWorkerHandle) { let (mut worker, handle, bootstrap_options) = @@ -412,8 +413,8 @@ impl WebWorker { (worker, handle) } - fn from_options( - services: WebWorkerServiceOptions, + fn from_options( + services: WebWorkerServiceOptions, mut options: WebWorkerOptions, ) -> (Self, SendableWebWorkerHandle, BootstrapOptions) { deno_core::extension!(deno_permissions_web_worker, @@ -504,7 +505,7 @@ impl WebWorker { deno_fs::deno_fs::init_ops_and_esm::( services.fs.clone(), ), - deno_node::deno_node::init_ops_and_esm::( + deno_node::deno_node::init_ops_and_esm::( services.node_services, services.fs, ), diff --git a/runtime/worker.rs b/runtime/worker.rs index 46fbd7b43f..a9a4440410 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -39,6 +39,7 @@ use deno_fs::FileSystem; use deno_http::DefaultHttpPropertyExtractor; use deno_io::Stdio; use deno_kv::dynamic::MultiBackendDbHandler; +use deno_node::ExtNodeSys; use deno_node::NodeExtInitServices; use deno_permissions::PermissionsContainer; use deno_tls::RootCertStoreProvider; @@ -128,7 +129,7 @@ pub struct MainWorker { dispatch_process_exit_event_fn_global: v8::Global, } -pub struct WorkerServiceOptions { +pub struct WorkerServiceOptions { pub blob_store: Arc, pub broadcast_channel: InMemoryBroadcastChannel, pub feature_checker: Arc, @@ -139,7 +140,7 @@ pub struct WorkerServiceOptions { /// If not provided runtime will error if code being /// executed tries to load modules. pub module_loader: Rc, - pub node_services: Option, + pub node_services: Option>, pub npm_process_state_provider: Option, pub permissions: PermissionsContainer, pub root_cert_store_provider: Option>, @@ -304,9 +305,9 @@ pub fn create_op_metrics( } impl MainWorker { - pub fn bootstrap_from_options( + pub fn bootstrap_from_options( main_module: ModuleSpecifier, - services: WorkerServiceOptions, + services: WorkerServiceOptions, options: WorkerOptions, ) -> Self { let (mut worker, bootstrap_options) = @@ -315,9 +316,9 @@ impl MainWorker { worker } - fn from_options( + fn from_options( main_module: ModuleSpecifier, - services: WorkerServiceOptions, + services: WorkerServiceOptions, mut options: WorkerOptions, ) -> (Self, BootstrapOptions) { deno_core::extension!(deno_permissions_worker, @@ -417,7 +418,7 @@ impl MainWorker { deno_fs::deno_fs::init_ops_and_esm::( services.fs.clone(), ), - deno_node::deno_node::init_ops_and_esm::( + deno_node::deno_node::init_ops_and_esm::( services.node_services, services.fs, ),