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
