Skip to content

Commit

Permalink
overlays/yarn: update to 4.5.3
Browse files Browse the repository at this point in the history
  • Loading branch information
thatsmydoing committed Dec 24, 2024
1 parent a9fcf95 commit 5e98102
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 92 deletions.
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
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;
});

0 comments on commit 5e98102

Please sign in to comment.