summaryrefslogtreecommitdiff
path: root/cli/npm
diff options
context:
space:
mode:
authorNathan Whitaker <17734409+nathanwhit@users.noreply.github.com>2024-10-02 17:16:46 -0700
committerGitHub <noreply@github.com>2024-10-02 17:16:46 -0700
commit275418473e7bda2b0bd33c86ae54cf3ac8ac5341 (patch)
tree970102cfb05c67819678f4d29a08a0aaf354bed3 /cli/npm
parent1e0c9b8c5b85c6c18ecdef0374a945b361d6e79d (diff)
fix(install): store tags associated with package in node_modules dir (#26000)
Fixes #25998. Fixes https://github.com/denoland/deno/issues/25928. Originally I was just going to make this an error message instead of a panic, but once I got to a minimal repro I felt that this really should work. The panic occurs when you have `nodeModulesDir: manual` (or a package.json present), and you have an npm package with a tag in your deno.json (see the spec test that illustrates this). This code path only actually executes when trying to choose an appropriate package version from `node_modules/.deno`, so we should be able to fix it by storing some extra data at install time. The fix proposed here is to repurpose the `.initialized` file that we store in `node_modules` to store the tags associated with a package. Basically, if you have a version requirement with a tag (e.g. `npm:chalk@latest`), when we set up the node_modules folder for that package, we store the tag (`latest`) in `.initialized`. Then, when doing BYONM resolution, if we have a version requirement with a tag, we read that file and check if the tag is present. The downside is that we do more work when setting up `node_modules`. We _could_ do this only when BYONM is enabled, but that would have the downside of needing to re-run `deno install` when you switch from auto -> manual, though maybe that's not a big deal.
Diffstat (limited to 'cli/npm')
-rw-r--r--cli/npm/managed/resolvers/local.rs33
1 files changed, 31 insertions, 2 deletions
diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs
index edc7c7ea0..258c9bf3d 100644
--- a/cli/npm/managed/resolvers/local.rs
+++ b/cli/npm/managed/resolvers/local.rs
@@ -343,6 +343,14 @@ async fn sync_resolution_with_fs(
},
);
let packages_with_deprecation_warnings = Arc::new(Mutex::new(Vec::new()));
+
+ let mut package_tags: HashMap<&PackageNv, Vec<&str>> = HashMap::new();
+ for (package_req, package_nv) in snapshot.package_reqs() {
+ if let Some(tag) = package_req.version_req.tag() {
+ package_tags.entry(package_nv).or_default().push(tag);
+ }
+ }
+
for package in &package_partitions.packages {
if let Some(current_pkg) =
newest_packages_by_name.get_mut(&package.id.nv.name)
@@ -357,11 +365,29 @@ async fn sync_resolution_with_fs(
let package_folder_name =
get_package_folder_id_folder_name(&package.get_package_cache_folder_id());
let folder_path = deno_local_registry_dir.join(&package_folder_name);
+ let tags = package_tags
+ .get(&package.id.nv)
+ .map(|tags| tags.join(","))
+ .unwrap_or_default();
+ enum PackageFolderState {
+ UpToDate,
+ Uninitialized,
+ TagsOutdated,
+ }
let initialized_file = folder_path.join(".initialized");
+ let package_state = std::fs::read_to_string(&initialized_file)
+ .map(|s| {
+ if s != tags {
+ PackageFolderState::TagsOutdated
+ } else {
+ PackageFolderState::UpToDate
+ }
+ })
+ .unwrap_or(PackageFolderState::Uninitialized);
if !cache
.cache_setting()
.should_use_for_npm_package(&package.id.nv.name)
- || !initialized_file.exists()
+ || matches!(package_state, PackageFolderState::Uninitialized)
{
// cache bust the dep from the dep setup cache so the symlinks
// are forced to be recreated
@@ -371,6 +397,7 @@ async fn sync_resolution_with_fs(
let bin_entries_to_setup = bin_entries.clone();
let packages_with_deprecation_warnings =
packages_with_deprecation_warnings.clone();
+
cache_futures.push(async move {
tarball_cache
.ensure_package(&package.id.nv, &package.dist)
@@ -389,7 +416,7 @@ async fn sync_resolution_with_fs(
move || {
clone_dir_recursive(&cache_folder, &package_path)?;
// write out a file that indicates this folder has been initialized
- fs::write(initialized_file, "")?;
+ fs::write(initialized_file, tags)?;
Ok::<_, AnyError>(())
}
@@ -410,6 +437,8 @@ async fn sync_resolution_with_fs(
drop(pb_guard); // explicit for clarity
Ok::<_, AnyError>(())
});
+ } else if matches!(package_state, PackageFolderState::TagsOutdated) {
+ fs::write(initialized_file, tags)?;
}
let sub_node_modules = folder_path.join("node_modules");