In general, would "action" (not configuration) closures be the first choice?


(hw.kirk) #1

Still confused on action vs configuration closures.

In general, don’t I always want action closures?

Since I want “action” at some point, right?

I have read the book several times and I’m still confused here.

Any advice is appreciated.


(Luke Daley) #2

You almost always want ‘Action’.

Most of the objects that are exposed at the DSL level in Gradle have been decorated at runtime (this is via class level byte code injection). One of the things this does is add ‘Closure’ overrides for action methods.

So, when you have:

class SomeTask extends DefaultTask {
  void thing(Action<Thing> action) {
    action.execute()
  }
}

At runtime you actually have:

class SomeTask extends DefaultTask {
  private Thing thing
    void thing(Closure<?> closure) {
    thing(new org.gradle.api.internal.ClosureBackedAction(closure))
  }
    void thing(Action<Thing> action) {
    action.execute(thing)
  }
}

Which in effect means you can call the method with a closure at runtime.

We haven’t quite closed out this feature yet which is why it’s under documented, which we are sorely aware of.

Hopefully that helps.


(hw.kirk) #3

Thank you for the prompt response.

So I will use ‘action’ closures.

I am trying to find the “correct” way to invoke tasks in sequence (analagous to successive 'attainGoal’s in maven)

Running gradle 1.4

Why does the below not work?

(gradle replies with Could not find property ‘taskB’ on root project).

The example below uses all ‘action’ closures.

task taskA (dependsOn: [taskB, taskC, taskZ]) << {

logger.lifecycle ‘…running taskA’ }

task taskB << {

logger.lifecycle ‘…running taskB’ }

task taskZ << {

logger.lifecycle ‘…running taskZ’ }

task taskC << {

logger.lifecycle ‘…running taskC’ }


(Luke Daley) #4

Sorry, I completely misunderstood the question. My first answer is not relavant to what you’re asking about. Regarding your first question, take a look at: http://www.gradle.org/docs/current/userguide/build_lifecycle.html

Maven and Gradle have different models. Maven is linear and phasic. Gradle is dependency based. You don’t specify a sequence of events in Gradle; you specify which events need to occur before a given event can occur. So you’d need:

task taskA << {
    logger.lifecycle '....running taskA'
}
task taskB(dependsOn: [taskA]) << {
    logger.lifecycle '....running
taskB'
}
task taskZ(dependsOn: [taskB]) << {
    logger.lifecycle '....running
taskZ'
}
task taskC(dependsOn: [taskZ]) << {
    logger.lifecycle '....running
taskC'
}

(hw.kirk) #5

So one last question:

Is the execute() method NOT recommended, then?

I have been doing the “task.execute()” thing for a while in my build script but am wondering if its causing other problems.

taskA.execute() taskB.execute() etc…

Starting to think I need to attend a class


(Michael Brand) #6

Isn’t this just an issue of definition order?

In your script, taskB has not yet been defined when the taskA tries to add the dependency on taskB. There are two possible resolutions: move taskA to the bottom of the file, or put the dependency definitions in quotes:

task taskA (dependsOn: [‘taskB’, ‘taskC’, ‘taskZ’]) << { …

I’m not sure if this answers your broader question, but I think this will fix your script issue.


(Luke Daley) #7

It should be avoided as it will go away at some point (not before Gradle 2.0).

It’s currently the only practical way around some problems, but we are actively working on a more powerful task relationship model that will remove the need for it.

Do your best to avoid using it.


(hw.kirk) #8

OK, thank you…I’m back on track now.