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.
05 May 19 8eb2d60dd9381720e4b95025e88a5eeffa81ef30
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
- 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.
27 Apr 19 efeecd680b3789217d92becf2ebcc7a390cfe129