DependencyGraphBuilderTest.groovy

Clone Tools
  • last updated a few seconds ago
Constraints
Constraints: committers
 
Constraints: files
Constraints: dates
Fix test

  1. … 1 more file in changeset.
Introduce `failOnDynamicVersion`

This commit introduces a new dependency graph validation mode,

which will make sure that if dynamic versions are found in the

graph, then either they are superceded by another version (they

don't participate in selection) or the build should fail.

This means that, for example, if a version selector uses a

version range `[1.0, 2.0[`, the build will fail because in a

subsequent build the resolution may change.

However, if there are two selectors participating, say

`[1.0, 2.0[` and `1.5`, then we choose `1.5` because this version

is within the range. Even if newer versions are released, we

would _not_ change the resolution result.

  1. … 8 more files in changeset.
Remove deprecated constructor

  1. … 2 more files in changeset.
Introduce constraint inheritance API

  1. … 40 more files in changeset.
Add deprecation mechanism for configurations

  1. … 16 more files in changeset.
Sort module selectors

This commit reworks module selectors so that they are sorted

in an order which reduces the cost of module selection. We

make sure to put local (project) selectors first, then we

use selectors from locks (if any).

The next selectors are "latest" version selectors because

even if they are dynamic, they are likely to "win" selection.

Then, exact version selectors are sorted by version descending

, and last we add dynamic version selectors.

    • -14
    • +14
    ./DependencyGraphBuilderTest.groovy
  1. … 19 more files in changeset.
Rework exclude rule merging

As a follow-up to #9197, this commit properly fixes the

exclude rule merging algorithm, by completely rewriting

it. The new merging algorithm works by implementing the

minimal set of algebra operations that make sense to

minimize computation durations. In order to do this,

this commit introduces a number of exclude specs

(found in their own package) and factories to create

actual implementation of those specs.

Specs represent the different kind of excludes we can

find:

- excluding a group

- excluding a module (no group defined)

- excluding a group+module

- excluding an artifact of a group+module

- pattern-matching excludes

- unions of excludes

- intersections of excludes

With all those minimal bricks, factories are responsible

of generating consistent specs. The dumbest factory

will just generate new instances for everything. This

is the default factory.

Minimally, this factory has to be backed by an optimizing

factory, which will take care of handling special cases:

- union or intersection of a single spec

- union or intersection of 2 specs

- when one of them is null

- when both are equal

Then we have a factory which performs the minimal algebra

to minimize specs:

- unions of unions

- intersections of intersections

- union of a union and individual specs

- insection of an intersection and individual spec

- ...

This factory can be as smart as it can, but one must be

careful that it's worth it: some previously implemented

optimizations (like (A+B).A = A turned out to be costly

to detect, and didn't make it the final cut.

Last but not least, a caching factory is there to avoid

recomputing the same intersections and unions of specs

when we have already done the job. This is efficient if

the underlying (delegate) specs are easily compared,

which is the case thanks to the interning factory.

All in all, the delegation chain allows us to make

the algorithm fast and hopefully reliable, while

making it easier to debug.

  1. … 75 more files in changeset.
Optimize `ModuleVersionResolveException`

During resolution, we may throw a lot of `ModuleVersionResolveException`

or `ModuleVersionNotFoundException`. Often, one per repository, when

a version is not found in that repository. But in the end, the version

may be found, or a different version may be selected, in which case we

don't care about the failure, which is only used if _no version_ could

be selected.

As a consequence, we had a lot of overhead in both generating a stack

trace **and** an error message, that would never be used.

This commit reworks those special exceptions used during resolution so

that we avoid filling the stack trace (we don't care) and we create

the message lazily (only if it will actually be used).

  1. … 23 more files in changeset.
Support requested capabilities on external dependencies

This commit adds support for having requested capabilities

part of the module component selector, for external dependencies.

This means that if a component is using Gradle metadata, we can

read requested capabilities and honor them during selection.

This reworks where requested capabilities are stored, and in

particular moves them to the `ComponentSelector`, making them

properly part of the identity of a dependency. As such, two

dependencies requiring two different variants by using distinct

capabilities will now properly appear as two different dependencies

in the dependency graph, instead of two variants of the same

dependency.

  1. … 63 more files in changeset.
Initial support for optional features

This commit introduces initial support for optional features, by

implementing a way for a dependency declaration (currently *only* in

the DSL) to request variants of the target component that provide one

or more capabilities.

Previously to this change, selection was (simplified) done like this:

1. find the target component

2. select the variant of the target component which matches the requested

attributes

Now, selection introduces another step:

1. find the target component

2. filter variants by eliminating those which do not provide the requested

capabilities

3. select the variant in this list which matches the requested attributes

Several changes had to be implemented:

First, component metadata rules calling `addCapability` will now return

a component which capabilities _include_ the default capability.

Second, attribute filtering is done in a secondary step, which means that

if there are no variant matching the requested capabilities, we will immediately

fail.

  1. … 58 more files in changeset.
Split off value snapshotting and attributes related methods of TestUtil

  1. … 64 more files in changeset.
Provide an explicit `acceptor` and `rejector` to API for choosing dependency version

This will permit a single `ResolvedVersionConstraint` to have both a `prefer`

and a `require` version.

  1. … 14 more files in changeset.
Use an `ImmutableSet` to represent the configuration hierarchy

ImmutableSets are ordered and optimized for lookups. We happen to

call `contains` a lot on hierarchies, so using a `Set` should

optimize things a little.

  1. … 31 more files in changeset.
Mitigate performance regressions

The introduction of the enforced platform algorithms introduced a performance

regression. This commit contains several changes to mitigate the regression:

- avoid the creation if iterators during resolution

- cache the "constraints" computation so that the JIT can inline calls to `isConstraint`

- add heuristic to determine the potential "size" of a graph and avoid resizes of internal datastructures

  1. … 4 more files in changeset.
Implement alignment of heterogeneous modules

This commit reworks the alignment strategy for "virtual" platforms, in

case not all leaves have the same versions _and_ that there are inconsistencies

in the graph, like in the Jackson case.

  1. … 7 more files in changeset.
Normalize `ModuleIdentifier`

This commit reworks the `ComponentModuleIdentifier`/`ComponentModuleSelector`/`ModuleVersionSelector`

classes to use `ModuleIdentifier` under the hood, instead of storing denormalized strings. This has

the advantage that we can reduce the use of the module identifier factory, which is called very

often during dependency resolution. Sharing instances reduces the need for conversions, and makes

comparisons faster.

    • -10
    • +10
    ./DependencyGraphBuilderTest.groovy
  1. … 164 more files in changeset.
Cache parsing of version strings

The version parser is by far the largest contributor to garbage created during the

resolution of a large dependency graph. This commit creates a build scope version

parser which is shared and caches the result of parsing, avoiding the creation of

a significant number of arrays.

  1. … 45 more files in changeset.
Refactor graph visitors

* Update start parameter type to be the more specific RootGraphNode

* Add unit tests for DependencyLockingArtifactVisitor

  1. … 18 more files in changeset.
Honor constraint attribute during selection

This commit makes sure that attributes from all selectors are used during

selection, including the attributes from constraints. It does not, however,

make sure that those attributes are consistent (compatible).

  1. … 13 more files in changeset.
Honor dependency attributes when they override configuration attributes

This commit fixes artifact selection so that when we resolve artifacts, we also use

the attributes defined on the dependency itself, if ever. Before, when we were resolving

artifacts, only the consumer configuration attributes were used.

  1. … 23 more files in changeset.
Avoid accessing `ResolutionStrategy` for non-root components

To determine if a configuration should have dependency locking enabled,

we inspect the ResolutionStrategy for that configuration. However, we

were needlessly inspecting this for configurations in referenced

projects, leading to added contention.

With this change, we only inspect the resolution strategy for

configurations when building the component metadata for the root

component, not for any referenced project components.

  1. … 12 more files in changeset.
Track selection state of module within module itself

This change removes the selected `ComponentState` instance from both the `SelectorState` and `EdgeState` implementations.

The currently selected component is now owned solely by the `ModuleResolveState`.

Each `SelectorState` can either have a failure, or bind to a successfully resolved module.

Likewise, an `EdgeState` will either be linked to a `SelectorState` with a failure,

or will have a target component from the resolved module.

  1. … 7 more files in changeset.
Lock validation and persist through graph visitor

This introduces validation of graph resolution with the lock file.

Added or missing dependencies in the graph compared to the lock

file cause a failure.

The visitor doing the validation is also used for trigerring

the persistence of the result.

Fixes #4862

  1. … 28 more files in changeset.
Avoid some extraneous calls to ModuleConflictResolver

  1. … 2 more files in changeset.
Use ResolutionStrategy as entry point to active locking

Issue #3182

  1. … 13 more files in changeset.
Provide ResolvedVersionConstraint when resolving component id

The 'resolved' version constraint is critical to resolving the component id

for a given selector. In order to honour all constraints in the resolution

process, this `ResolvedVersionConstraint` will be composed of more than

just the constraints for a single selector.

With this change, the `ResolvedVersionConstraint` is constructed

prior to resolving the id, rather than being constructed as part of that

process.

  1. … 14 more files in changeset.
Rename id accessors for consistency

Use `ComponentIdentifier getId()`

Use `ModuleVersionIdentifier getModuleVersionId()`

    • -20
    • +20
    ./DependencyGraphBuilderTest.groovy
  1. … 67 more files in changeset.
Make it possible to fail on capability version conflict

If the configuration resolution strategy is set to fail on version conflict,

then capabilities will not automatically be upgraded to the latest version.

Instead, just like regular conflict resolution, dependendency resolution will

fail with an error listing the capability with the conflicting versions.

  1. … 3 more files in changeset.
Introduce `CapabilitiesExtension`

This commit adds a capabilities extension which can be applied to a project. If it's added, local

components gain the ability to declare capabilities. Currently, only the `java-library` plugin

supports capabilities, but it's expected that more plugins will add it (for example, the native

plugin), which explains why the extension lives in `core`.

When a project declares capabilities, they are bound to configurations. This lets us fail whenever

a local component capability conflicts with a transitive module capability. It will also let us

publish capabilities for local components in a subsequent commit.

  1. … 16 more files in changeset.
Remove unused `FeaturePreviews` field and constructor param

  1. … 3 more files in changeset.