On Wed, Sep 24, 2014 at 4:19 PM, Adam Murdoch <adam.murd...@gradleware.com> wrote:
> > On 25 Sep 2014, at 6:12 am, Daz DeBoer <darrell.deb...@gradleware.com> > wrote: > > So I'm battling a bit as to whether we should really be modelling these > replacements at the component level (using rules as suggested) or should be > designing these at a higher level, on some sort of new model concept. > > Reviewing some of the old emails on this, I found this from Adam: > > I think it’s still an open question as to whether we use the component >> (instance) meta-data rules or introduce a new type of meta data for streams >> of work and how they map to modules over time. >> If we decide to add this to component meta-data then we would use >> whatever DSL happens to be available for defining the component meta-data, >> which happens to be `dependencies.components.eachComponent`. We’d later add >> the modules(_) { … } convenience DSL. > > > So the alternative to component metadata rules will be modelling some new > data structure, which we've done in the current implementation with > "component module" (ComponentModuleMetadata). This doesn't quite represent > a 'stream of work', but perhaps it could evolve in that way. > > So the big question in my mind is do we: > a) Implement 'replaces/replacedBy' at the component instance level, and > configure it via component metadata rules > OR > b) Do a bit more work to model component replacements in the context of a > 'stream of work' and clearly separate the DSL from the metadata rules. > > > It feels like ultimately this is something we need to know at the > component instance level. Given an instance x, we need to know: > > 1. For each instance y that also appears in the graph, do x and y conflict? > 2. When x and y conflict, which one should we select? Do we replace x with > y or y with x? > 3. When x is replaced by y, which other instances must also be included in > the result? > 4. When x is replaced by y, which other instances must also be replaced by > y? > > #3 is for the case where a module is busted up into several others. #4 is > for the case where several modules are combined into a single module. This > can happen over time (eg groovy 1.x was busted up into pieces from groovy > 2.0 and later) and can happen as an aggregation (eg if I choose groovy-all > I need to pull all of the groovy modules out of the result). > > So this is the kind of model we want DependencyGraphBuilder to work with. > For now, it doesn’t need to be anywhere near this general, as there are > performance implications to trying to make this work generally with any > arbitrary set of instances. > > From the build author’s point of view, we want a different model. We > should be able to declare concrete and specific facts in the DSL and use > those facts to derive answers to the above questions. We don’t want to > expose the above questions in the DSL, at least not yet. > > The model we want to aim for is one where we describe the history of a > component instance: where did this instance come from? > > So, we have a few options for the user model: > > 1. This is just more stuff you add to the component instance meta-data. > Each component instance would describe its full history - all the other > component instances that it is newer than (ie replaces). Not literally - > you’d use some kind of declarative convenience. You’d use the existing > component meta-data rules to attach this history. > > 2. This is stuff you add to the meta-data about a module/component. We’d > use a new module meta-data rules DSL for this. > > 3. Some combination of the two, where there isn’t any concept of a > module/component, but there is a separate convenience DSL to describe the > history of all components instances with a particular module id, without > requiring the meta-data of each instance. > > The big downside of #1 is when there are transitive changes. For example: > a was replaced by b and then split into (c,d). Given this, if I end up with > a and d in the graph, I need to figure out that a and d conflict and that I > need to replace a with c and d. > > With #1, we’d need to find some meta-data for an instance of b in order to > apply the rule, even though b is never referenced in the graph. So I reckon > #1 is out. > That's a fair argument. So in effect it's not enough to know the metadata of the 2 nodes involved in the potential conflict, we'd also need metadata for intervening nodes in a replacement chain. Given this, maybe we should go with something very similar to Szczepan's original work, but using a different enclosing block (not 'components'). This block would represent logic where we deal with groups of components, be that modules, releasable units, etc. Something like: dependencies { units { // Need a better name for this module("com.google.collections:google- collections").replacedBy("com.google.guava:guava") releasableUnit("spring2") { module("org.springframework:spring-core") module("org.springframework:spring-beans") // Would need to list the entire set here, for the 'replacedBy' to work. } module("org.springframework:spring").replacedBy("spring2") } } Alternatively, we could go with using 'components' block, but ensure that all component-instance-rule methods are clearly named: dependencies { components { // component-instance-rules eachComponent { .. rule .. } eachComponent.forModule("org.google.collections:google-collections") { ... } // model configuration as above module("com.google.collections:google- collections").replacedBy("com.google.guava:guava") releasableUnit("spring2") { .... } } Feedback? We need to come up with a reasonable pattern for this DSL for 2.2 Daz > From a user’s point of view, there probably isn’t much difference between > #2 and #3. > > > > > On Wed, Sep 24, 2014 at 10:41 AM, Szczepan Faber <szcze...@gmail.com> > wrote: > >> Awesome feedback! Let's skype on it today. >> >> On Wed, Sep 24, 2014 at 5:50 PM, Daz DeBoer >> <darrell.deb...@gradleware.com> wrote: >> > Thanks Szczepan! >> > >> > I've finally found the time to get fully across this feature. I haven't >> yet >> > looked into the implementation. >> > >> > Here's some initial feedback on the model. >> > >> > 1. We've named this feature 'component replacements', but the modelling >> is >> > done at the "module" level (ComponentModuleMetadata). I don't think >> this is >> > ideal: I'd like to think about a 'replacement' being modelled at the >> > component level ("org:name:version" instead of "org:name"). In most >> cases >> > we'll consider all components with the same 'org:name as having the same >> > replacements, and the DSL would make it convenient to define this. But >> the >> > underlying model should associate 'replacements' with a component, I >> think. >> > 2. Eventually, we'd like a published component to contain replacement >> > information. For this to be convenient, we'd normally publish a >> component >> > and say it 'replaces' or 'supercedes' a set of other components. I >> think it >> > might be helpful to model the relationship in this way, using 'replaces' >> > rather than 'replaced by'. >> > >> > And on the DSL: >> > The DSLs for all of our 'rules' that apply to dependency resolution are >> > converging on a pattern that will hopefully allow them to be migrated >> into >> > the new configuration rule infrastructure at some stage. The pattern is: >> > >> > model-rule-type { >> > eachXXX { SomeMutableType mutable[, OtherType immutableInput]* -> >> > } >> > module("group:name") { SomeMutableType mutable[, OtherType >> > immutableInput]* -> >> > } >> > } >> > >> > Exceptions: >> > - For component selection rules, 'all' is used instead of >> > 'eachComponentSelection'. >> > - I'm thinking this works better as a partner method to 'module()' >> > - For component metadata rules, the module() method doesn't exist yet. >> > - For dependency resolve rules, the 'model-rule-type' containing element >> > doesn't exist. >> > >> > If we stick with the same pattern for component replacements, we'd have: >> > >> > dependencies { >> > components { >> > module("com.google.guava:guava") { ComponentSubstitutionDetails >> > component -> >> > >> > component.replacesModule("com.google.collections:google-collections") >> > } >> > } >> > } >> > >> > That's it for now. Thanks for restarting the discussion! >> > Daz >> > >> > On Wed, Sep 24, 2014 at 3:31 AM, Szczepan Faber <szcze...@gmail.com> >> wrote: >> >> >> >> Upcoming Gradle 2.2 contains new incubating component replacement >> rules: >> >> >> >> dependencies { >> >> components { >> >> >> >> >> module("com.google.collections:google-collections").replacedBy("com.google.guava:guava") >> >> } >> >> } >> >> >> >> See more in http://www.gradle.org/docs/nightly/release-notes. This >> >> declaration is used during conflict resolution, Gradle will prevent >> >> both collections and guava appear in the same dependency tree, >> >> preferring any version of guava over every version of collections. >> >> Most importantly, if the dependency tree _only_ contains collections >> >> it will _not_ be replaced (because there is no conflict). Multiple >> >> modules can have the same target replacement. However, we don't >> >> support (yet) having single module replaced by multiple modules. >> >> >> >> The full DSL in the current form, based on our previous discussion on >> >> the mailing list. I'm starting new email thread on purpose (for good >> >> or bad, let's see whether it helps). >> >> >> >> dependencies { >> >> components { >> >> //declaring replacement: >> >> >> >> >> module("com.google.collections:google-collections").replacedBy("com.google.guava:guava") >> >> >> module(someModuleIdentifier).replacedBy("com.google.guava:guava") >> >> >> >> //querying for the replacement target: >> >> ModuleIdentifier id = >> >> module("com.google.collections:google-collections").getReplacedBy() >> >> >> >> //querying for the replacement source: >> >> ModuleIdentifier id = >> >> module("com.google.collections:google-collections").getId() >> >> } >> >> } >> >> >> >> Javadoc (for interface names, etc.): >> >> >> >> >> http://www.gradle.org/docs/nightly/javadoc/org/gradle/api/artifacts/dsl/ComponentMetadataHandler.html#module(java.lang.Object) >> >> >> >> This DSL can grow to accommodate features like: >> >> a) replacing single module with a set of modules. I'd love to have >> >> this. I also want to make incremental progress. >> >> b) other component module metadata (e.g. releasable units, impl module >> >> consistent with api module). I'd love to have this, too. >> >> >> >> Let's confirm this API and/or make changes to it before 2.2 release. >> >> Other related APIs that we should have in mind (for consistency): >> >> >> >> 1. component selection rules: >> >> >> >> configurations.conf.resolutionStrategy { >> >> componentSelection { >> >> all { ComponentSelection selection -> >> >> if (selection.candidate.group == 'org.sample') { >> >> selection.reject("rejecting experimental") >> >> } >> >> } >> >> module("org.sample:api") { ComponentSelection selection -> >> >> if (selection.candidate.version == "1.1") { >> >> selection.reject("known bad version") >> >> } >> >> } >> >> } >> >> } >> >> >> >> 2. component metadata rules: >> >> >> >> dependencies { >> >> components { >> >> eachComponent { ComponentMetadataDetails details, >> >> IvyModuleDescriptor ivyModule -> >> >> if (details.id.group == 'my.org' && ivyModule.branch == >> >> 'testing') { >> >> details.changing = true >> >> } >> >> } >> >> } >> >> } >> >> >> >> Cheers! >> >> -- >> >> Szczepan Faber >> >> Core dev@gradle; Founder@mockito >> >> >> >> --------------------------------------------------------------------- >> >> To unsubscribe from this list, please visit: >> >> >> >> http://xircles.codehaus.org/manage_email >> >> >> >> >> > >> > >> > >> > -- >> > Darrell (Daz) DeBoer >> > http://www.gradleware.com >> >> >> >> -- >> Szczepan Faber >> Core dev@gradle; Founder@mockito >> >> --------------------------------------------------------------------- >> To unsubscribe from this list, please visit: >> >> http://xircles.codehaus.org/manage_email >> >> >> > > > -- > Darrell (Daz) DeBoer > http://www.gradleware.com > > > > -- > Adam Murdoch > Gradle Co-founder > http://www.gradle.org > CTO Gradleware Inc. - Gradle Training, Support, Consulting > http://www.gradleware.com > > > > -- Darrell (Daz) DeBoer http://www.gradleware.com