diff options
Diffstat (limited to 'cli/npm')
-rw-r--r-- | cli/npm/cache.rs | 34 | ||||
-rw-r--r-- | cli/npm/registry.rs | 23 | ||||
-rw-r--r-- | cli/npm/resolvers/local.rs | 4 |
3 files changed, 44 insertions, 17 deletions
diff --git a/cli/npm/cache.rs b/cli/npm/cache.rs index b2c842309..5e2f06ef7 100644 --- a/cli/npm/cache.rs +++ b/cli/npm/cache.rs @@ -1,14 +1,17 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +use std::collections::HashSet; use std::fs; use std::path::Path; use std::path::PathBuf; +use std::sync::Arc; use deno_ast::ModuleSpecifier; use deno_core::anyhow::bail; use deno_core::anyhow::Context; use deno_core::error::custom_error; use deno_core::error::AnyError; +use deno_core::parking_lot::Mutex; use deno_core::url::Url; use crate::cache::DenoDir; @@ -317,6 +320,8 @@ pub struct NpmCache { cache_setting: CacheSetting, http_client: HttpClient, progress_bar: ProgressBar, + /// ensures a package is only downloaded once per run + previously_reloaded_packages: Arc<Mutex<HashSet<String>>>, } impl NpmCache { @@ -331,6 +336,7 @@ impl NpmCache { cache_setting, http_client, progress_bar, + previously_reloaded_packages: Default::default(), } } @@ -338,6 +344,26 @@ impl NpmCache { self.readonly.clone() } + pub fn cache_setting(&self) -> &CacheSetting { + &self.cache_setting + } + + /// Checks if the cache should be used for the provided name and version. + /// NOTE: Subsequent calls for the same package will always return `true` + /// to ensure a package is only downloaded once per run of the CLI. This + /// prevents downloads from re-occurring when someone has `--reload` and + /// and imports a dynamic import that imports the same package again for example. + fn should_use_global_cache_for_package( + &self, + package: (&str, &NpmVersion), + ) -> bool { + self.cache_setting.should_use_for_npm_package(package.0) + || !self + .previously_reloaded_packages + .lock() + .insert(format!("{}@{}", package.0, package.1)) + } + pub async fn ensure_package( &self, package: (&str, &NpmVersion), @@ -352,10 +378,6 @@ impl NpmCache { }) } - pub fn should_use_cache_for_npm_package(&self, package_name: &str) -> bool { - self.cache_setting.should_use_for_npm_package(package_name) - } - async fn ensure_package_inner( &self, package: (&str, &NpmVersion), @@ -367,11 +389,11 @@ impl NpmCache { package.1, registry_url, ); - if package_folder.exists() + if self.should_use_global_cache_for_package(package) + && package_folder.exists() // if this file exists, then the package didn't successfully extract // the first time, or another process is currently extracting the zip file && !package_folder.join(NPM_PACKAGE_SYNC_LOCK_FILENAME).exists() - && self.should_use_cache_for_npm_package(package.0) { return Ok(()); } else if self.cache_setting == CacheSetting::Only { diff --git a/cli/npm/registry.rs b/cli/npm/registry.rs index 3f0a84165..c62e6e1e7 100644 --- a/cli/npm/registry.rs +++ b/cli/npm/registry.rs @@ -2,6 +2,7 @@ use std::cmp::Ordering; use std::collections::HashMap; +use std::collections::HashSet; use std::fs; use std::io::ErrorKind; use std::path::PathBuf; @@ -248,7 +249,6 @@ impl RealNpmRegistryApi { pub fn new( base_url: Url, cache: NpmCache, - cache_setting: CacheSetting, http_client: HttpClient, progress_bar: ProgressBar, ) -> Self { @@ -256,7 +256,7 @@ impl RealNpmRegistryApi { base_url, cache, mem_cache: Default::default(), - cache_setting, + previously_reloaded_packages: Default::default(), http_client, progress_bar, })) @@ -286,7 +286,7 @@ struct RealNpmRegistryApiInner { base_url: Url, cache: NpmCache, mem_cache: Mutex<HashMap<String, Option<Arc<NpmPackageInfo>>>>, - cache_setting: CacheSetting, + previously_reloaded_packages: Mutex<HashSet<String>>, http_client: HttpClient, progress_bar: ProgressBar, } @@ -296,12 +296,16 @@ impl RealNpmRegistryApiInner { &self, name: &str, ) -> Result<Option<Arc<NpmPackageInfo>>, AnyError> { - let maybe_info = self.mem_cache.lock().get(name).cloned(); - if let Some(info) = maybe_info { - Ok(info) + let maybe_maybe_info = self.mem_cache.lock().get(name).cloned(); + if let Some(maybe_info) = maybe_maybe_info { + Ok(maybe_info) } else { let mut maybe_package_info = None; - if self.cache_setting.should_use_for_npm_package(name) { + if self.cache.cache_setting().should_use_for_npm_package(name) + // if this has been previously reloaded, then try loading from the + // file system cache + || !self.previously_reloaded_packages.lock().insert(name.to_string()) + { // attempt to load from the file cache maybe_package_info = self.load_file_cached_package_info(name); } @@ -409,15 +413,14 @@ impl RealNpmRegistryApiInner { &self, name: &str, ) -> Result<Option<NpmPackageInfo>, AnyError> { - if self.cache_setting == CacheSetting::Only { + if *self.cache.cache_setting() == CacheSetting::Only { return Err(custom_error( "NotCached", format!( "An npm specifier not found in cache: \"{}\", --cached-only is specified.", name ) - ) - ); + )); } let package_url = self.get_package_url(name); diff --git a/cli/npm/resolvers/local.rs b/cli/npm/resolvers/local.rs index a6df641d1..ff699f26f 100644 --- a/cli/npm/resolvers/local.rs +++ b/cli/npm/resolvers/local.rs @@ -291,7 +291,9 @@ async fn sync_resolution_with_fs( get_package_folder_id_folder_name(&package.get_package_cache_folder_id()); let folder_path = deno_local_registry_dir.join(&folder_name); let initialized_file = folder_path.join(".initialized"); - if !cache.should_use_cache_for_npm_package(&package.id.name) + if !cache + .cache_setting() + .should_use_for_npm_package(&package.id.name) || !initialized_file.exists() { let cache = cache.clone(); |