diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2023-09-30 12:06:38 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-30 12:06:38 -0400 |
commit | 8d24be1a59714761665516e0d78d25059608c29b (patch) | |
tree | aed0140b63441008cb9b549d44948f7a36a4f5f1 /cli/npm/managed/resolvers/global.rs | |
parent | 1cda3840ff673512f7c6d58fa8402c35c760bc3b (diff) |
refactor(npm): create `cli::npm::managed` module (#20740)
Creates the `cli::npm::managed` module and starts moving more
functionality into it.
Diffstat (limited to 'cli/npm/managed/resolvers/global.rs')
-rw-r--r-- | cli/npm/managed/resolvers/global.rs | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/cli/npm/managed/resolvers/global.rs b/cli/npm/managed/resolvers/global.rs new file mode 100644 index 000000000..25db62f73 --- /dev/null +++ b/cli/npm/managed/resolvers/global.rs @@ -0,0 +1,184 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +//! Code for global npm cache resolution. + +use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; + +use async_trait::async_trait; +use deno_ast::ModuleSpecifier; +use deno_core::anyhow::bail; +use deno_core::error::AnyError; +use deno_core::url::Url; +use deno_npm::resolution::PackageNotFoundFromReferrerError; +use deno_npm::NpmPackageCacheFolderId; +use deno_npm::NpmPackageId; +use deno_npm::NpmResolutionPackage; +use deno_npm::NpmSystemInfo; +use deno_runtime::deno_fs::FileSystem; +use deno_runtime::deno_node::NodePermissions; +use deno_runtime::deno_node::NodeResolutionMode; + +use crate::npm::NpmCache; + +use super::super::resolution::NpmResolution; +use super::common::cache_packages; +use super::common::types_package_name; +use super::common::NpmPackageFsResolver; +use super::common::RegistryReadPermissionChecker; + +/// Resolves packages from the global npm cache. +#[derive(Debug)] +pub struct GlobalNpmPackageResolver { + cache: Arc<NpmCache>, + resolution: Arc<NpmResolution>, + registry_url: Url, + system_info: NpmSystemInfo, + registry_read_permission_checker: RegistryReadPermissionChecker, +} + +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(®istry_url), + ), + } + } + + fn resolve_types_package( + &self, + package_name: &str, + referrer_pkg_id: &NpmPackageCacheFolderId, + ) -> Result<NpmResolutionPackage, Box<PackageNotFoundFromReferrerError>> { + let types_name = types_package_name(package_name); + self + .resolution + .resolve_package_from_package(&types_name, referrer_pkg_id) + } +} + +#[async_trait] +impl NpmPackageFsResolver for GlobalNpmPackageResolver { + fn root_dir_url(&self) -> &Url { + self.cache.root_dir_url() + } + + fn node_modules_path(&self) -> Option<PathBuf> { + None + } + + fn package_folder(&self, id: &NpmPackageId) -> Result<PathBuf, AnyError> { + let folder_id = self + .resolution + .resolve_pkg_cache_folder_id_from_pkg_id(id) + .unwrap(); + Ok( + self + .cache + .package_folder_for_id(&folder_id, &self.registry_url), + ) + } + + fn resolve_package_folder_from_package( + &self, + name: &str, + referrer: &ModuleSpecifier, + mode: NodeResolutionMode, + ) -> Result<PathBuf, AnyError> { + let Some(referrer_pkg_id) = self + .cache + .resolve_package_folder_id_from_specifier(referrer, &self.registry_url) + else { + bail!("could not find npm package for '{}'", referrer); + }; + let pkg = if mode.is_types() && !name.starts_with("@types/") { + // attempt to resolve the types package first, then fallback to the regular package + match self.resolve_types_package(name, &referrer_pkg_id) { + Ok(pkg) => pkg, + Err(_) => self + .resolution + .resolve_package_from_package(name, &referrer_pkg_id)?, + } + } else { + self + .resolution + .resolve_package_from_package(name, &referrer_pkg_id)? + }; + 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, + ), + ) + } + + async fn cache_packages(&self) -> Result<(), AnyError> { + let package_partitions = self + .resolution + .all_system_packages_partitioned(&self.system_info); + + cache_packages( + package_partitions.packages, + &self.cache, + &self.registry_url, + ) + .await?; + + // create the copy package folders + for copy in package_partitions.copy_packages { + self.cache.ensure_copy_package( + ©.get_package_cache_folder_id(), + &self.registry_url, + )?; + } + + Ok(()) + } + + fn ensure_read_permission( + &self, + permissions: &dyn NodePermissions, + path: &Path, + ) -> Result<(), AnyError> { + self + .registry_read_permission_checker + .ensure_registry_read_permission(permissions, path) + } +} |