Hi,
I'd like to make a change to how we resolve dynamic versions, in particular
when a module is published without a meta-data file. This would be a breaking
change.
Currently, to resolve a dynamic version for a given repository:
1. For each meta-data pattern:
1. List versions that match this pattern (using maven-metadata.xml or a
directory listing).
2. Order the versions from highest to lowest.
3. For each version that matches the version selector, check for the
meta-data file. If it exists, use this version.
2. For each artefact referenced in the dependency (usually just a jar):
1. For each artefact pattern:
1. List versions that match this pattern (using
maven-metadata.xml or a directory listing).
2. Order the versions from highest to lowest.
3. For each version that matches the version selector, check
for the artefact. If it exists, use this version.
There are a few issues with this:
1. If a meta-data file is not published for a module, then we scan all of the
versions looking for the meta-data file before starting the scan again looking
for the artefacts. For a 'latest.$status' version, this means scanning all of
the versions that have ever been published.
2. If a module switches from publishing to not publishing a meta-data file,
then the algorithm above will lock on to the highest version with a meta-data
file and ignore any later versions without a meta-data file.
3. For most repository layouts, we end up listing the same directory multiple
times, when meta-data files are not published.
Things get more complex when you add in multiple repositories, as we iterate
over the repositories applying the matching above and then choose the highest
version found from each repository, regardless of whether it has meta-data or
not.
I'd like to split the matching into 2 discrete stages: firstly, determine all
the potential versions without verifying that they exist, then scan this list
looking for the first version that exists. Specifically:
1. Calculate the set of candidate versions
1. For each meta-data pattern, if we've not seen this pattern yet, list
versions that match this pattern. Add to the set of candidates.
2. For each artefact pattern, if we've not seen this pattern yet, list
versions that match this pattern. Add to the set of candidates.
2. For each candidate version from highest to lowest
1. If this version does not match the version selector, skip.
2. For each meta-data pattern, check for the meta-data file. If it
exists:
1. Download and parse the meta-data.
2. If the version selector does not accept the meta-data, skip.
Otherwise, use this version.
3. Use default meta-data for this version. If the version selector does
not accept the meta-data, skip.
3. For each referenced artefact
1. For each artefact pattern, check for the artefact. If it
exists, use this version.
This addresses the above issues. It is also a step towards the overall
structure that we want for the dependency resolution algorithm, where as we
traverse dependencies in the graph, we resolve first to a set of candidate
versions and later narrow this down to a single version as we traverse the
graph and apply conflict resolution.
The downside of this change is that it will break a build that relies on the
behaviour for issue #2 above. That is, a build that:
1. Consumes a module that has switched from publishing meta-data files to not
publishing meta-data files, and
2. Expects that resolving adds an implicit 'and has a meta-data file' to the
version selector.
The workaround for these builds is to replace the dynamic version with either a
version range or a specific version, either in the dependency declarations or
via a forced version.
Given this, I think this is a reasonable breaking change to make.
--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com