fix(arborist): clean up orphaned scoped store entries in linked strategy#9441
Open
manzoorwanijk wants to merge 1 commit into
Open
fix(arborist): clean up orphaned scoped store entries in linked strategy#9441manzoorwanijk wants to merge 1 commit into
manzoorwanijk wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
In continuation of our exploration of using
install-strategy=linkedin the Gutenberg monorepo, which powers the WordPress Block Editor.Under
--install-strategy=linked, each external package is extracted into a content-addressed store entry keyed byname@version-hash.For scoped packages the key contains the unescaped scope slash, so the entry nests one extra directory level:
node_modules/.store/@scope/pkg@version-hash/node_modules/@scope/pkg.The store key itself spans two path segments.
When a scoped dependency is updated or removed, the orphan-cleanup pass in
#cleanOrphanedStoreEntriesfailed to remove the stale store entry, so the store accumulated dead scoped entries on every update.This never happened for unscoped packages.
The root cause is that the cleanup made a single-segment assumption in two places.
When collecting valid keys from the ideal tree,
loc.split('/')[2]returned just@scopeinstead of the full@scope/pkg@version-hashkey.When enumerating on-disk entries, the non-recursive
readdir(storeDir)returned the@scopedirectory as a single entry and never descended into the per-version subdirectories inside it.The orphan filter then compared
@scopeon disk against@scopein the valid set, so the scope directory was always considered valid and never swept, no matter how many stale versions it contained.Fixed by reconstructing the full two-segment key for scoped entries when collecting valid keys, and by descending one level into each
@scopedirectory when enumerating on-disk entries so the real per-version entries are listed and compared as full keys.Both sides are compared in forward-slash form, matching how ideal-tree locations are already normalized, so
resolvereconstructs the on-disk path correctly on POSIX and Windows.Removing the last scoped orphan under a scope would leave an empty
@scopedirectory behind, so after removing orphans the pass now prunes any scope directory that has become empty.References
Fixes #9440