There are a couple of different meanings for ‘conflict' here, so we should 
clarify which ones we’re talking about. One kind of conflict is when two 
consumers of a component ask for different version of that component. This may 
or may not be a problem, depending on the changes between the two requested 
versions. In the jvm world, this kind of conflict happens all the time and is 
not a problem maybe 80% of the time. Let’s call this kind of conflict a 
‘version mismatch’.

The other kind of conflict is where dependency resolution chooses some 
component implementation that is incompatible with some consumer, so that the 
code fails in odd ways at runtime. Let’s call this a ‘dependency conflict'. 
Some version mismatches lead to a dependency conflict, but not all version 
mismatches do (or even most). Dependency conflicts can also happen when 
dependencies are opaque to Gradle. Here are some examples:

- using file dependencies
- using `gradleApi()`
- when a project’s build script inherits stuff from one of its ancestor projects
- when the project’s classes conflict with something in the dependency graph
- when a thing provides the same classes as some other thing (eg log4j and 
log4j-over-slf4j).

So, there are two problems with switching on `failOnVersionConflict()` as a 
default. First, it fails on version mismatches rather than dependency 
conflicts, which means it will fail in perfectly valid cases. Secondly, it 
considers only (group, module, version) and so misses other sources for 
dependency conflicts.

Plus there’s the backwards compatibility issue.

Our plan to solve this problem has several parts:

1. Split the single build script dependency graph into a dependency graph per 
plugin, thereby making the graphs much smaller and the chance of a conflict 
much less likely. There will still be the chance of a conflict, if two plugins 
expose different versions of a thing via their APIs (an argument for not 
exposing the classes of a plugin to the build script as a default).

2. Fail on dependency conflict by default (but not version mismatch), and add 
various way for Gradle to infer when there is likely to be a dependency 
conflict. For example, the meta-data for a component might declare that ‘this 
component uses semantic versioning’, in which case we can fail when there is a 
version mismatch that requests different major versions. Or the meta-data for a 
component might declare that ‘this component works only with some-lib:1.2.3` 
and so on. Richer meta-data and dependency declarations, basically.

3. Make some of the opaque cases above more transparent. For example, for 
`gradleApi()` one part of Gradle knows exactly which versions of which 
components are included, but never passes this information on to the part of 
Gradle that does conflict resolution. Another example: In the native language 
plugins, there’s a way to attach meta-data to file dependencies, allowing 
conflict resolution to happen. The plan is to roll this back into the jvm world.

4. Add some real language-specific conflict detection. The stuff we plan to do 
for incremental java compilation means that we can do some conflict detection 
that considers the actual contents of the artefacts, rather than just their 
(group, name, version). For example, these two jars contain the same classes, 
so they may conflict, or this method has changed in an incompatible way, so 
there is a conflict.

You could summarise the last 3 points as: assume there is not a conflict but 
fail if we can infer that there is, and gradually add more cases that we can 
infer this for.


On 24 Dec 2013, at 7:40 am, Xavier Ducrohet <x...@google.com> wrote:

> What I'm wondering if this should become a default though.
> 
> Most people won't know what's going on when they apply two plugins with 
> incompatible dependencies and the lack of diagnostic output doesn't help. I 
> do realize it might break compatibility for some (many?) people but that 
> would be easy to fix in the build file anyway and it just seem safer to me.
> 
> 
> On Mon, Dec 23, 2013 at 12:33 PM, Luke Daley <luke.da...@gradleware.com> 
> wrote:
> You can do this today by:
> 
> buildscript {
>   configurations.classpath.resolutionStrategy.failOnVersionConflict()
> 
> }
> 
> When is it planned for?
> 
> It's something we are working on, but it's probably going to be at least 2 - 
> 3 release cycles at best before it would effectively resolve this kind of 
> problem.
> 
> 
> On 23 Dec 2013, at 20:23, Xavier Ducrohet wrote:
> 
> That makes sense. I'm glad to hear it's coming.
> 
> When is it planned for? If it's in a while, would it be possible to make
> resolution strict for plugin classpath (ie, consider the dependencies to be
> exactly the version they declare, and break on all conflict)? this would
> make figuring out conflict easier and would still allow for fixing this
> through the conflict resolution already in place.
> 
> Xav
> 
> 
> On Sat, Dec 21, 2013 at 5:33 AM, Luke Daley <luke.da...@gradleware.com>wrote:
> 
> 
> On 20 Dec 2013, at 18:16, Xavier Ducrohet wrote:
> 
> Hello,
> 
> We have a user who had an issue with two different plugins that depended
> on
> different versions of ASM.
> 
> Is there a way to see the build script dependency graph (similar to
> running
> the dependencies task)?
> 
> 
> Not currently, though this would be something that would be good to add.
> It's a little more complex than the proper configurations to visualise, but
> we could do something.
> 
> 
> 
> Can the dependency conflict resolution apply to the build script
> classpath?
> 
> 
> It does right now.
> 
> 
> Is there any way to silo each plugin into their own separate classpath?
> This seems fragile right now.
> 
> 
> Not right now, but it's coming.
> 
> A naive approach of simply completely isolating each plugin into its own
> class loader doesn't work because then plugins can't collaborate. For
> example, my plugin that builds on the Android plugin wouldn't have access
> to the model classes from it because they'd be in a separate class loader.
> To make this work we essentially have to provide our own dependency based
> class loader visibility system like OSGi or ClassWorlds, which we have
> started planning.
> 
> Before we get there though there are some things we need to do:
> 
> 1. Allow plugin classpath to be derived at application time (right now the
> opposite is the case)
> 2. Allow plugins to declare their public types
> 3. Allow published plugins to declare their public/private classpaths
> 
> There is more detail in this spec: https://github.com/gradle/
> gradle/blob/master/design-docs/publishing-and-sharing-plugins.md
> 
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
> 
> http://xircles.codehaus.org/manage_email
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
> 
>    http://xircles.codehaus.org/manage_email
> 
> 
> 


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com



Reply via email to