On 26 Sep 2014, at 4:44 am, Daz DeBoer <darrell.deb...@gradleware.com> wrote:
> 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 I’d just call them ‘modules’ for now. The logic applies to components that happen to be published as modules in an ivy/maven repo. > > 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”) I would make these blocks: module(“…”) { ModuleMetaDataDetails module -> … some stuff about the module ... } eachModule { ModuleMetaDataDetails module -> … } > } > } > > 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 -- Adam Murdoch Gradle Co-founder http://www.gradle.org CTO Gradleware Inc. - Gradle Training, Support, Consulting http://www.gradleware.com