On 9 April 2014 at 5:23:35 am, Peter Niederwieser ([email protected]) wrote:
All,
as we are improving component metadata rules, we need a way for a rule to
declare which metadata it is interested in. The current proposal is to do
this via typed callback parameters. For example:
dependencies {
components {
eachComponent { ComponentMetaDataDetails details,
IvyModuleDescriptor descriptor -> ... }
}
}
The rule above declares that it is interested in the generic metadata
(`ComponentMetaDataDetails`) and Ivy specific metadata
(`IvyModuleDescriptor`). Because it is interested in Ivy specific metadata,
the rule will only fire for Ivy components.
The set of potentially supported parameter types is open-ended. For example,
future Gradle versions may support a `ArtifactoryProperties` parameter type.
This raises some questions:
* The above looks very much like a model rule. (`details` is the object to
be mutated, `descriptor` is an input.) Should `eachComponent()` indeed
accept a `ModelRule`, now or in the future?
* If not, what should the Java API look like?
* Do we want to generate the closure-based Groovy API from the Java API, now
or in the future?
For the time being, I've hand-coded the Groovy API, but obviously we also
need a Java API.
Thanks for any insights.
Not sure it’s insightful, but here goes…
This is slightly different to the model rules we’ve implemented to date, but
not different to the types of rules we’ve discussed or conceptualised.
Disclaimer: I don’t have a good understand of the component model, so I could
be well off with what I’m about to say.
My understand is that conceptually we are transforming things (modules?) into
components, and this hook allows you to augment how that should be done. So
internally, there is a model rule that knows how to create components from
module descriptors (roughly). We want to supply extra configuration to the
created components, based on how they were created (i.e. what type of module
descriptor they were created from). So, this is a model rule where the bindings
are relative to the rule the created the thing to mutate.
We currently don’t have any implementation for partially (potential other
names: speculatively, relatively) bound rules. Currently, the rule itself
dictates how it is bound to the model. In this case, The same rule can be
reused and be bound to different elements each time because the bindings are
not absolute. So, this is some context specific sugar that would somehow create
many absolutely bound rules (in some form) from the partially bound rule.
In terms of API, the complication here is that there are constraints on the
rule. It can only mutate a ComponentMetaDataDetails. Arbitrary targets don’t
make sense. I can’t see an easy way to express “first argument must be <T>, but
the rest are any <? extends X>”. Java’s type system isn’t up for this. We are
going to have this problem generally for the model rules of course.
One possibility for a general pattern would be something like…
interface Components {
void eachComponent(MutationRules<ComponentMetaDataDetails> rules) {}
}
abstract class MutationRules<T> {
public final T getTarget() {
// retrieve the target from some thread scoped global that we manage
}
}
components.eachComponent(new MutationRules<ComponentMetaDataDetails>>() {
// arbitrary methods in here that act as rules, with arbitrary signatures
})
We could then as a common pattern, transform this kind of method to…
void eachComponent(@DelegatesTo(ComponentMetaDataDetails) Closure<?> closure)
So the closure delegate is the target, and all of the closure params are inputs.
I’ll keep thinking on it.