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

Reply via email to