Skip to content

Suboptimal logic when resolving selectors with dynamic ones #33593

@ljacomet

Description

@ljacomet

Current Behavior

When Gradle resolves a dynamic selector, it attempts to find a version that matches other potential selectors.
For example, with existing versions:

  • 1.2, 1.5, 1.8, 2.1

and with two selectors:

  • [1,2)
  • 1.5

Gradle would resolve 1.5 as it is the best fit. The range alone would have resolved 1.8.

As part of that resolution mechanism, Gradle iterates over all versions and checks their compatibility. One such check is about variants, to confirm that the selected version does have a variant that can match. But this requires downloading the metadata of the version, to resolve its variants.
Gradle also does two other checks that are local and could reject the version. But those checks are done after the check requiring the full metadata.

Expected Behavior

Move the full metadata check to be the last one done by Gradle. This can save quite a number of network requests in cases where the additional selector is not compatible with the range, like the following:

  • [1,2)
  • 2.1!!

Context (optional)

There are potentially multiple layers for this fix:

  • At the first level, we can change the order of the checks here:
    RejectedByAttributesVersion maybeRejectByAttributes = tryRejectByAttributes(candidateId, metadataProvider, consumerAttributes);
    if (maybeRejectByAttributes != null) {
    result.doesNotMatchConsumerAttributes(maybeRejectByAttributes);
    } else if (isRejectedBySelector(candidateId, rejectedVersionSelector)) {
    // Mark this version as rejected
    result.rejectedBySelector(candidateId, rejectedVersionSelector);
    } else {
    RejectedByRuleVersion rejectedByRules = isRejectedByRule(candidateId, rules, metadataProvider);
    if (rejectedByRules != null) {
    // Mark this version as rejected
    result.rejectedByRule(rejectedByRules);
    if (requestedVersionMatcher.matchesUniqueVersion()) {
    // Only consider one candidate, because matchesUniqueVersion means that there's no ambiguity on the version number
    break;
    }
    } else {
    result.matches(candidateId);
    return;
    }
    }
  • At a second level, Gradle could verify if the rejectedVersionSelector is compatible or not with the range. And possibly, fully skip the whole fetching of versions, since none will be a match.

Note that Gradle should consider porting this fix back to 7.x as that logic has not change since then.

Self-contained Reproducer Project

N/A but will add tests with the fix

Gradle version

all

Build scan URL (optional)

No response

Your Environment (optional)

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions