Skip to content
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
merged 1 commit into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 4 additions & 22 deletions overlays/yarn/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,15 @@ let
berry2nix-src = fetchFromGitHub {
owner = "iknow";
repo = "berry2nix";
rev = "51129dab790cb832e8ab9dd34b6cd5a52d80514d";
sha256 = "sha256-amYnoqtmChi2O4GJv6Fqx+XIh8xIEpMbGy5sEMAmrcQ=";
rev = "83d3057e65cfdca1bb67ff14df983279e2dfbdaf";
sha256 = "sha256-DsuCKJbPEQLpPJgS1AfDZe46GwAS2NFhHNhPBQjU4Os=";
};

inherit (callPackage (berry2nix-src + "/yarn") {}) yarn-patched;

yarn-plugin-workspace-tools = fetchurl {
url = "https://repo.yarnpkg.com/${yarn-patched.version}/packages/plugin-workspace-tools/bin/@yarnpkg/plugin-workspace-tools.js";
sha256 = "sha256-hgBbcQ3fvrQP8bqAGsMLYcYM/WhyrBMQMUNVJY3dCxE=";
};

yarn-plugin-interactive-tools = fetchurl {
url = "https://repo.yarnpkg.com/${yarn-patched.version}/packages/plugin-interactive-tools/bin/@yarnpkg/plugin-interactive-tools.js";
sha256 = "sha256-coBeeoPdV3Y/FwerT6bb1TkaYPgnH8M/tVps0qVbEUM=";
};

yarn-plugin-version = fetchurl {
url = "https://repo.yarnpkg.com/${yarn-patched.version}/packages/plugin-version/bin/@yarnpkg/plugin-version.js";
sha256 = "sha256-JXucgc21umG5L1ok6nu5i5g6uKPlAKRfl318Dav57t4=";
};

yarn-plugin-outdated = fetchurl {
url = "https://raw.githubusercontent.com/mskelton/yarn-plugin-outdated/v3.2.4/bundles/@yarnpkg/plugin-outdated.js";
sha256 = "sha256-lB3TaXrcmPKr8sUfHjVMMP6WQoGyQFeNy5HXlUIOWfY=";
url = "https://raw.githubusercontent.com/mskelton/yarn-plugin-outdated/v4.0.1/bundles/@yarnpkg/plugin-outdated.js";
sha256 = "sha256-6cARNfm2Gyr3GrL4zpYnEa2GTm96t7tO3PjAAIOnvEo=";
};

yarn-plugin-iknow = fetchurl {
Expand All @@ -45,9 +30,6 @@ in
];
};
plugins = [
yarn-plugin-workspace-tools
yarn-plugin-interactive-tools
yarn-plugin-version
Comment on lines -48 to -50
Copy link
Contributor Author

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.

yarn-plugin-outdated
yarn-plugin-iknow
];
Expand Down
208 changes: 138 additions & 70 deletions overlays/yarn/direct-dedupe.patch
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`,
Expand All @@ -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}) => {
Expand All @@ -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`);
Expand All @@ -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;
});