More thoughts on conflict resolution, Adam-style :) 1. The starting use case is avoiding conflicting guava and google-collections on the same classpath. We'll enable that by offering an API to declare that a module (group+name) replaces/supersedes/deprecates a different module (group+name). This use is a starting point to more interesting use cases which I will describe in later. While designing the DSL and the behavior we need to be cautious about those other use cases, so that we can develop this feature incrementally. We will use guava an collections as an example.
2. In a standalone project, a guava-collections issue is not that problematic, it can be sorted out by editing the build file (change the dependencies, add an 'exclude', add force rule, etc.). The use case is getting interesting in on an enterprise level, where the organisation wants to solve the problem in the shared plugin suite, instead of getting each team solve the problem on their own. Well-known deprecations like collections-guava could be even encoded in Gradle out of the box, but that's a different topic. 3. Current APIs for influencing the dependency resolution (forcing versions, dependency resolve rules) offer only "unconditional" manipulation to the dependencies that are being resolved. Let's map the collections-guava problem to the current API: we could force collections to become guava via dependency resolve rule. The effect is: - only collections in graph - guava is used a) only guava in graph - guava is used b) both collections in graph - guava is used (collections are forced into guava) c) only collections in graph - guava is used This is what I mean by 'unconditional' manipulation - if collections appear in graph it is _always_ replaced with guava. And this is not quite what we want... 4. We want the replacement rule to get activated only when both collections and guava are in the graph. If only collections appear in the graph - there is no need to replace it with guava. Perhaps guava and collection is not the best example because early guava is completely backwards compatible with latest collections. So in theory, we could unconditionally replace collections with an early version of guava via existing dependency resolve rule API. However, let's imagine that replacement source and target are not that quite compatible or that someone is using an _early_ version of collections which is not quite compatible with _early_ guava. 5. The implementation is tricker than our current forcing/dependency resolve rules. Consider dependency graph traversal scenarios: - first we encounter collections, we happily use it and continue traversing. - then we encounter guava - oups - we need to evict already resolved module collections and continue traversing. (It's more complicated than that, as we resolve conflicts only when we cannot traverse any further). In fact, it does not really differ from the standard, version-based conflict resolution. I wanted to point out the difference between existing dependency resolve rules implementation. The latter does not need to consider already-resolved modules. 6. Other features to consider: - module is replaced with a set of modules ('spring' -> 'spring-core', 'spring-aop', etc.) - set of modules is replaced with a single module (I don't know any real example for that) - api module and impl module use consistent version 7. Given that there are more ways to influence the dependency resolution, and specifically, to replace/force certain dependencies with others we should think about improving diagnostics on why certain dependency ended up in the graph and why this particular version is used. Our reports and API already provides 'selection reason' information but I'm afraid it's not enough. A dependency can be manipulated during resolution by different rules, applied by different plugins and a flat information like 'dependency resolve rule was used' is not enough IMHO. There can be a stream of actions that affects the selected version of a dependency. 8. I made up my mind about the DSL. I'm easy and I can totally be convinced to something else. Yet, here's my current preference: a) I would reuse some existing low-level, imperative API, like the component rules or dependency resolve rules, for example: eachDependency { details -> if (details.target.name == 'google-collections') { details.replacedBy 'com.google.guava:guava' } } b) I would add some higher level api that would use a). For example: dependencies { components { modules("com.google.collections:google-collections").deprecatedBy("com.google.guava:guava") //or replacedBy(), supersededBy() } } Thoughts? On Fri, Aug 1, 2014 at 11:30 AM, Szczepan Faber <szcze...@gmail.com> wrote: > This is a typo, the spec is work in progress. Initially we thought > about 'replaces' but we've changed that into 'replacedBy' but I forgot > to reverse the source and target :) > > So: > > google-collections is replaced by guava > guava replaces google-collections > > Thanks for pointing this out. I'll do more speccing and get back to > the mailing list. > > Cheers! > > On Fri, Aug 1, 2014 at 9:38 AM, Heinrich Filter > <heinrich.fil...@mmiholdings.co.za> wrote: >> Hi Szczepan, >> >> I'm new around the Gradle community but would love to start contributing >> more. Please feel free to point out any "conventions" that I miss. >> >> For me the "replacedBy" keyword is a bit confusing. In your example: 'guava' >> was replace by 'google-collections'. In my mind that implies that >> 'google-collection' is the *newer* dependency and not, as you state in the >> doc, the older version. >> >> I would think that 'guava' rather *replaces* or *supersedes* >> 'google-collections'. >> >> Or am thinking about this the wrong way? >> >> Regards, >> Heinrich >> >> On 31 Jul 2014, at 3:27 PM, Szczepan Faber <szcze...@gmail.com> wrote: >> >>> Hey, >>> >>> I've started speccing improvements to conflict resolution here: >>> https://github.com/gradle/gradle/blob/master/design-docs/conflict-resolution-spec.md >>> (there's a big DSL mock-up down the bottom). >>> >>> It would be good to start discussing the DSL additions here on the >>> mailing list. Please give feedback about the DSL or the use cases, >>> etc. I haven't decided myself on the DSL :) I'll keep you in loop on >>> how the design goes. >>> >>> Cheers! >>> -- >>> Szczepan Faber >>> Core dev@gradle; Founder@mockito >>> >>> --------------------------------------------------------------------- >>> To unsubscribe from this list, please visit: >>> >>> http://xircles.codehaus.org/manage_email >>> >>> >> >> >> ********************************************************************** >> This email and all content are subject to the following disclaimer >> >> http://content.momentum.co.za/content/legal/disclaimer_email.htm >> >> ********************************************************************** >> >> --------------------------------------------------------------------- >> To unsubscribe from this list, please visit: >> >> http://xircles.codehaus.org/manage_email >> >> > > > > -- > Szczepan Faber > Core dev@gradle; Founder@mockito -- Szczepan Faber Core dev@gradle; Founder@mockito --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email