diff options
Diffstat (limited to 'cli/npm/resolvers')
-rw-r--r-- | cli/npm/resolvers/common.rs | 3 | ||||
-rw-r--r-- | cli/npm/resolvers/global.rs | 13 | ||||
-rw-r--r-- | cli/npm/resolvers/local.rs | 7 | ||||
-rw-r--r-- | cli/npm/resolvers/mod.rs | 76 |
4 files changed, 93 insertions, 6 deletions
diff --git a/cli/npm/resolvers/common.rs b/cli/npm/resolvers/common.rs index 508b783c9..7769d2322 100644 --- a/cli/npm/resolvers/common.rs +++ b/cli/npm/resolvers/common.rs @@ -10,6 +10,7 @@ use deno_core::futures; use deno_core::futures::future::BoxFuture; use deno_core::url::Url; +use crate::npm::resolution::NpmResolutionSnapshot; use crate::npm::NpmCache; use crate::npm::NpmPackageReq; use crate::npm::NpmResolutionPackage; @@ -39,6 +40,8 @@ pub trait InnerNpmPackageResolver: Send + Sync { ) -> BoxFuture<'static, Result<(), AnyError>>; fn ensure_read_permission(&self, path: &Path) -> Result<(), AnyError>; + + fn snapshot(&self) -> NpmResolutionSnapshot; } /// Caches all the packages in parallel. diff --git a/cli/npm/resolvers/global.rs b/cli/npm/resolvers/global.rs index 94b963898..c1b6818fd 100644 --- a/cli/npm/resolvers/global.rs +++ b/cli/npm/resolvers/global.rs @@ -13,6 +13,7 @@ use deno_core::futures::FutureExt; use deno_core::url::Url; use crate::npm::resolution::NpmResolution; +use crate::npm::resolution::NpmResolutionSnapshot; use crate::npm::resolvers::common::cache_packages; use crate::npm::NpmCache; use crate::npm::NpmPackageId; @@ -31,9 +32,13 @@ pub struct GlobalNpmPackageResolver { } impl GlobalNpmPackageResolver { - pub fn new(cache: NpmCache, api: NpmRegistryApi) -> Self { + pub fn new( + cache: NpmCache, + api: NpmRegistryApi, + initial_snapshot: Option<NpmResolutionSnapshot>, + ) -> Self { let registry_url = api.base_url().to_owned(); - let resolution = Arc::new(NpmResolution::new(api)); + let resolution = Arc::new(NpmResolution::new(api, initial_snapshot)); Self { cache, @@ -105,4 +110,8 @@ impl InnerNpmPackageResolver for GlobalNpmPackageResolver { let registry_path = self.cache.registry_folder(&self.registry_url); ensure_registry_read_permission(®istry_path, path) } + + fn snapshot(&self) -> NpmResolutionSnapshot { + self.resolution.snapshot() + } } diff --git a/cli/npm/resolvers/local.rs b/cli/npm/resolvers/local.rs index fa2ad4275..10ac8abfa 100644 --- a/cli/npm/resolvers/local.rs +++ b/cli/npm/resolvers/local.rs @@ -47,9 +47,10 @@ impl LocalNpmPackageResolver { cache: NpmCache, api: NpmRegistryApi, node_modules_folder: PathBuf, + initial_snapshot: Option<NpmResolutionSnapshot>, ) -> Self { let registry_url = api.base_url().to_owned(); - let resolution = Arc::new(NpmResolution::new(api)); + let resolution = Arc::new(NpmResolution::new(api, initial_snapshot)); Self { cache, @@ -180,6 +181,10 @@ impl InnerNpmPackageResolver for LocalNpmPackageResolver { fn ensure_read_permission(&self, path: &Path) -> Result<(), AnyError> { ensure_registry_read_permission(&self.root_node_modules_path, path) } + + fn snapshot(&self) -> NpmResolutionSnapshot { + self.resolution.snapshot() + } } /// Creates a pnpm style folder structure. diff --git a/cli/npm/resolvers/mod.rs b/cli/npm/resolvers/mod.rs index 3a40340f0..4b4ec4723 100644 --- a/cli/npm/resolvers/mod.rs +++ b/cli/npm/resolvers/mod.rs @@ -8,9 +8,13 @@ use deno_ast::ModuleSpecifier; use deno_core::anyhow::bail; use deno_core::error::custom_error; use deno_core::error::AnyError; +use deno_core::serde_json; use deno_runtime::deno_node::PathClean; use deno_runtime::deno_node::RequireNpmResolver; use global::GlobalNpmPackageResolver; +use once_cell::sync::Lazy; +use serde::Deserialize; +use serde::Serialize; use std::path::Path; use std::path::PathBuf; @@ -20,15 +24,50 @@ use crate::fs_util; use self::common::InnerNpmPackageResolver; use self::local::LocalNpmPackageResolver; +use super::resolution::NpmResolutionSnapshot; use super::NpmCache; use super::NpmPackageReq; use super::NpmRegistryApi; +const RESOLUTION_STATE_ENV_VAR_NAME: &str = + "DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE"; + +static IS_NPM_MAIN: Lazy<bool> = + Lazy::new(|| std::env::var(RESOLUTION_STATE_ENV_VAR_NAME).is_ok()); + +/// State provided to the process via an environment variable. +#[derive(Debug, Serialize, Deserialize)] +struct NpmProcessState { + snapshot: NpmResolutionSnapshot, + local_node_modules_path: Option<String>, +} + +impl NpmProcessState { + pub fn was_set() -> bool { + *IS_NPM_MAIN + } + + pub fn take() -> Option<NpmProcessState> { + // initialize the lazy before we remove the env var below + if !Self::was_set() { + return None; + } + + let state = std::env::var(RESOLUTION_STATE_ENV_VAR_NAME).ok()?; + let state = serde_json::from_str(&state).ok()?; + // remove the environment variable so that sub processes + // that are spawned do not also use this. + std::env::remove_var(RESOLUTION_STATE_ENV_VAR_NAME); + Some(state) + } +} + #[derive(Clone)] pub struct NpmPackageResolver { unstable: bool, no_npm: bool, inner: Arc<dyn InnerNpmPackageResolver>, + local_node_modules_path: Option<PathBuf>, } impl NpmPackageResolver { @@ -39,19 +78,30 @@ impl NpmPackageResolver { no_npm: bool, local_node_modules_path: Option<PathBuf>, ) -> Self { - let inner: Arc<dyn InnerNpmPackageResolver> = match local_node_modules_path + let process_npm_state = NpmProcessState::take(); + let local_node_modules_path = local_node_modules_path.or_else(|| { + process_npm_state + .as_ref() + .and_then(|s| s.local_node_modules_path.as_ref().map(PathBuf::from)) + }); + let maybe_snapshot = process_npm_state.map(|s| s.snapshot); + let inner: Arc<dyn InnerNpmPackageResolver> = match &local_node_modules_path { Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new( cache, api, - node_modules_folder, + node_modules_folder.clone(), + maybe_snapshot, )), - None => Arc::new(GlobalNpmPackageResolver::new(cache, api)), + None => { + Arc::new(GlobalNpmPackageResolver::new(cache, api, maybe_snapshot)) + } }; Self { unstable, no_npm, inner, + local_node_modules_path, } } @@ -137,6 +187,26 @@ impl NpmPackageResolver { self.inner.add_package_reqs(packages).await } + + // If the main module should be treated as being in an npm package. + // This is triggered via a secret environment variable which is used + // for functionality like child_process.fork. Users should NOT depend + // on this functionality. + pub fn is_npm_main(&self) -> bool { + NpmProcessState::was_set() + } + + /// Gets the state of npm for the process. + pub fn get_npm_process_state(&self) -> String { + serde_json::to_string(&NpmProcessState { + snapshot: self.inner.snapshot(), + local_node_modules_path: self + .local_node_modules_path + .as_ref() + .map(|p| p.to_string_lossy().to_string()), + }) + .unwrap() + } } impl RequireNpmResolver for NpmPackageResolver { |