On 14/06/2012, at 11:15 PM, Adam Murdoch <[email protected]> wrote:

> 
> On 14/06/2012, at 11:03 PM, Luke Daley wrote:
> 
>> Howdy,
>> 
>> On a project I am working on, I'm orchestrating a release process. Part of 
>> this is checking out the project from a tag and running a build against the 
>> checkout. It's awkward to use a task in this case as it's one step in a 
>> sequential workflow. I can make a GradleBuild task work, but it is awkward.
>> 
>> Is there any good reason not to offer a gradleBuild {} “imperative” method 
>> like javaexec {}, copy {} etc.? I think it makes sense to offer it.
>> 
>> 
>> Speaking more generally, I'm seeing this kind of issue more and more. It can 
>> be inconvenient to lock functionality up behind the task mechanism. I think 
>> the core issue here is that tasks don't really compose into larger “atomic” 
>> pieces.
> 
> So we should fix this, rather than work around it.
> 
> 
>> 
>> I think as a general philosophy and approach, we should be careful about 
>> locking functionality up behind tasks. Tasks should just adapt the 
>> functionality into our execution mechanism. This leads to some duplication, 
>> but it makes the most sense to me. We already do this sometimes, but I 
>> wouldn't consider it a consistent approach. What are others thoughts on 
>> this? I've been saying this kind of thing to plugin developers etc. and in 
>> trainings for a while.
>> 
>> Longer term, a richer execution model will alleviate some of this stuff but 
>> I'm not suggesting pursuing this now.
> 
> Don't assume this stuff is longer term. We should add the stuff we need 
> rather than work around it with imperative stuff. It's not one big bang 
> feature - it's a bunch of smaller ones.
> 
> The plan is to use declarative tasks and not imperative actions for all work 
> that Gradle does, and push this more and more. Actions do not scale. Tasks do.
> 
> Having said that, there are 2 things we might do to bridge the task and 
> action world:
> * Support pojo task types, combined with dependency injection. This way, you 
> don't need to implement Task, and we'll take care of filling in the missing 
> pieces when we happen to need a Task instance.
> * Allow arbitrary Runnable instances to be instantiated from such pogo types.
> 
> This way, there is no difference between an action implementation and a task 
> implementation - they're the same thing. It's how the instances are used that 
> determines whether the logic is an action or a task.

Good stuff, but it wouldn't help here. Granted it could reduce the cost of 
supporting declarative & imperative in the long term.

I don't think we can lay task semantics over any action POJO. There is going to 
always be the need to do some adapting. I think we should focus on making task 
adapters cheap somehow. Take something like JavaExec, a large part (but not 
all, importantly) of it is just boilerplate delegation. When moving 
functionality out of the task (as I think needs to happen for JettyRun for e.g) 
you pay this boilerplate cost. 
This tempts people into fat tasks, which is inflexible.

I see three options:

1. making it more convenient to write thin task adapters
2. Fat tasks, but make using tasks much more flexible (composites, 
cloning/retry etc.)
3. A new model.

We probably will need both 1 & 2 I guess.


Returning to the concrete…

If we want to avoid exposing more action impls, to solve the use case I had in 
mind we'd need the ability to create composite tasks. With that, I could 
express each piece as a task and use dependencies to arrange them in a serial 
fashion. This would also be enough to form a reasonable solution to the 
integration test container problem.

Seems like a reasonable place to start to me, opposed to POJO tasks etc.

> 
> 
> --
> 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