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
>