From a750314e0452cb8bd4688f274c95fec14556a91b Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:29:46 -0800 Subject: [PATCH] fix(install): don't re-set up node_modules if running lifecycle script (#26984) Fixes https://github.com/denoland/deno/issues/26904 If using `nodeModulesDir: "auto"`, it's possible for the lifecycle script subprocess to try to set up the node_modules dir (despite the fact that we're already doing that). If it does that, it hangs trying to acquire the file lock on the node_modules dir. As a fix, don't try to set up node_modules if we're running as part of a lifecycle script. Ideally we'd have better control over when we do and don't set up node_modules automatically (that's the underlying problem behind #25782 as well) --- .../managed/resolvers/common/lifecycle_scripts.rs | 13 +++++++++++++ cli/npm/managed/resolvers/local.rs | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/cli/npm/managed/resolvers/common/lifecycle_scripts.rs b/cli/npm/managed/resolvers/common/lifecycle_scripts.rs index 5c5755c819..f8b9e8a7e8 100644 --- a/cli/npm/managed/resolvers/common/lifecycle_scripts.rs +++ b/cli/npm/managed/resolvers/common/lifecycle_scripts.rs @@ -182,6 +182,12 @@ impl<'a> LifecycleScripts<'a> { ); let mut env_vars = crate::task_runner::real_env_vars(); + // so the subprocess can detect that it is running as part of a lifecycle script, + // and avoid trying to set up node_modules again + env_vars.insert( + LIFECYCLE_SCRIPTS_RUNNING_ENV_VAR.to_string(), + "1".to_string(), + ); // we want to pass the current state of npm resolution down to the deno subprocess // (that may be running as part of the script). we do this with an inherited temp file // @@ -303,6 +309,13 @@ impl<'a> LifecycleScripts<'a> { } } +const LIFECYCLE_SCRIPTS_RUNNING_ENV_VAR: &str = + "DENO_INTERNAL_IS_LIFECYCLE_SCRIPT"; + +pub fn is_running_lifecycle_script() -> bool { + std::env::var(LIFECYCLE_SCRIPTS_RUNNING_ENV_VAR).is_ok() +} + // take in all (non copy) packages from snapshot, // and resolve the set of available binaries to create // custom commands available to the task runner diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs index 50c5bd2689..ca7867425d 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/managed/resolvers/local.rs @@ -298,6 +298,12 @@ async fn sync_resolution_with_fs( return Ok(()); // don't create the directory } + // don't set up node_modules (and more importantly try to acquire the file lock) + // if we're running as part of a lifecycle script + if super::common::lifecycle_scripts::is_running_lifecycle_script() { + return Ok(()); + } + let deno_local_registry_dir = root_node_modules_dir_path.join(".deno"); let deno_node_modules_dir = deno_local_registry_dir.join("node_modules"); fs::create_dir_all(&deno_node_modules_dir).with_context(|| {