On 3 September 2014 at 5:52:44 am, Adam Murdoch (adam.murd...@gradleware.com) wrote:
On 3 Sep 2014, at 2:29 am, Marcin Erdmann <marcin.erdm...@proxerd.pl> wrote: While working on the new configuration model Luke and I have noticed that we are not locking task container after the configuration phase so the following does not throw an error (even though it essentially has no useful effect): task foo { doFirst { tasks.create("bar") } } As implemented at the moment tasks references are added to the new configuration model based on the task container contents at the end of the configuration phase therefore it probably makes sense to prevent any more modifications to the container after that point in time. It makes sense to prevent (or warn about) pointless creation of tasks. We do have to be a little careful about when we lock the task container for a given project, for backwards compatibility reasons. Currently, any build script can define a task in any other project, so we can’t lock until after every project build script has been executed and the afterEvaluate() events fired. We could certainly deprecate this behaviour, but we still need to support it. The story that triggered this is about defining the lifecycle WRT the “configuration phase” and the new model rule stuff. At the moment we interleave the two, which we want to now change. What I want to do is register the tasks into the model space _just_ before the task graph is built, and do this via iteration instead of .all(). This is cleaner, and avoids some awkwardness with task removal/replacement during the configuration phase. If we do this, we should ensure that no tasks are yet to be created. So, it’s at this point I want to “lock” the task container. This leaves only two “holes” for tasks to still be added: during task dependency traversal (a Buildable input could create a task in its getTaskDependency() impl) and during execution time proper. I can’t think of any valid reasons to do either of those. I suspect that creating tasks during the creation of the task graph is going to lead to CMEs at worst, and is undefined at best. Probably the same for creating tasks at execution time. Three options as I see them: 1. Once we start building the task graph, have all task containers warn that adding tasks at this time is deprecated but still try and add it 2. Once we start building the task graph, have all task containers warn that adding tasks at this time is not support it and discard the task 3. Once we start building the task graph, have all task containers error if someone tries to add a task Given how edge case this is, I’m for jumping straight to 3 as a breaking change. In the future, we want to be able to interleave tasks and rules (for example, configure my publications after I’ve generated my source to see what needs to be published, or build my plugin and then apply it to my project). Yes, but I think this will only be possible with the extra insight we get from the model system. Therefore, not interleaving the “configuration phase” make sense I think. That is, what you describe here will only be possible when the relevant bits are managed model. So, we could potentially lock the task container after the DAG for the project has been finalised, and we’re not going to consider any further tasks in that project for execution. Right, that’s less aggressive than what I want to do. This doesn’t quite help us for the model stuff as we need to actualise the tasks produced my model rules before the task graph is built. The only practical difference would be that locking after the task graph is built would still let tasks be created as we mine task inputs to build the graph. I’d really like to close that hole as well. -- Adam Murdoch Gradle Co-founder http://www.gradle.org CTO Gradleware Inc. - Gradle Training, Support, Consulting http://www.gradleware.com