summaryrefslogtreecommitdiff
path: root/cli/npm/managed/resolvers/global.rs
diff options
context:
space:
mode:
authorNathan Whitaker <17734409+nathanwhit@users.noreply.github.com>2024-09-24 12:23:57 -0700
committerGitHub <noreply@github.com>2024-09-24 19:23:57 +0000
commit36ebc03f177cc7db5deb93f4d403cafbed756eb5 (patch)
treec36af6c9b7093d3191de3cd6e60c4ce9dca4151a /cli/npm/managed/resolvers/global.rs
parentba5b8d0213cde2585236098b00beb8a512889626 (diff)
fix(cli): Warn on not-run lifecycle scripts with global cache (#25786)
Refactors the lifecycle scripts code to extract out the common functionality and then uses that to provide a warning in the global resolver. While ideally we would still support them with the global cache, for now a warning is at least better than the status quo (where people are unaware why their packages aren't working).
Diffstat (limited to 'cli/npm/managed/resolvers/global.rs')
-rw-r--r--cli/npm/managed/resolvers/global.rs100
1 files changed, 98 insertions, 2 deletions
diff --git a/cli/npm/managed/resolvers/global.rs b/cli/npm/managed/resolvers/global.rs
index 7f8f285f3..187e6b277 100644
--- a/cli/npm/managed/resolvers/global.rs
+++ b/cli/npm/managed/resolvers/global.rs
@@ -2,16 +2,19 @@
//! Code for global npm cache resolution.
+use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
+use crate::colors;
use async_trait::async_trait;
use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_core::url::Url;
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;
@@ -19,10 +22,14 @@ use node_resolver::errors::PackageFolderResolveError;
use node_resolver::errors::PackageNotFoundError;
use node_resolver::errors::ReferrerNotFoundError;
+use crate::args::LifecycleScriptsConfig;
+use crate::cache::FastInsecureHasher;
+
use super::super::cache::NpmCache;
use super::super::cache::TarballCache;
use super::super::resolution::NpmResolution;
use super::common::cache_packages;
+use super::common::lifecycle_scripts::LifecycleScriptsStrategy;
use super::common::NpmPackageFsResolver;
use super::common::RegistryReadPermissionChecker;
@@ -34,6 +41,7 @@ pub struct GlobalNpmPackageResolver {
resolution: Arc<NpmResolution>,
system_info: NpmSystemInfo,
registry_read_permission_checker: RegistryReadPermissionChecker,
+ lifecycle_scripts: LifecycleScriptsConfig,
}
impl GlobalNpmPackageResolver {
@@ -43,6 +51,7 @@ impl GlobalNpmPackageResolver {
tarball_cache: Arc<TarballCache>,
resolution: Arc<NpmResolution>,
system_info: NpmSystemInfo,
+ lifecycle_scripts: LifecycleScriptsConfig,
) -> Self {
Self {
registry_read_permission_checker: RegistryReadPermissionChecker::new(
@@ -53,6 +62,7 @@ impl GlobalNpmPackageResolver {
tarball_cache,
resolution,
system_info,
+ lifecycle_scripts,
}
}
}
@@ -149,8 +159,7 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
let package_partitions = self
.resolution
.all_system_packages_partitioned(&self.system_info);
-
- cache_packages(package_partitions.packages, &self.tarball_cache).await?;
+ cache_packages(&package_partitions.packages, &self.tarball_cache).await?;
// create the copy package folders
for copy in package_partitions.copy_packages {
@@ -159,6 +168,18 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
.ensure_copy_package(&copy.get_package_cache_folder_id())?;
}
+ let mut lifecycle_scripts =
+ super::common::lifecycle_scripts::LifecycleScripts::new(
+ &self.lifecycle_scripts,
+ GlobalLifecycleScripts::new(self, &self.lifecycle_scripts.root_dir),
+ );
+ for package in &package_partitions.packages {
+ let package_folder = self.cache.package_folder_for_nv(&package.id.nv);
+ lifecycle_scripts.add(package, Cow::Borrowed(&package_folder));
+ }
+
+ lifecycle_scripts.warn_not_run_scripts()?;
+
Ok(())
}
@@ -172,3 +193,78 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
.ensure_registry_read_permission(permissions, path)
}
}
+
+struct GlobalLifecycleScripts<'a> {
+ resolver: &'a GlobalNpmPackageResolver,
+ path_hash: u64,
+}
+
+impl<'a> GlobalLifecycleScripts<'a> {
+ fn new(resolver: &'a GlobalNpmPackageResolver, root_dir: &Path) -> Self {
+ let mut hasher = FastInsecureHasher::new_without_deno_version();
+ hasher.write(root_dir.to_string_lossy().as_bytes());
+ let path_hash = hasher.finish();
+ Self {
+ resolver,
+ path_hash,
+ }
+ }
+
+ fn warned_scripts_file(&self, package: &NpmResolutionPackage) -> PathBuf {
+ self
+ .package_path(package)
+ .join(format!(".scripts-warned-{}", self.path_hash))
+ }
+}
+
+impl<'a> super::common::lifecycle_scripts::LifecycleScriptsStrategy
+ for GlobalLifecycleScripts<'a>
+{
+ fn can_run_scripts(&self) -> bool {
+ false
+ }
+ fn package_path(&self, package: &NpmResolutionPackage) -> PathBuf {
+ self.resolver.cache.package_folder_for_nv(&package.id.nv)
+ }
+
+ fn warn_on_scripts_not_run(
+ &self,
+ packages: &[(&NpmResolutionPackage, PathBuf)],
+ ) -> std::result::Result<(), deno_core::anyhow::Error> {
+ log::warn!("{} The following packages contained npm lifecycle scripts ({}) that were not executed:", colors::yellow("Warning"), colors::gray("preinstall/install/postinstall"));
+ for (package, _) in packages {
+ log::warn!("┠─ {}", colors::gray(format!("npm:{}", package.id.nv)));
+ }
+ log::warn!("┃");
+ log::warn!(
+ "┠─ {}",
+ colors::italic("This may cause the packages to not work correctly.")
+ );
+ log::warn!("┠─ {}", colors::italic("Lifecycle scripts are only supported when using a `node_modules` directory."));
+ log::warn!(
+ "┠─ {}",
+ colors::italic("Enable it in your deno config file:")
+ );
+ log::warn!("┖─ {}", colors::bold("\"nodeModulesDir\": \"auto\""));
+
+ for (package, _) in packages {
+ std::fs::write(self.warned_scripts_file(package), "")?;
+ }
+ Ok(())
+ }
+
+ fn did_run_scripts(
+ &self,
+ _package: &NpmResolutionPackage,
+ ) -> std::result::Result<(), deno_core::anyhow::Error> {
+ Ok(())
+ }
+
+ fn has_warned(&self, package: &NpmResolutionPackage) -> bool {
+ self.warned_scripts_file(package).exists()
+ }
+
+ fn has_run(&self, _package: &NpmResolutionPackage) -> bool {
+ false
+ }
+}