-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
overlays/yarn: update to 4.5.3 #17
Merged
+142
−92
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,20 @@ | ||
commit 239734bddfc723ebe8be47ed49c0a83cee1f371f | ||
Author: Thomas Dy <[email protected]> | ||
Date: Tue Dec 24 14:34:30 2024 +0900 | ||
|
||
Add direct dedupe strategy | ||
|
||
diff --git a/packages/plugin-essentials/sources/dedupeUtils.ts b/packages/plugin-essentials/sources/dedupeUtils.ts | ||
index ec168dd..bcf2845 100644 | ||
index d29057a2..d76192ee 100644 | ||
--- a/packages/plugin-essentials/sources/dedupeUtils.ts | ||
+++ b/packages/plugin-essentials/sources/dedupeUtils.ts | ||
@@ -22,6 +22,14 @@ export enum Strategy { | ||
@@ -1,4 +1,4 @@ | ||
-import {Project, ResolveOptions, ThrowReport, Resolver, miscUtils, Descriptor, Package, Report, Cache, DescriptorHash} from '@yarnpkg/core'; | ||
+import {Project, ResolveOptions, ThrowReport, Resolver, miscUtils, Descriptor, Package, Report, Cache, DescriptorHash, Configuration} from '@yarnpkg/core'; | ||
import {formatUtils, structUtils, IdentHash, LocatorHash, MessageName, Fetcher, FetchOptions} from '@yarnpkg/core'; | ||
import micromatch from 'micromatch'; | ||
|
||
@@ -25,6 +25,14 @@ export enum Strategy { | ||
* - dependencies are never downgraded | ||
*/ | ||
HIGHEST = `highest`, | ||
|
@@ -17,18 +29,12 @@ index ec168dd..bcf2845 100644 | |
} | ||
|
||
export const acceptedStrategies = new Set(Object.values(Strategy)); | ||
@@ -80,6 +88,112 @@ const DEDUPE_ALGORITHMS: Record<Strategy, Algorithm> = { | ||
|
||
const updatedResolution = bestCandidate.locatorHash; | ||
@@ -132,6 +140,168 @@ const DEDUPE_ALGORITHMS: Record<Strategy, Algorithm> = { | ||
}); | ||
} | ||
|
||
+ const updatedPackage = project.originalPackages.get(updatedResolution); | ||
+ if (typeof updatedPackage === `undefined`) | ||
+ throw new Error(`Assertion failed: The package (${updatedResolution}) should have been registered`); | ||
+ | ||
+ if (updatedResolution === currentResolution) | ||
+ return null; | ||
+ | ||
+ return {descriptor, currentPackage, updatedPackage}; | ||
+ return [...deferredMap.values()].map(deferred => { | ||
+ return deferred.promise; | ||
+ }); | ||
+ }, | ||
+ direct: async (project, patterns, {resolver, fetcher, resolveOptions, fetchOptions}) => { | ||
|
@@ -45,7 +51,8 @@ index ec168dd..bcf2845 100644 | |
+ const directLocatorsByIdent = new Map<IdentHash, Set<LocatorHash>>(); | ||
+ for (const workspace of project.workspaces) { | ||
+ const addIdents = async (deps: Map<IdentHash, Descriptor>) => { | ||
+ for (const descriptor of deps.values()) { | ||
+ const normalizedMap = project.configuration.normalizeDependencyMap(deps); | ||
+ for (const descriptor of normalizedMap.values()) { | ||
+ const locators = locatorsByIdent.get(descriptor.identHash); | ||
+ if (typeof locators === `undefined`) | ||
+ throw new Error(`Assertion failed: The resolutions (${descriptor.identHash}) should have been registered`); | ||
|
@@ -55,78 +62,139 @@ index ec168dd..bcf2845 100644 | |
+ if (typeof pkg === `undefined`) | ||
+ throw new Error(`Assertion failed: The package (${locatorHash}) should have been registered`); | ||
+ | ||
+ return pkg.reference; | ||
+ return pkg; | ||
+ }); | ||
+ | ||
+ const candidates = await resolver.getSatisfying(descriptor, references, resolveOptions); | ||
+ | ||
+ const bestCandidate = candidates?.[0]; | ||
+ if (typeof bestCandidate === `undefined`) | ||
+ continue; | ||
+ | ||
+ miscUtils.getSetWithDefault(directLocatorsByIdent, descriptor.identHash).add(bestCandidate.locatorHash); | ||
+ try { | ||
+ // some resolvers (like the patch resolver) will throw if we don't | ||
+ // provide the resolved dependencies but we don't really care about | ||
+ // them | ||
+ const satisfying = await resolver.getSatisfying(descriptor, {}, references, resolveOptions); | ||
+ | ||
+ // if there are no results or the result list is not sorted we | ||
+ // can't know the actual "best" candidate | ||
+ if (satisfying.locators.length === 0 || !satisfying.sorted) { | ||
+ continue; | ||
+ } | ||
+ | ||
+ const bestCandidate = satisfying.locators[0]; | ||
+ miscUtils.getSetWithDefault(directLocatorsByIdent, descriptor.identHash).add(bestCandidate.locatorHash); | ||
+ } catch {} | ||
+ } | ||
+ }; | ||
+ | ||
+ await addIdents(workspace.manifest.dependencies); | ||
+ await addIdents(workspace.manifest.devDependencies); | ||
+ } | ||
+ | ||
+ return Array.from(project.storedDescriptors.values(), async descriptor => { | ||
+ if (patterns.length && !micromatch.isMatch(structUtils.stringifyIdent(descriptor), patterns)) | ||
+ return null; | ||
+ | ||
+ const deferredMap = new Map<DescriptorHash, miscUtils.Deferred<PackageUpdate>>( | ||
+ miscUtils.mapAndFilter(project.storedDescriptors.values(), descriptor => { | ||
+ // We only care about resolutions that are stored in the lockfile | ||
+ // (we shouldn't accidentally try deduping virtual packages) | ||
+ if (structUtils.isVirtualDescriptor(descriptor)) | ||
+ return miscUtils.mapAndFilter.skip; | ||
+ | ||
+ return [descriptor.descriptorHash, miscUtils.makeDeferred()]; | ||
+ }), | ||
+ ); | ||
+ | ||
+ for (const descriptor of project.storedDescriptors.values()) { | ||
+ const deferred = deferredMap.get(descriptor.descriptorHash); | ||
+ if (typeof deferred === `undefined`) | ||
+ throw new Error(`Assertion failed: The descriptor (${descriptor.descriptorHash}) should have been registered`); | ||
+ | ||
+ const currentResolution = project.storedResolutions.get(descriptor.descriptorHash); | ||
+ if (typeof currentResolution === `undefined`) | ||
+ throw new Error(`Assertion failed: The resolution (${descriptor.descriptorHash}) should have been registered`); | ||
+ | ||
+ // We only care about resolutions that are stored in the lockfile | ||
+ // (we shouldn't accidentally try deduping virtual packages) | ||
+ const currentPackage = project.originalPackages.get(currentResolution); | ||
+ if (typeof currentPackage === `undefined`) | ||
+ return null; | ||
+ | ||
+ // No need to try deduping packages that are not persisted, | ||
+ // they will be resolved again anyways | ||
+ if (!resolver.shouldPersistResolution(currentPackage, resolveOptions)) | ||
+ return null; | ||
+ | ||
+ const locators = locatorsByIdent.get(descriptor.identHash); | ||
+ if (typeof locators === `undefined`) | ||
+ throw new Error(`Assertion failed: The resolutions (${descriptor.identHash}) should have been registered`); | ||
+ | ||
+ // No need to choose when there's only one possibility | ||
+ if (locators.size === 1) | ||
+ return null; | ||
+ | ||
+ const references = [...locators].map(locatorHash => { | ||
+ const pkg = project.originalPackages.get(locatorHash); | ||
+ if (typeof pkg === `undefined`) | ||
+ throw new Error(`Assertion failed: The package (${locatorHash}) should have been registered`); | ||
+ | ||
+ return pkg.reference; | ||
+ }); | ||
+ | ||
+ let candidates = await resolver.getSatisfying(descriptor, references, resolveOptions); | ||
+ | ||
+ const directLocators = directLocatorsByIdent.get(descriptor.identHash); | ||
+ | ||
+ // If this ident is of a direct dependency, use only the candidates those | ||
+ // direct dependencies will use. If this results in no candidates, use | ||
+ // all candidates. | ||
+ if (typeof directLocators !== `undefined` && candidates !== null) { | ||
+ const filteredCandidates = candidates.filter(locator => directLocators.has(locator.locatorHash)); | ||
+ if (filteredCandidates.length > 0) { | ||
+ candidates = filteredCandidates; | ||
+ throw new Error(`Assertion failed: The package (${currentResolution}) should have been registered`); | ||
+ | ||
+ Promise.resolve().then(async () => { | ||
+ const dependencies = resolver.getResolutionDependencies(descriptor, resolveOptions); | ||
+ | ||
+ const resolvedDependencies = Object.fromEntries( | ||
+ await miscUtils.allSettledSafe( | ||
+ Object.entries(dependencies).map(async ([dependencyName, dependency]) => { | ||
+ const dependencyDeferred = deferredMap.get(dependency.descriptorHash); | ||
+ if (typeof dependencyDeferred === `undefined`) | ||
+ throw new Error(`Assertion failed: The descriptor (${dependency.descriptorHash}) should have been registered`); | ||
+ | ||
+ const dedupeResult = await dependencyDeferred.promise; | ||
+ if (!dedupeResult) | ||
+ throw new Error(`Assertion failed: Expected the dependency to have been through the dedupe process itself`); | ||
+ | ||
+ return [dependencyName, dedupeResult.updatedPackage]; | ||
+ }), | ||
+ ), | ||
+ ); | ||
+ | ||
+ if (patterns.length && !micromatch.isMatch(structUtils.stringifyIdent(descriptor), patterns)) | ||
+ return currentPackage; | ||
+ | ||
+ // No need to try deduping packages that are not persisted, | ||
+ // they will be resolved again anyways | ||
+ if (!resolver.shouldPersistResolution(currentPackage, resolveOptions)) | ||
+ return currentPackage; | ||
+ | ||
+ const candidateHashes = locatorsByIdent.get(descriptor.identHash); | ||
+ if (typeof candidateHashes === `undefined`) | ||
+ throw new Error(`Assertion failed: The resolutions (${descriptor.identHash}) should have been registered`); | ||
+ | ||
+ // No need to choose when there's only one possibility | ||
+ if (candidateHashes.size === 1) | ||
+ return currentPackage; | ||
+ | ||
+ const candidates = [...candidateHashes].map(locatorHash => { | ||
+ const pkg = project.originalPackages.get(locatorHash); | ||
+ if (typeof pkg === `undefined`) | ||
+ throw new Error(`Assertion failed: The package (${locatorHash}) should have been registered`); | ||
+ | ||
+ return pkg; | ||
+ }); | ||
+ | ||
+ let satisfying = await resolver.getSatisfying(descriptor, resolvedDependencies, candidates, resolveOptions); | ||
+ | ||
+ const directLocators = directLocatorsByIdent.get(descriptor.identHash); | ||
+ | ||
+ // If this ident is of a direct dependency, use only the candidates those | ||
+ // direct dependencies will use. If this results in no candidates, use | ||
+ // all candidates. | ||
+ if (typeof directLocators !== `undefined` && candidates !== null) { | ||
+ const filteredLocators = satisfying.locators.filter(locator => directLocators.has(locator.locatorHash)); | ||
+ if (filteredLocators.length > 0) { | ||
+ satisfying = { | ||
+ locators: filteredLocators, | ||
+ sorted: satisfying.sorted, | ||
+ }; | ||
+ } | ||
+ } | ||
+ } | ||
+ | ||
+ const bestCandidate = candidates?.[0]; | ||
+ if (typeof bestCandidate === `undefined`) | ||
+ return null; | ||
+ | ||
+ const updatedResolution = bestCandidate.locatorHash; | ||
+ const bestLocator = satisfying.locators?.[0]; | ||
+ if (typeof bestLocator === `undefined` || !satisfying.sorted) | ||
+ return currentPackage; | ||
+ | ||
+ const updatedPackage = project.originalPackages.get(bestLocator.locatorHash); | ||
+ if (typeof updatedPackage === `undefined`) | ||
+ throw new Error(`Assertion failed: The package (${bestLocator.locatorHash}) should have been registered`); | ||
+ | ||
+ return updatedPackage; | ||
+ }).then(async updatedPackage => { | ||
+ const resolvedPackage = await project.preparePackage(updatedPackage, {resolver, resolveOptions}); | ||
+ | ||
+ deferred.resolve({ | ||
+ descriptor, | ||
+ currentPackage, | ||
+ updatedPackage, | ||
+ resolvedPackage, | ||
+ }); | ||
+ }).catch(error => { | ||
+ deferred.reject(error); | ||
+ }); | ||
+ } | ||
+ | ||
const updatedPackage = project.originalPackages.get(updatedResolution); | ||
if (typeof updatedPackage === `undefined`) | ||
throw new Error(`Assertion failed: The package (${updatedResolution}) should have been registered`); | ||
return [...deferredMap.values()].map(deferred => { | ||
return deferred.promise; | ||
}); |
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All official yarn plugins are bundled into yarn as of v4.