On 27 Apr 2014, at 6:37 am, Szczepan Faber <szczepan.fa...@gradleware.com> wrote:
> Thanks Adam, that's the input I was looking for. Some more questions / > feedback below. > > On Mon, Apr 21, 2014 at 9:39 AM, Adam Murdoch <adam.murd...@gradleware.com> > wrote: > > On 20 Apr 2014, at 7:38 am, Szczepan Faber <szczepan.fa...@gradleware.com> > wrote: > >> I was asked by the client to perform a quick spike on conflict resolution >> rules. I decided spike it first before kicking off a discussion. Here're my >> findings. >> >> Intro. >> >> Currently, a version conflict means that there are modules with the same >> group+name but different version. However, there is also a different class >> of conflicts - different modules (different group or name) are conflicting >> and only one of them should be chosen. In the spike, the ResolutionStrategy >> a) allows declaring that certain modules are conflicting and b) allows to >> choose preferred module version in case of such conflict. >> >> Some specific use cases I found so far: >> >> 1. 'com.google.collections:google-collections' and 'com.google.guava:guava' >> are conflicting, prefer guava. >> 2. 'org.jboss.netty:netty' and 'io.netty:netty*' are conflicting, prefer >> io.netty. >> 3. 'org.springframework:spring' and 'org.springframework:spring-*' are >> conflicting, prefer 'org.springframework:spring-*' (for example, >> spring-core). >> 4. 'kafka:kafka_2.8.2' VS 'kafka:kafka_2.10' VS 'kafka:kafka' are >> conflicting, prefer _2.10 (say) >> 5. A team in an organization decided to extract a standalone project out of >> a bigger project. The group id of the modules moved to a new project needed >> to change. Now there's a risk that consumers will have problems with >> conflict resolution. > > You can boil this down to 3 use cases: > > 1. A given component moves to some new coordinates. This would be #1 and #2 > above. > 2. A given component is repackaged, by splitting it into a set of smaller > components. This would be #3 and #5 above. Groovy 1.x -> 2.x is another > example of this. > 3. A given component is build for multiple versions of some runtime. This > would be #4 above, where Scala is the runtime. > > You can generalise #1 and #2 into a ‘replaces’ abstraction: > > - com.google.guava:guava replaces com.google.collections.google-collections > - io.netty:netty-all replaces org.jboss.netty:netty > - io.netty:(everything except -all and -parent) replace org.jboss.netty:netty > - my.org:(a, b) replace my.old.org:ab > > This can also be used to model Maven relocations too. > > Given we know that a replaces b, we can do two things: > > 1. Detect conflicts. Only one of a or b can be present in the result. > 2. Resolve the conflict. The result should include a and not b. > > I like where this model is going. Not sure if 'replaces' is the right word. > At first sight I associate it with 'forcing', e.g. an unconditional > replacement. However, I cannot think about anything that is better. It ‘replaces’ in the sense of ‘supersedes’ or ‘is newer than’ or ‘should be used instead of’. Perhaps ‘supersedes’ is a better term. -- Adam Murdoch Gradle Co-founder http://www.gradle.org VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting http://www.gradleware.com Join us for Gradle Summit 2014, June 12th and 13th in Santa Clara, CA: http://www.gradlesummit.com