diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2022-09-13 11:59:01 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-13 11:59:01 -0400 |
commit | 73efed218fe94ab27e89675ee238e2933b3fd4d1 (patch) | |
tree | 6961287971d127599a90a348bb6a9bc6256f7cd9 /cli/npm/resolvers/global.rs | |
parent | 51ba4764d1ca089eb65d333eb8797e064ac4c550 (diff) |
refactor(npm): create general use `NpmPackageResolver` (#15882)
Diffstat (limited to 'cli/npm/resolvers/global.rs')
-rw-r--r-- | cli/npm/resolvers/global.rs | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/cli/npm/resolvers/global.rs b/cli/npm/resolvers/global.rs new file mode 100644 index 000000000..259d9b9a0 --- /dev/null +++ b/cli/npm/resolvers/global.rs @@ -0,0 +1,138 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +use std::io::ErrorKind; +use std::path::Path; +use std::sync::Arc; + +use deno_ast::ModuleSpecifier; +use deno_core::error::AnyError; +use deno_core::futures::future::BoxFuture; +use deno_core::futures::FutureExt; +use deno_core::url::Url; + +use crate::npm::resolution::NpmResolution; +use crate::npm::resolvers::common::cache_packages; +use crate::npm::NpmCache; +use crate::npm::NpmPackageId; +use crate::npm::NpmPackageReq; +use crate::npm::NpmRegistryApi; + +use super::common::InnerNpmPackageResolver; +use super::common::LocalNpmPackageInfo; + +#[derive(Debug, Clone)] +pub struct GlobalNpmPackageResolver { + cache: NpmCache, + resolution: Arc<NpmResolution>, + registry_url: Url, +} + +impl GlobalNpmPackageResolver { + pub fn new(cache: NpmCache, api: NpmRegistryApi) -> Self { + let registry_url = api.base_url().to_owned(); + let resolution = Arc::new(NpmResolution::new(api)); + + Self { + cache, + resolution, + registry_url, + } + } + + fn local_package_info(&self, id: &NpmPackageId) -> LocalNpmPackageInfo { + LocalNpmPackageInfo { + folder_path: self.cache.package_folder(id, &self.registry_url), + id: id.clone(), + } + } +} + +impl InnerNpmPackageResolver for GlobalNpmPackageResolver { + fn resolve_package_from_deno_module( + &self, + pkg_req: &NpmPackageReq, + ) -> Result<LocalNpmPackageInfo, AnyError> { + let pkg = self.resolution.resolve_package_from_deno_module(pkg_req)?; + Ok(self.local_package_info(&pkg.id)) + } + + fn resolve_package_from_package( + &self, + name: &str, + referrer: &ModuleSpecifier, + ) -> Result<LocalNpmPackageInfo, AnyError> { + let referrer_pkg_id = self + .cache + .resolve_package_id_from_specifier(referrer, &self.registry_url)?; + let pkg = self + .resolution + .resolve_package_from_package(name, &referrer_pkg_id)?; + Ok(self.local_package_info(&pkg.id)) + } + + fn resolve_package_from_specifier( + &self, + specifier: &ModuleSpecifier, + ) -> Result<LocalNpmPackageInfo, AnyError> { + let pkg_id = self + .cache + .resolve_package_id_from_specifier(specifier, &self.registry_url)?; + Ok(self.local_package_info(&pkg_id)) + } + + fn has_packages(&self) -> bool { + self.resolution.has_packages() + } + + fn add_package_reqs( + &self, + packages: Vec<NpmPackageReq>, + ) -> BoxFuture<'static, Result<(), AnyError>> { + let resolver = self.clone(); + async move { + resolver.resolution.add_package_reqs(packages).await?; + cache_packages( + resolver.resolution.all_packages(), + &resolver.cache, + &resolver.registry_url, + ) + .await + } + .boxed() + } + + fn ensure_read_permission(&self, path: &Path) -> Result<(), AnyError> { + let registry_path = self.cache.registry_folder(&self.registry_url); + ensure_read_permission(®istry_path, path) + } +} + +fn ensure_read_permission( + registry_path: &Path, + path: &Path, +) -> Result<(), AnyError> { + // allow reading if it's in the deno_dir node modules + if path.starts_with(®istry_path) + && path + .components() + .all(|c| !matches!(c, std::path::Component::ParentDir)) + { + // todo(dsherret): cache this? + if let Ok(registry_path) = std::fs::canonicalize(registry_path) { + match std::fs::canonicalize(path) { + Ok(path) if path.starts_with(registry_path) => { + return Ok(()); + } + Err(e) if e.kind() == ErrorKind::NotFound => { + return Ok(()); + } + _ => {} // ignore + } + } + } + + Err(deno_core::error::custom_error( + "PermissionDenied", + format!("Reading {} is not allowed", path.display()), + )) +} |