On Tue, May 7, 2013 at 8:50 AM, Adam Murdoch <adam.murd...@gradleware.com>wrote:
> Hi, > > For the C++ support, I'd like to make use of the deferred configuration > stuff. This will mean growing it to make it more usable. > > There are 2 use cases I'd like to use deferred configuration for: > > 1. Defer creation of tasks until we know which binaries to build. This > allows the creation of tool chain specific task implementations. We might > also use this to skip creation of tasks for binaries that cannot be built > locally. > > 2. Add default variants when none defined. This allows us to select a tool > chain based on whatever's available and add a variant for this. > > For use case #1, this means being able to register some logic that runs > after a domain object has been configured. For use case #2, this means > being able to register some logic that runs just before a domain object is > made available for consumption, but after all other configuration logic. > > One simple option is to allow the plugin that defines an extension (and > only that plugin) to register an action to run once the extension is > configured. This action can take care of both #1 and #2: > > project.extensions.createDeferred('libraries', NativeLibraries.class, { … > define defaults and then create tasks ... }) > > A couple of downsides: The main one is that there's no way to configure > the domain object without creating the tasks for that domain object and we > want to move away from this. The other is that there's no way to override > the 'infer the defaults' logic or the 'create the tasks' logic - it's baked > into the definition of the domain object. > > A similar option is to allow logic to be registered that fires at various > points in the domain object's lifecycle: > > // Define a delayed extension (replaces @DeferredConfigurable) and return > a promise for the result > Delayed<NativeLibraries> extension = > project.extensions.define('libraries', NativeLibraries.class) > > extension.beforeConfigured { … called before any configure actions are > executed … } > extension.configure { … called to configure the object … } > extension.finishConfiguration { … called after all configure actions are > executed … } > extension.whenConfigured { … called once the object is configured … } > That would solve a problem we have with our container rules at the moment. At the moment we only have whenAdded and all (e.g. tasks.withType(Jar).all { ... } ). The configure closure is called before the object is configured by the user. Sometimes this is what you want, but there are use cases where you want this to happen after the user configuration. I assume here that those rules will be made available for all our domain object containers. My concern with this model is extendability. What I have in mind are the base plugins for a domain (e.g. Android, C++). Those plugins I see as an extension of the Gradle platform that then get extended/modified by another set of plugins for this particular domain (e.g. the Android plugin gets extended by the Testdroid plugin). I find that our listener hooks are not very suitable to be extended (e.g. will the extension of the extension be executed before or after the original configure closure, ...). A DAG based configuration task approach would be much better here I think. However we implement the first go for this I'm interested if we agree in general that configuration tasks would be better. I had not bandwidth to follow the whole deferred configuration debate. So I might be missing something obvious. Hans