Hi,

A plugin that I'm working on has to resolve a bunch of dependencies in order to 
decide the tasks to create and wire together. At the moment, this means 
resolving the configuration at project configuration time. This has some 
issues, which I'll get to below. Strictly speaking, this could be made lazy, 
but it's just too complicated to make this lazy.

One option would be to make it easier to make the logic lazy. So far our 
approach has been to have lazy data structures and a single chunk of imperative 
configuration code. I think a much better approach would be to use dumber data 
structures and configuration logic that is lazily applied as required. This, in 
my experience, is easier for people to deal with mentally. And this means 
simpler plugins, which is better for everyone.

At the moment, I need to do various contortions in my plugin to make sure I 
don't try to add the tasks until the project dependencies have been configured, 
and that any other projects that the project depends on have also been 
configured. It would be very nice if my plugin had a way to say something like: 
'I'm going to add task A and task B, but in order to do so, I will need to know 
the dependencies of this project'. Then Gradle can take care of ordering things 
so that the dependency graph has been fully configured, before invoking my 
plugin logic. And later, because I've told Gradle what the logic produces, 
Gradle can take care of skipping my plugin entirely if no-one ever asks about 
task A or task B.

You can see a similar kind of thing in various other places. One example is in 
plugin level configuration via an extension. It would be very nice if my plugin 
could say 'I'm going to need a fully configured ThingoExtension before I can 
add any tasks', and Gradle can take care of first making sure that the 
ThingoExtension has been configured before asking the plugin to add its tasks. 
Combine that with the plugin declaring the tasks it might add, and Gradle can 
skip the plugin entirely (including creating and configuring the extension) if 
nothing is interested in using the tasks that it adds.

I think this approach will help make it easier to write build logic and 
(especially) domain objects, and get rid of some timing problems. I suspect it 
will also help enormously with configuration time performance and heap usage, 
as we create and configure less stuff, and do so in a declarative way that we 
can parallelise or skip. 

Of course, this is a deep change that we'd have to do gradually. In the 
meantime, there is another option for the particular problem, which I think 
makes sense to do in the short-term. Given that we think it's reasonable to be 
able to resolve a dependency configuration at project configuration time, I'd 
like to:

1. Change dependency resolution so that it traverses the project dependency 
graph and ensures that each project has been configured.
2. Change Configuration to fail if you try to modify a configuration that has 
been referenced in dependency resolution, whether directly or transitively. We 
currently do this for configurations that have been directly resolved, but not 
for configurations that are referenced by project dependencies.

#1 is a best effort attempt to make sure the project graph has been configured. 
It will miss out on configuration logic that might run later, from various 
hooks or from tasks, so #2 is there to let you know about the code that was 
missed. As we tackle some of the more general stuff above, #1 will cover more 
and more configuration logic, and #2 will fire less often.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Reply via email to