Hi, Luke and I have been discussing ways that we can improve Gradle's configuration model - to get rid of timing weirdness, to give better diagnostics, to do less work, to do things in parallel, and so on.
We've started by recognising two things: Firstly, there's no real difference between configuring (or building) a model and building some files. And secondly, there is a very powerful approach that we already use for building files - that is, tasks. You can generalise what a task is, and think about about it as a function that takes a set of inputs and produces some outputs. These inputs and outputs are declared, so that we know what they are without having to execute the function. And this means, since we know the inputs and outputs, we can order execution so that a function is not executed until its inputs are available. Also - very importantly - we can order execution so that the inputs of a function are immutable, so that everything else that affects that input has already been executed. You can also think about a build script or plugin in a similar way: these are a set of functions, each of which take some inputs and produces some outputs. Usually, but certainly not always, these inputs and outputs are model elements (where a task is just another model element). So, let's say we add some way for Gradle to infer the inputs and outputs of each such configuration function. Then the goodness we have for tasks can also be used for configuration. So when a configuration function executes, Gradle would make sure that its inputs are available and immutable. For example, say I'm implementing a plugin where I don't know which tasks to create until after my model has been configured (e.g. an Android plugin or a C++ plugin). I can structure my plugin so that I have a configuration function that takes my model as input and produces tasks as output. Gradle won't call this function until the model has been completely configured - whether that's by a build script, or some custom plugin, or injected by an init script or some combination. As the plugin author I don't know or care where that configuration happens, only that it has happened, and that it won't happen after I've used the model. There are some more useful things that knowing tasks inputs and outputs gives us: We only run the tasks that are required to produce the requested outputs, and we can run unrelated task in parallel. The same would be true of configuration functions. For tasks, we also short-circuit a task whose inputs and outputs have not changed since last time it was run. We can do this because we persist the inputs and outputs, or at least enough about them to know if they've changed or not. If we were to persist the inputs and outputs of configuration functions, then we'd be able to do the same for configuration. Things get very interesting at this point. We'd be serialising the models, as these are the inputs and outputs of configuration functions. And because we can serialise them, we can ship models between threads, and jvms, and over time. This means, for example: - Task-level parallel execution. - Distributed configuration and execution. - Configuration and execution can happen in different jvms. For example, I can configure my C++ component model locally, and then run the compile and link tasks across a bunch of machines, one for each architecture that I build. - Tasks can run in an isolated jvm. For example, I might run all my compile tasks in a separate warmed-up jvm. - I can spread my build over many jvms to put together a massive (logical) heap. - We can spool models out to disk when heap space is tight. - We can ship models between builds. For example, my CI build might publish the entire build model along with the artefacts. My dev build can download this model from the repository and use it, instead of running all the configuration logic. - Fast tooling, as we only need to run the configuration logic that has changed. - Keep the model up-to-date in the daemon, in the background. - Implement some really nice build reproducibility. To reproduce a build, I can download the model that was used for that build, and set up all the inputs so that they are exactly the same as those used last time (and/or let the user know what's different or could not be made the same). And this would work for custom models, not just core models. - Implement some nice reporting and auditing: what inputs have changed between these two builds? what inputs were used to build this thing? I can answer these kinds of question without running the build. You get the idea. Something to note: We're not talking about using tasks to configure models. Instead, we're talking here about some underlying concept that is used both for building things and configuring models. Tasks would be some sugar over this underlying concept, to make it easy to building things. We'd introduce some equivalent DSL and APIs which would be sugar to make it easy to configure models. What this means is that we can blur the lines between building things and configuring models. For example, things that are outputs of tasks can be the input for some configuration logic. For example, I might use a plugin or task produced by another project to configure the current project. That thing needs to be built before I can configure the project. Or perhaps I need to generate some source files before I decide what which artefacts to include in my publication. By using a single concept, and treating models and files as things that can be inputs and outputs, we can offer a very flexible configuration model. Of course, it's not that simple. There are some 'interesting' problems to solve as far as backwards compatibility, usability and performance goes, plus lots of details to sort out. We've worked through a lot of this and we think we've got answers for much of this, and a plan for introducing this incrementally. More details to come later in the form of a spec and/or code. There's also a bit of a spike checked into master, where we've ported the publishing plugins to use this approach. -- Adam Murdoch Gradle Co-founder http://www.gradle.org VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting http://www.gradleware.com Join us at the Gradle eXchange 2013, Oct 28th in London, UK: http://skillsmatter.com/event/java-jee/gradle-exchange-2013