summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/args/mod.rs98
-rw-r--r--cli/factory.rs2
-rw-r--r--cli/http_util.rs33
-rw-r--r--cli/lsp/config.rs5
-rw-r--r--cli/lsp/language_server.rs4
-rw-r--r--cli/lsp/resolver.rs6
-rw-r--r--cli/npm/cache_dir.rs61
-rw-r--r--cli/npm/common.rs24
-rw-r--r--cli/npm/managed/cache.rs37
-rw-r--r--cli/npm/managed/mod.rs28
-rw-r--r--cli/npm/managed/registry.rs38
-rw-r--r--cli/npm/managed/resolvers/common.rs11
-rw-r--r--cli/npm/managed/resolvers/global.rs51
-rw-r--r--cli/npm/managed/resolvers/local.rs36
-rw-r--r--cli/npm/managed/resolvers/mod.rs4
-rw-r--r--cli/standalone/binary.rs6
-rw-r--r--cli/standalone/mod.rs14
-rw-r--r--cli/tools/installer.rs2
-rw-r--r--cli/tools/upgrade.rs2
19 files changed, 302 insertions, 160 deletions
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index 03a6357aa..bc384a132 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -13,6 +13,8 @@ use ::import_map::ImportMap;
use deno_ast::SourceMapOption;
use deno_core::resolve_url_or_path;
use deno_graph::GraphKind;
+use deno_npm::npm_rc::NpmRc;
+use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_npm::NpmSystemInfo;
use deno_runtime::deno_tls::RootCertStoreProvider;
@@ -546,6 +548,83 @@ fn discover_package_json(
Ok(None)
}
+/// Discover `.npmrc` file - currently we only support it next to `package.json`
+/// or next to `deno.json`.
+///
+/// In the future we will need to support it in user directory or global directory
+/// as per https://docs.npmjs.com/cli/v10/configuring-npm/npmrc#files.
+fn discover_npmrc(
+ maybe_package_json_path: Option<PathBuf>,
+ maybe_deno_json_path: Option<PathBuf>,
+) -> Result<Arc<ResolvedNpmRc>, AnyError> {
+ if !*DENO_FUTURE {
+ return Ok(create_default_npmrc());
+ }
+
+ const NPMRC_NAME: &str = ".npmrc";
+
+ fn get_env_var(var_name: &str) -> Option<String> {
+ std::env::var(var_name).ok()
+ }
+
+ fn try_to_read_npmrc(
+ dir: &Path,
+ ) -> Result<Option<(String, PathBuf)>, AnyError> {
+ let path = dir.join(NPMRC_NAME);
+ let maybe_source = match std::fs::read_to_string(&path) {
+ Ok(source) => Some(source),
+ Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
+ Err(err) => {
+ bail!("Error loading .npmrc at {}. {:#}", path.display(), err)
+ }
+ };
+
+ Ok(maybe_source.map(|source| (source, path)))
+ }
+
+ fn try_to_parse_npmrc(
+ source: String,
+ path: &Path,
+ ) -> Result<Arc<ResolvedNpmRc>, AnyError> {
+ let npmrc = NpmRc::parse(&source, &get_env_var).with_context(|| {
+ format!("Failed to parse .npmrc at {}", path.display())
+ })?;
+ let resolved = npmrc
+ .as_resolved(npm_registry_url())
+ .context("Failed to resolve .npmrc options")?;
+ Ok(Arc::new(resolved))
+ }
+
+ if let Some(package_json_path) = maybe_package_json_path {
+ if let Some(package_json_dir) = package_json_path.parent() {
+ if let Some((source, path)) = try_to_read_npmrc(package_json_dir)? {
+ return try_to_parse_npmrc(source, &path);
+ }
+ }
+ }
+
+ if let Some(deno_json_path) = maybe_deno_json_path {
+ if let Some(deno_json_dir) = deno_json_path.parent() {
+ if let Some((source, path)) = try_to_read_npmrc(deno_json_dir)? {
+ return try_to_parse_npmrc(source, &path);
+ }
+ }
+ }
+
+ log::debug!("No .npmrc file found");
+ Ok(create_default_npmrc())
+}
+
+pub fn create_default_npmrc() -> Arc<ResolvedNpmRc> {
+ Arc::new(ResolvedNpmRc {
+ default_config: deno_npm::npm_rc::RegistryConfigWithUrl {
+ registry_url: npm_registry_url().clone(),
+ config: Default::default(),
+ },
+ scopes: Default::default(),
+ })
+}
+
struct CliRootCertStoreProvider {
cell: OnceCell<RootCertStore>,
maybe_root_path: Option<PathBuf>,
@@ -722,6 +801,7 @@ pub struct CliOptions {
maybe_vendor_folder: Option<PathBuf>,
maybe_config_file: Option<ConfigFile>,
maybe_package_json: Option<PackageJson>,
+ npmrc: Arc<ResolvedNpmRc>,
maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
overrides: CliOptionOverrides,
maybe_workspace_config: Option<WorkspaceConfig>,
@@ -736,6 +816,7 @@ impl CliOptions {
maybe_config_file: Option<ConfigFile>,
maybe_lockfile: Option<Arc<Mutex<Lockfile>>>,
maybe_package_json: Option<PackageJson>,
+ npmrc: Arc<ResolvedNpmRc>,
force_global_cache: bool,
) -> Result<Self, AnyError> {
if let Some(insecure_allowlist) =
@@ -798,6 +879,7 @@ impl CliOptions {
maybe_config_file,
maybe_lockfile,
maybe_package_json,
+ npmrc,
maybe_node_modules_folder,
maybe_vendor_folder,
overrides: Default::default(),
@@ -851,6 +933,16 @@ impl CliOptions {
} else {
maybe_package_json = discover_package_json(&flags, None, &initial_cwd)?;
}
+ let npmrc = discover_npmrc(
+ maybe_package_json.as_ref().map(|p| p.path.clone()),
+ maybe_config_file.as_ref().and_then(|cf| {
+ if cf.specifier.scheme() == "file" {
+ Some(cf.specifier.to_file_path().unwrap())
+ } else {
+ None
+ }
+ }),
+ )?;
let maybe_lock_file = lockfile::discover(
&flags,
@@ -863,6 +955,7 @@ impl CliOptions {
maybe_config_file,
maybe_lock_file.map(|l| Arc::new(Mutex::new(l))),
maybe_package_json,
+ npmrc,
false,
)
}
@@ -1172,6 +1265,7 @@ impl CliOptions {
maybe_vendor_folder: self.maybe_vendor_folder.clone(),
maybe_config_file: self.maybe_config_file.clone(),
maybe_package_json: self.maybe_package_json.clone(),
+ npmrc: self.npmrc.clone(),
maybe_lockfile: self.maybe_lockfile.clone(),
maybe_workspace_config: self.maybe_workspace_config.clone(),
overrides: self.overrides.clone(),
@@ -1303,6 +1397,10 @@ impl CliOptions {
&self.maybe_package_json
}
+ pub fn npmrc(&self) -> &Arc<ResolvedNpmRc> {
+ &self.npmrc
+ }
+
pub fn maybe_package_json_deps(&self) -> Option<PackageJsonDeps> {
if matches!(
self.flags.subcommand,
diff --git a/cli/factory.rs b/cli/factory.rs
index 8a9d20970..43486bca0 100644
--- a/cli/factory.rs
+++ b/cli/factory.rs
@@ -446,7 +446,7 @@ impl CliFactory {
self.package_json_deps_provider().clone(),
),
npm_system_info: self.options.npm_system_info(),
- npm_registry_url: crate::args::npm_registry_url().to_owned(),
+ npmrc: self.options.npmrc().clone()
})
}).await
}.boxed_local())
diff --git a/cli/http_util.rs b/cli/http_util.rs
index 30507a629..832ccec1c 100644
--- a/cli/http_util.rs
+++ b/cli/http_util.rs
@@ -17,6 +17,8 @@ use deno_runtime::deno_fetch::reqwest::header::LOCATION;
use deno_runtime::deno_fetch::reqwest::Response;
use deno_runtime::deno_fetch::CreateHttpClientOptions;
use deno_runtime::deno_tls::RootCertStoreProvider;
+use reqwest::header::HeaderName;
+use reqwest::header::HeaderValue;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
@@ -294,7 +296,7 @@ impl HttpClient {
&self,
url: U,
) -> Result<Vec<u8>, AnyError> {
- let maybe_bytes = self.inner_download(url, None).await?;
+ let maybe_bytes = self.inner_download(url, None, None).await?;
match maybe_bytes {
Some(bytes) => Ok(bytes),
None => Err(custom_error("Http", "Not found.")),
@@ -304,17 +306,21 @@ impl HttpClient {
pub async fn download_with_progress<U: reqwest::IntoUrl>(
&self,
url: U,
+ maybe_header: Option<(HeaderName, HeaderValue)>,
progress_guard: &UpdateGuard,
) -> Result<Option<Vec<u8>>, AnyError> {
- self.inner_download(url, Some(progress_guard)).await
+ self
+ .inner_download(url, maybe_header, Some(progress_guard))
+ .await
}
async fn inner_download<U: reqwest::IntoUrl>(
&self,
url: U,
+ maybe_header: Option<(HeaderName, HeaderValue)>,
progress_guard: Option<&UpdateGuard>,
) -> Result<Option<Vec<u8>>, AnyError> {
- let response = self.get_redirected_response(url).await?;
+ let response = self.get_redirected_response(url, maybe_header).await?;
if response.status() == 404 {
return Ok(None);
@@ -339,15 +345,30 @@ impl HttpClient {
pub async fn get_redirected_response<U: reqwest::IntoUrl>(
&self,
url: U,
+ mut maybe_header: Option<(HeaderName, HeaderValue)>,
) -> Result<Response, AnyError> {
let mut url = url.into_url()?;
- let mut response = self.get_no_redirect(url.clone())?.send().await?;
+
+ let mut builder = self.get_no_redirect(url.clone())?;
+ if let Some((header_name, header_value)) = maybe_header.as_ref() {
+ builder = builder.header(header_name, header_value);
+ }
+ let mut response = builder.send().await?;
let status = response.status();
if status.is_redirection() {
for _ in 0..5 {
let new_url = resolve_redirect_from_response(&url, &response)?;
- let new_response =
- self.get_no_redirect(new_url.clone())?.send().await?;
+ let mut builder = self.get_no_redirect(new_url.clone())?;
+
+ if new_url.origin() == url.origin() {
+ if let Some((header_name, header_value)) = maybe_header.as_ref() {
+ builder = builder.header(header_name, header_value);
+ }
+ } else {
+ maybe_header = None;
+ }
+
+ let new_response = builder.send().await?;
let status = new_response.status();
if status.is_redirection() {
response = new_response;
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs
index 597f45688..89ecb84d8 100644
--- a/cli/lsp/config.rs
+++ b/cli/lsp/config.rs
@@ -24,6 +24,7 @@ use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::ModuleSpecifier;
use deno_lockfile::Lockfile;
+use deno_npm::npm_rc::ResolvedNpmRc;
use deno_runtime::deno_node::PackageJson;
use deno_runtime::fs_util::specifier_to_file_path;
use deno_runtime::permissions::PermissionsContainer;
@@ -1090,6 +1091,7 @@ pub struct ConfigData {
pub vendor_dir: Option<PathBuf>,
pub lockfile: Option<Arc<Mutex<Lockfile>>>,
pub package_json: Option<Arc<PackageJson>>,
+ pub npmrc: Option<Arc<ResolvedNpmRc>>,
pub import_map: Option<Arc<ImportMap>>,
pub import_map_from_settings: bool,
watched_files: HashMap<ModuleSpecifier, ConfigWatchedFileType>,
@@ -1274,6 +1276,8 @@ impl ConfigData {
// Load package.json
let mut package_json = None;
+ // TODO(bartlomieju): support discovering .npmrc
+ let npmrc = None;
if let Ok(path) = specifier_to_file_path(scope) {
let path = path.join("package.json");
if let Ok(specifier) = ModuleSpecifier::from_file_path(&path) {
@@ -1429,6 +1433,7 @@ impl ConfigData {
vendor_dir,
lockfile: lockfile.map(Mutex::new).map(Arc::new),
package_json: package_json.map(Arc::new),
+ npmrc: npmrc.map(Arc::new),
import_map: import_map.map(Arc::new),
import_map_from_settings,
watched_files,
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 17ed02cd6..8f37d8b9c 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -83,6 +83,7 @@ use super::tsc::ChangeKind;
use super::tsc::GetCompletionDetailsArgs;
use super::tsc::TsServer;
use super::urls;
+use crate::args::create_default_npmrc;
use crate::args::get_root_cert_store;
use crate::args::CaData;
use crate::args::CacheSetting;
@@ -3318,6 +3319,9 @@ impl Inner {
config_data.and_then(|d| d.config_file.as_deref().cloned()),
config_data.and_then(|d| d.lockfile.clone()),
config_data.and_then(|d| d.package_json.as_deref().cloned()),
+ config_data
+ .and_then(|d| d.npmrc.clone())
+ .unwrap_or_else(create_default_npmrc),
force_global_cache,
)?;
diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs
index c4d97177f..0567bba86 100644
--- a/cli/lsp/resolver.rs
+++ b/cli/lsp/resolver.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+use crate::args::create_default_npmrc;
use crate::args::package_json;
use crate::args::CacheSetting;
use crate::cache::FastInsecureHasher;
@@ -363,7 +364,10 @@ async fn create_npm_resolver(
// do not install while resolving in the lsp—leave that to the cache command
package_json_installer:
CliNpmResolverManagedPackageJsonInstallerOption::NoInstall,
- npm_registry_url: crate::args::npm_registry_url().to_owned(),
+ npmrc: config_data
+ .npmrc
+ .clone()
+ .unwrap_or_else(create_default_npmrc),
npm_system_info: NpmSystemInfo::default(),
})
};
diff --git a/cli/npm/cache_dir.rs b/cli/npm/cache_dir.rs
index 1c28a9b81..d51913775 100644
--- a/cli/npm/cache_dir.rs
+++ b/cli/npm/cache_dir.rs
@@ -20,10 +20,13 @@ pub struct NpmCacheDir {
root_dir: PathBuf,
// cached url representation of the root directory
root_dir_url: Url,
+ // A list of all registry that were discovered via `.npmrc` files
+ // turned into a safe directory names.
+ known_registries_dirnames: Vec<String>,
}
impl NpmCacheDir {
- pub fn new(root_dir: PathBuf) -> Self {
+ pub fn new(root_dir: PathBuf, known_registries_urls: Vec<Url>) -> Self {
fn try_get_canonicalized_root_dir(
root_dir: &Path,
) -> Result<PathBuf, AnyError> {
@@ -38,12 +41,27 @@ impl NpmCacheDir {
let root_dir =
try_get_canonicalized_root_dir(&root_dir).unwrap_or(root_dir);
let root_dir_url = Url::from_directory_path(&root_dir).unwrap();
+
+ let known_registries_dirnames: Vec<_> = known_registries_urls
+ .into_iter()
+ .map(|url| {
+ root_url_to_safe_local_dirname(&url)
+ .to_string_lossy()
+ .replace('\\', "/")
+ })
+ .collect();
+
Self {
root_dir,
root_dir_url,
+ known_registries_dirnames,
}
}
+ pub fn root_dir(&self) -> &Path {
+ &self.root_dir
+ }
+
pub fn root_dir_url(&self) -> &Url {
&self.root_dir_url
}
@@ -88,7 +106,7 @@ impl NpmCacheDir {
}
}
- pub fn registry_folder(&self, registry_url: &Url) -> PathBuf {
+ fn registry_folder(&self, registry_url: &Url) -> PathBuf {
self
.root_dir
.join(root_url_to_safe_local_dirname(registry_url))
@@ -97,23 +115,32 @@ impl NpmCacheDir {
pub fn resolve_package_folder_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
- registry_url: &Url,
) -> Option<NpmPackageCacheFolderId> {
- let registry_root_dir = self
- .root_dir_url
- .join(&format!(
- "{}/",
- root_url_to_safe_local_dirname(registry_url)
- .to_string_lossy()
- .replace('\\', "/")
- ))
- // this not succeeding indicates a fatal issue, so unwrap
- .unwrap();
- let mut relative_url = registry_root_dir.make_relative(specifier)?;
- if relative_url.starts_with("../") {
- return None;
+ let mut maybe_relative_url = None;
+
+ // Iterate through known registries and try to get a match.
+ for registry_dirname in &self.known_registries_dirnames {
+ let registry_root_dir = self
+ .root_dir_url
+ .join(&format!("{}/", registry_dirname))
+ // this not succeeding indicates a fatal issue, so unwrap
+ .unwrap();
+
+ let Some(relative_url) = registry_root_dir.make_relative(specifier)
+ else {
+ continue;
+ };
+
+ if relative_url.starts_with("../") {
+ continue;
+ }
+
+ maybe_relative_url = Some(relative_url);
+ break;
}
+ let mut relative_url = maybe_relative_url?;
+
// base32 decode the url if it starts with an underscore
// * Ex. _{base32(package_name)}/
if let Some(end_url) = relative_url.strip_prefix('_') {
@@ -194,8 +221,8 @@ mod test {
fn should_get_package_folder() {
let deno_dir = crate::cache::DenoDir::new(None).unwrap();
let root_dir = deno_dir.npm_folder_path();
- let cache = NpmCacheDir::new(root_dir.clone());
let registry_url = Url::parse("https://registry.npmjs.org/").unwrap();
+ let cache = NpmCacheDir::new(root_dir.clone(), vec![registry_url.clone()]);
assert_eq!(
cache.package_folder_for_id(
diff --git a/cli/npm/common.rs b/cli/npm/common.rs
index e40924838..bf45aa5b8 100644
--- a/cli/npm/common.rs
+++ b/cli/npm/common.rs
@@ -1,5 +1,8 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+use deno_npm::npm_rc::RegistryConfig;
+use reqwest::header;
+
/// Gets the corresponding @types package for the provided package name.
pub fn types_package_name(package_name: &str) -> String {
debug_assert!(!package_name.starts_with("@types/"));
@@ -8,6 +11,27 @@ pub fn types_package_name(package_name: &str) -> String {
format!("@types/{}", package_name.replace('/', "__"))
}
+// TODO(bartlomieju): support more auth methods besides token and basic auth
+pub fn maybe_auth_header_for_npm_registry(
+ registry_config: &RegistryConfig,
+) -> Option<(header::HeaderName, header::HeaderValue)> {
+ if let Some(token) = registry_config.auth_token.as_ref() {
+ return Some((
+ header::AUTHORIZATION,
+ header::HeaderValue::from_str(&format!("Bearer {}", token)).unwrap(),
+ ));
+ }
+
+ if let Some(auth) = registry_config.auth.as_ref() {
+ return Some((
+ header::AUTHORIZATION,
+ header::HeaderValue::from_str(&format!("Basic {}", auth)).unwrap(),
+ ));
+ }
+
+ None
+}
+
#[cfg(test)]
mod test {
use super::types_package_name;
diff --git a/cli/npm/managed/cache.rs b/cli/npm/managed/cache.rs
index 44b98fcee..4056c97ad 100644
--- a/cli/npm/managed/cache.rs
+++ b/cli/npm/managed/cache.rs
@@ -13,6 +13,7 @@ use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::url::Url;
+use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageVersionDistInfo;
use deno_npm::NpmPackageCacheFolderId;
use deno_runtime::deno_fs;
@@ -20,6 +21,7 @@ use deno_semver::package::PackageNv;
use crate::args::CacheSetting;
use crate::http_util::HttpClient;
+use crate::npm::common::maybe_auth_header_for_npm_registry;
use crate::npm::NpmCacheDir;
use crate::util::fs::hard_link_dir_recursive;
use crate::util::progress_bar::ProgressBar;
@@ -35,6 +37,7 @@ pub struct NpmCache {
fs: Arc<dyn deno_fs::FileSystem>,
http_client: Arc<HttpClient>,
progress_bar: ProgressBar,
+ pub(crate) npmrc: Arc<ResolvedNpmRc>,
/// ensures a package is only downloaded once per run
previously_reloaded_packages: Mutex<HashSet<PackageNv>>,
}
@@ -46,6 +49,7 @@ impl NpmCache {
fs: Arc<dyn deno_fs::FileSystem>,
http_client: Arc<HttpClient>,
progress_bar: ProgressBar,
+ npmrc: Arc<ResolvedNpmRc>,
) -> Self {
Self {
cache_dir,
@@ -54,6 +58,7 @@ impl NpmCache {
http_client,
progress_bar,
previously_reloaded_packages: Default::default(),
+ npmrc,
}
}
@@ -82,10 +87,9 @@ impl NpmCache {
&self,
package: &PackageNv,
dist: &NpmPackageVersionDistInfo,
- registry_url: &Url,
) -> Result<(), AnyError> {
self
- .ensure_package_inner(package, dist, registry_url)
+ .ensure_package_inner(package, dist)
.await
.with_context(|| format!("Failed caching npm package '{package}'."))
}
@@ -94,8 +98,10 @@ impl NpmCache {
&self,
package_nv: &PackageNv,
dist: &NpmPackageVersionDistInfo,
- registry_url: &Url,
) -> Result<(), AnyError> {
+ let registry_url = self.npmrc.get_registry_url(&package_nv.name);
+ let registry_config = self.npmrc.get_registry_config(&package_nv.name);
+
let package_folder = self
.cache_dir
.package_folder_for_name_and_version(package_nv, registry_url);
@@ -118,10 +124,12 @@ impl NpmCache {
bail!("Tarball URL was empty.");
}
+ let maybe_auth_header = maybe_auth_header_for_npm_registry(registry_config);
+
let guard = self.progress_bar.update(&dist.tarball);
let maybe_bytes = self
.http_client
- .download_with_progress(&dist.tarball, &guard)
+ .download_with_progress(&dist.tarball, maybe_auth_header, &guard)
.await?;
match maybe_bytes {
Some(bytes) => {
@@ -164,8 +172,8 @@ impl NpmCache {
pub fn ensure_copy_package(
&self,
folder_id: &NpmPackageCacheFolderId,
- registry_url: &Url,
) -> Result<(), AnyError> {
+ let registry_url = self.npmrc.get_registry_url(&folder_id.nv.name);
assert_ne!(folder_id.copy_index, 0);
let package_folder = self
.cache_dir
@@ -192,40 +200,37 @@ impl NpmCache {
Ok(())
}
- pub fn package_folder_for_id(
- &self,
- id: &NpmPackageCacheFolderId,
- registry_url: &Url,
- ) -> PathBuf {
+ pub fn package_folder_for_id(&self, id: &NpmPackageCacheFolderId) -> PathBuf {
+ let registry_url = self.npmrc.get_registry_url(&id.nv.name);
self.cache_dir.package_folder_for_id(id, registry_url)
}
pub fn package_folder_for_name_and_version(
&self,
package: &PackageNv,
- registry_url: &Url,
) -> PathBuf {
+ let registry_url = self.npmrc.get_registry_url(&package.name);
self
.cache_dir
.package_folder_for_name_and_version(package, registry_url)
}
- pub fn package_name_folder(&self, name: &str, registry_url: &Url) -> PathBuf {
+ pub fn package_name_folder(&self, name: &str) -> PathBuf {
+ let registry_url = self.npmrc.get_registry_url(name);
self.cache_dir.package_name_folder(name, registry_url)
}
- pub fn registry_folder(&self, registry_url: &Url) -> PathBuf {
- self.cache_dir.registry_folder(registry_url)
+ pub fn root_folder(&self) -> PathBuf {
+ self.cache_dir.root_dir().to_owned()
}
pub fn resolve_package_folder_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
- registry_url: &Url,
) -> Option<NpmPackageCacheFolderId> {
self
.cache_dir
- .resolve_package_folder_id_from_specifier(specifier, registry_url)
+ .resolve_package_folder_id_from_specifier(specifier)
}
}
diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs
index 0625911d3..3a2657cfb 100644
--- a/cli/npm/managed/mod.rs
+++ b/cli/npm/managed/mod.rs
@@ -9,8 +9,8 @@ use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::serde_json;
-use deno_core::url::Url;
use deno_graph::NpmPackageReqResolution;
+use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmRegistryApi;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::resolution::PackageReqNotFoundError;
@@ -72,7 +72,7 @@ pub struct CliNpmResolverManagedCreateOptions {
pub maybe_node_modules_path: Option<PathBuf>,
pub npm_system_info: NpmSystemInfo,
pub package_json_installer: CliNpmResolverManagedPackageJsonInstallerOption,
- pub npm_registry_url: Url,
+ pub npmrc: Arc<ResolvedNpmRc>,
}
pub async fn create_managed_npm_resolver_for_lsp(
@@ -96,7 +96,6 @@ pub async fn create_managed_npm_resolver_for_lsp(
options.text_only_progress_bar,
options.maybe_node_modules_path,
options.package_json_installer,
- options.npm_registry_url,
options.npm_system_info,
)
}
@@ -116,7 +115,6 @@ pub async fn create_managed_npm_resolver(
options.text_only_progress_bar,
options.maybe_node_modules_path,
options.package_json_installer,
- options.npm_registry_url,
options.npm_system_info,
))
}
@@ -131,7 +129,6 @@ fn create_inner(
text_only_progress_bar: crate::util::progress_bar::ProgressBar,
node_modules_dir_path: Option<PathBuf>,
package_json_installer: CliNpmResolverManagedPackageJsonInstallerOption,
- npm_registry_url: Url,
npm_system_info: NpmSystemInfo,
) -> Arc<dyn CliNpmResolver> {
let resolution = Arc::new(NpmResolution::from_serialized(
@@ -143,7 +140,6 @@ fn create_inner(
fs.clone(),
npm_cache.clone(),
&text_only_progress_bar,
- npm_registry_url,
resolution.clone(),
node_modules_dir_path,
npm_system_info.clone(),
@@ -175,11 +171,15 @@ fn create_inner(
fn create_cache(options: &CliNpmResolverManagedCreateOptions) -> Arc<NpmCache> {
Arc::new(NpmCache::new(
- NpmCacheDir::new(options.npm_global_cache_dir.clone()),
+ NpmCacheDir::new(
+ options.npm_global_cache_dir.clone(),
+ options.npmrc.get_all_known_registries_urls(),
+ ),
options.cache_setting.clone(),
options.fs.clone(),
options.http_client.clone(),
options.text_only_progress_bar.clone(),
+ options.npmrc.clone(),
))
}
@@ -188,9 +188,9 @@ fn create_api(
npm_cache: Arc<NpmCache>,
) -> Arc<CliNpmRegistryApi> {
Arc::new(CliNpmRegistryApi::new(
- options.npm_registry_url.clone(),
npm_cache.clone(),
options.http_client.clone(),
+ options.npmrc.clone(),
options.text_only_progress_bar.clone(),
))
}
@@ -483,15 +483,8 @@ impl ManagedCliNpmResolver {
.map_err(|err| err.into())
}
- pub fn registry_base_url(&self) -> &ModuleSpecifier {
- self.api.base_url()
- }
-
- pub fn registry_folder_in_global_cache(
- &self,
- registry_url: &ModuleSpecifier,
- ) -> PathBuf {
- self.global_npm_cache.registry_folder(registry_url)
+ pub fn global_cache_root_folder(&self) -> PathBuf {
+ self.global_npm_cache.root_folder()
}
}
@@ -564,7 +557,6 @@ impl CliNpmResolver for ManagedCliNpmResolver {
self.fs.clone(),
self.global_npm_cache.clone(),
&self.progress_bar,
- self.api.base_url().clone(),
npm_resolution,
self.root_node_modules_path().map(ToOwned::to_owned),
self.npm_system_info.clone(),
diff --git a/cli/npm/managed/registry.rs b/cli/npm/managed/registry.rs
index 3199a3c32..391ff0640 100644
--- a/cli/npm/managed/registry.rs
+++ b/cli/npm/managed/registry.rs
@@ -18,6 +18,8 @@ use deno_core::futures::FutureExt;
use deno_core::parking_lot::Mutex;
use deno_core::serde_json;
use deno_core::url::Url;
+use deno_npm::npm_rc::RegistryConfig;
+use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageInfo;
use deno_npm::registry::NpmRegistryApi;
use deno_npm::registry::NpmRegistryPackageInfoLoadError;
@@ -25,6 +27,7 @@ use deno_npm::registry::NpmRegistryPackageInfoLoadError;
use crate::args::CacheSetting;
use crate::cache::CACHE_PERM;
use crate::http_util::HttpClient;
+use crate::npm::common::maybe_auth_header_for_npm_registry;
use crate::util::fs::atomic_write_file;
use crate::util::progress_bar::ProgressBar;
use crate::util::sync::AtomicFlag;
@@ -36,17 +39,17 @@ pub struct CliNpmRegistryApi(Option<Arc<CliNpmRegistryApiInner>>);
impl CliNpmRegistryApi {
pub fn new(
- base_url: Url,
cache: Arc<NpmCache>,
http_client: Arc<HttpClient>,
+ npmrc: Arc<ResolvedNpmRc>,
progress_bar: ProgressBar,
) -> Self {
Self(Some(Arc::new(CliNpmRegistryApiInner {
- base_url,
cache,
force_reload_flag: Default::default(),
mem_cache: Default::default(),
previously_reloaded_packages: Default::default(),
+ npmrc,
http_client,
progress_bar,
})))
@@ -64,10 +67,6 @@ impl CliNpmRegistryApi {
self.inner().get_cached_package_info(name)
}
- pub fn base_url(&self) -> &Url {
- &self.inner().base_url
- }
-
fn inner(&self) -> &Arc<CliNpmRegistryApiInner> {
// this panicking indicates a bug in the code where this
// wasn't initialized
@@ -121,12 +120,12 @@ enum CacheItem {
#[derive(Debug)]
struct CliNpmRegistryApiInner {
- base_url: Url,
cache: Arc<NpmCache>,
force_reload_flag: AtomicFlag,
mem_cache: Mutex<HashMap<String, CacheItem>>,
previously_reloaded_packages: Mutex<HashSet<String>>,
http_client: Arc<HttpClient>,
+ npmrc: Arc<ResolvedNpmRc>,
progress_bar: ProgressBar,
}
@@ -273,13 +272,20 @@ impl CliNpmRegistryApiInner {
&self,
name: &str,
) -> Result<Option<NpmPackageInfo>, AnyError> {
+ let registry_url = self.npmrc.get_registry_url(name);
+ let registry_config = self.npmrc.get_registry_config(name);
+
self
- .load_package_info_from_registry_inner(name)
+ .load_package_info_from_registry_inner(
+ name,
+ registry_url,
+ registry_config,
+ )
.await
.with_context(|| {
format!(
"Error getting response at {} for package \"{}\"",
- self.get_package_url(name),
+ self.get_package_url(name, registry_url),
name
)
})
@@ -288,6 +294,8 @@ impl CliNpmRegistryApiInner {
async fn load_package_info_from_registry_inner(
&self,
name: &str,
+ registry_url: &Url,
+ registry_config: &RegistryConfig,
) -> Result<Option<NpmPackageInfo>, AnyError> {
if *self.cache.cache_setting() == CacheSetting::Only {
return Err(custom_error(
@@ -298,12 +306,14 @@ impl CliNpmRegistryApiInner {
));
}
- let package_url = self.get_package_url(name);
+ let package_url = self.get_package_url(name, registry_url);
let guard = self.progress_bar.update(package_url.as_str());
+ let maybe_auth_header = maybe_auth_header_for_npm_registry(registry_config);
+
let maybe_bytes = self
.http_client
- .download_with_progress(package_url, &guard)
+ .download_with_progress(package_url, maybe_auth_header, &guard)
.await?;
match maybe_bytes {
Some(bytes) => {
@@ -315,7 +325,7 @@ impl CliNpmRegistryApiInner {
}
}
- fn get_package_url(&self, name: &str) -> Url {
+ fn get_package_url(&self, name: &str, registry_url: &Url) -> Url {
// list of all characters used in npm packages:
// !, ', (, ), *, -, ., /, [0-9], @, [A-Za-z], _, ~
const ASCII_SET: percent_encoding::AsciiSet =
@@ -332,11 +342,11 @@ impl CliNpmRegistryApiInner {
.remove(b'_')
.remove(b'~');
let name = percent_encoding::utf8_percent_encode(name, &ASCII_SET);
- self.base_url.join(&name.to_string()).unwrap()
+ registry_url.join(&name.to_string()).unwrap()
}
fn get_package_file_cache_path(&self, name: &str) -> PathBuf {
- let name_folder_path = self.cache.package_name_folder(name, &self.base_url);
+ let name_folder_path = self.cache.package_name_folder(name);
name_folder_path.join("registry.json")
}
diff --git a/cli/npm/managed/resolvers/common.rs b/cli/npm/managed/resolvers/common.rs
index a326b562b..b010bdd7c 100644
--- a/cli/npm/managed/resolvers/common.rs
+++ b/cli/npm/managed/resolvers/common.rs
@@ -44,11 +44,6 @@ pub trait NpmPackageFsResolver: Send + Sync {
mode: NodeResolutionMode,
) -> Result<PathBuf, AnyError>;
- fn resolve_package_folder_from_specifier(
- &self,
- specifier: &ModuleSpecifier,
- ) -> Result<Option<PathBuf>, AnyError>;
-
fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
@@ -132,16 +127,12 @@ impl RegistryReadPermissionChecker {
pub async fn cache_packages(
packages: Vec<NpmResolutionPackage>,
cache: &Arc<NpmCache>,
- registry_url: &Url,
) -> Result<(), AnyError> {
let mut handles = Vec::with_capacity(packages.len());
for package in packages {
let cache = cache.clone();
- let registry_url = registry_url.clone();
let handle = spawn(async move {
- cache
- .ensure_package(&package.id.nv, &package.dist, &registry_url)
- .await
+ cache.ensure_package(&package.id.nv, &package.dist).await
});
handles.push(handle);
}
diff --git a/cli/npm/managed/resolvers/global.rs b/cli/npm/managed/resolvers/global.rs
index 4b3c9d613..cfc57e591 100644
--- a/cli/npm/managed/resolvers/global.rs
+++ b/cli/npm/managed/resolvers/global.rs
@@ -32,7 +32,6 @@ use super::common::RegistryReadPermissionChecker;
pub struct GlobalNpmPackageResolver {
cache: Arc<NpmCache>,
resolution: Arc<NpmResolution>,
- registry_url: Url,
system_info: NpmSystemInfo,
registry_read_permission_checker: RegistryReadPermissionChecker,
}
@@ -41,18 +40,16 @@ impl GlobalNpmPackageResolver {
pub fn new(
fs: Arc<dyn FileSystem>,
cache: Arc<NpmCache>,
- registry_url: Url,
resolution: Arc<NpmResolution>,
system_info: NpmSystemInfo,
) -> Self {
Self {
cache: cache.clone(),
resolution,
- registry_url: registry_url.clone(),
system_info,
registry_read_permission_checker: RegistryReadPermissionChecker::new(
fs,
- cache.registry_folder(&registry_url),
+ cache.root_folder(),
),
}
}
@@ -84,11 +81,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
.resolution
.resolve_pkg_cache_folder_id_from_pkg_id(id)
.unwrap();
- Ok(
- self
- .cache
- .package_folder_for_id(&folder_id, &self.registry_url),
- )
+ Ok(self.cache.package_folder_for_id(&folder_id))
}
fn resolve_package_folder_from_package(
@@ -99,7 +92,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
) -> Result<PathBuf, AnyError> {
let Some(referrer_pkg_id) = self
.cache
- .resolve_package_folder_id_from_specifier(referrer, &self.registry_url)
+ .resolve_package_folder_id_from_specifier(referrer)
else {
bail!("could not find npm package for '{}'", referrer);
};
@@ -119,32 +112,14 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
self.package_folder(&pkg.id)
}
- fn resolve_package_folder_from_specifier(
- &self,
- specifier: &ModuleSpecifier,
- ) -> Result<Option<PathBuf>, AnyError> {
- let Some(pkg_folder_id) = self
- .cache
- .resolve_package_folder_id_from_specifier(specifier, &self.registry_url)
- else {
- return Ok(None);
- };
- Ok(Some(
- self
- .cache
- .package_folder_for_id(&pkg_folder_id, &self.registry_url),
- ))
- }
-
fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
) -> Result<Option<NpmPackageCacheFolderId>, AnyError> {
Ok(
- self.cache.resolve_package_folder_id_from_specifier(
- specifier,
- &self.registry_url,
- ),
+ self
+ .cache
+ .resolve_package_folder_id_from_specifier(specifier),
)
}
@@ -153,19 +128,13 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
.resolution
.all_system_packages_partitioned(&self.system_info);
- cache_packages(
- package_partitions.packages,
- &self.cache,
- &self.registry_url,
- )
- .await?;
+ cache_packages(package_partitions.packages, &self.cache).await?;
// create the copy package folders
for copy in package_partitions.copy_packages {
- self.cache.ensure_copy_package(
- &copy.get_package_cache_folder_id(),
- &self.registry_url,
- )?;
+ self
+ .cache
+ .ensure_copy_package(&copy.get_package_cache_folder_id())?;
}
Ok(())
diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs
index f8d69d148..9d0ca3f8c 100644
--- a/cli/npm/managed/resolvers/local.rs
+++ b/cli/npm/managed/resolvers/local.rs
@@ -58,7 +58,6 @@ pub struct LocalNpmPackageResolver {
cache: Arc<NpmCache>,
progress_bar: ProgressBar,
resolution: Arc<NpmResolution>,
- registry_url: Url,
root_node_modules_path: PathBuf,
root_node_modules_url: Url,
system_info: NpmSystemInfo,
@@ -70,7 +69,6 @@ impl LocalNpmPackageResolver {
fs: Arc<dyn deno_fs::FileSystem>,
cache: Arc<NpmCache>,
progress_bar: ProgressBar,
- registry_url: Url,
node_modules_folder: PathBuf,
resolution: Arc<NpmResolution>,
system_info: NpmSystemInfo,
@@ -80,7 +78,6 @@ impl LocalNpmPackageResolver {
cache,
progress_bar,
resolution,
- registry_url,
root_node_modules_url: Url::from_directory_path(&node_modules_folder)
.unwrap(),
root_node_modules_path: node_modules_folder.clone(),
@@ -126,6 +123,17 @@ impl LocalNpmPackageResolver {
.map(Some)
.map_err(|err| err.into())
}
+
+ fn resolve_package_folder_from_specifier(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Result<Option<PathBuf>, AnyError> {
+ let Some(local_path) = self.resolve_folder_for_specifier(specifier)? else {
+ return Ok(None);
+ };
+ let package_root_path = self.resolve_package_root(&local_path);
+ Ok(Some(package_root_path))
+ }
}
#[async_trait]
@@ -202,17 +210,6 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
);
}
- fn resolve_package_folder_from_specifier(
- &self,
- specifier: &ModuleSpecifier,
- ) -> Result<Option<PathBuf>, AnyError> {
- let Some(local_path) = self.resolve_folder_for_specifier(specifier)? else {
- return Ok(None);
- };
- let package_root_path = self.resolve_package_root(&local_path);
- Ok(Some(package_root_path))
- }
-
fn resolve_package_cache_folder_id_from_specifier(
&self,
specifier: &ModuleSpecifier,
@@ -231,7 +228,6 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
&self.resolution.snapshot(),
&self.cache,
&self.progress_bar,
- &self.registry_url,
&self.root_node_modules_path,
&self.system_info,
)
@@ -254,7 +250,6 @@ async fn sync_resolution_with_fs(
snapshot: &NpmResolutionSnapshot,
cache: &Arc<NpmCache>,
progress_bar: &ProgressBar,
- registry_url: &Url,
root_node_modules_dir_path: &Path,
system_info: &NpmSystemInfo,
) -> Result<(), AnyError> {
@@ -317,12 +312,9 @@ async fn sync_resolution_with_fs(
let pb = progress_bar.clone();
let cache = cache.clone();
- let registry_url = registry_url.clone();
let package = package.clone();
let handle = spawn(async move {
- cache
- .ensure_package(&package.id.nv, &package.dist, &registry_url)
- .await?;
+ cache.ensure_package(&package.id.nv, &package.dist).await?;
let pb_guard = pb.update_with_prompt(
ProgressMessagePrompt::Initialize,
&package.id.nv.to_string(),
@@ -332,8 +324,8 @@ async fn sync_resolution_with_fs(
join_package_name(&sub_node_modules, &package.id.nv.name);
fs::create_dir_all(&package_path)
.with_context(|| format!("Creating '{}'", folder_path.display()))?;
- let cache_folder = cache
- .package_folder_for_name_and_version(&package.id.nv, &registry_url);
+ let cache_folder =
+ cache.package_folder_for_name_and_version(&package.id.nv);
if hard_link_dir_recursive(&cache_folder, &package_path).is_err() {
// Fallback to copying the directory.
//
diff --git a/cli/npm/managed/resolvers/mod.rs b/cli/npm/managed/resolvers/mod.rs
index dfd291afc..d5472344a 100644
--- a/cli/npm/managed/resolvers/mod.rs
+++ b/cli/npm/managed/resolvers/mod.rs
@@ -7,7 +7,6 @@ mod local;
use std::path::PathBuf;
use std::sync::Arc;
-use deno_core::url::Url;
use deno_npm::NpmSystemInfo;
use deno_runtime::deno_fs::FileSystem;
@@ -25,7 +24,6 @@ pub fn create_npm_fs_resolver(
fs: Arc<dyn FileSystem>,
cache: Arc<NpmCache>,
progress_bar: &ProgressBar,
- registry_url: Url,
resolution: Arc<NpmResolution>,
maybe_node_modules_path: Option<PathBuf>,
system_info: NpmSystemInfo,
@@ -35,7 +33,6 @@ pub fn create_npm_fs_resolver(
fs,
cache,
progress_bar.clone(),
- registry_url,
node_modules_folder,
resolution,
system_info,
@@ -43,7 +40,6 @@ pub fn create_npm_fs_resolver(
None => Arc::new(GlobalNpmPackageResolver::new(
fs,
cache,
- registry_url,
resolution,
system_info,
)),
diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs
index 143c1824d..042d3c3c6 100644
--- a/cli/standalone/binary.rs
+++ b/cli/standalone/binary.rs
@@ -537,7 +537,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
self
.client
- .download_with_progress(download_url, &progress)
+ .download_with_progress(download_url, None, &progress)
.await?
};
let bytes = match maybe_bytes {
@@ -670,9 +670,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
} else {
// DO NOT include the user's registry url as it may contain credentials,
// but also don't make this dependent on the registry url
- let registry_url = npm_resolver.registry_base_url();
- let root_path =
- npm_resolver.registry_folder_in_global_cache(registry_url);
+ let root_path = npm_resolver.global_cache_root_folder();
let mut builder = VfsBuilder::new(root_path)?;
for package in npm_resolver.all_system_packages(&self.npm_system_info)
{
diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs
index 288618287..1c081bc86 100644
--- a/cli/standalone/mod.rs
+++ b/cli/standalone/mod.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+use crate::args::create_default_npmrc;
use crate::args::get_root_cert_store;
use crate::args::npm_pkg_req_ref_to_binary_command;
use crate::args::CaData;
@@ -349,7 +350,8 @@ pub async fn run(
let root_path = std::env::temp_dir()
.join(format!("deno-compile-{}", current_exe_name))
.join("node_modules");
- let npm_cache_dir = NpmCacheDir::new(root_path.clone());
+ let npm_cache_dir =
+ NpmCacheDir::new(root_path.clone(), vec![npm_registry_url.clone()]);
let npm_global_cache_dir = npm_cache_dir.get_cache_location();
let cache_setting = CacheSetting::Only;
let (package_json_deps_provider, fs, npm_resolver, maybe_vfs_root) =
@@ -363,7 +365,7 @@ pub async fn run(
let vfs_root_dir_path = if node_modules_dir {
root_path
} else {
- npm_cache_dir.registry_folder(&npm_registry_url)
+ npm_cache_dir.root_dir().to_owned()
};
let vfs = load_npm_vfs(vfs_root_dir_path.clone())
.context("Failed to load npm vfs.")?;
@@ -392,8 +394,10 @@ pub async fn run(
CliNpmResolverManagedPackageJsonInstallerOption::ConditionalInstall(
package_json_deps_provider.clone(),
),
- npm_registry_url,
npm_system_info: Default::default(),
+ // Packages from different registries are already inlined in the ESZip,
+ // so no need to create actual `.npmrc` configuration.
+ npmrc: create_default_npmrc(),
}),
)
.await?;
@@ -448,8 +452,10 @@ pub async fn run(
CliNpmResolverManagedPackageJsonInstallerOption::ConditionalInstall(
package_json_deps_provider.clone(),
),
- npm_registry_url,
npm_system_info: Default::default(),
+ // Packages from different registries are already inlined in the ESZip,
+ // so no need to create actual `.npmrc` configuration.
+ npmrc: create_default_npmrc(),
}),
)
.await?;
diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs
index 82a44de16..e0cb5a222 100644
--- a/cli/tools/installer.rs
+++ b/cli/tools/installer.rs
@@ -139,7 +139,7 @@ pub async fn infer_name_from_url(url: &Url) -> Option<String> {
if url.path() == "/" {
let client = HttpClient::new(None, None);
- if let Ok(res) = client.get_redirected_response(url.clone()).await {
+ if let Ok(res) = client.get_redirected_response(url.clone(), None).await {
url = res.url().clone();
}
}
diff --git a/cli/tools/upgrade.rs b/cli/tools/upgrade.rs
index 8379c6fd2..00e7a2d57 100644
--- a/cli/tools/upgrade.rs
+++ b/cli/tools/upgrade.rs
@@ -619,7 +619,7 @@ async fn download_package(
// text above which will stay alive after the progress bars are complete
let progress = progress_bar.update("");
client
- .download_with_progress(download_url, &progress)
+ .download_with_progress(download_url, None, &progress)
.await?
};
match maybe_bytes {