Running a task after execution of another task

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Running a task after execution of another task

Glen Stampoultzis
Hi,

I have a little problem with getting a task to run after execution of another task.  In this case I have a task called integrationTest.  What I want to do is use the Jetty plugin to execute the jettyRun task before running the integrationTest task and to run jettyStop task after it has finished.

integrationTest.dependsOn(jettyRun) lets me easily start the jetty server but there doesn't seem to be a good way of hooking in jettyStop at the end.

Using integrationTest.doLast { jettyRun.execute() } lets me hook in an action at the end of the execution chain but this suffers from a couple of problems.  Firstly if integrationTest is up-to-date then the actions aren't run so the server doesn't stop.   Secondly executing a task this way seems to be non-standard (execute is a private API).

I found a solution to the first problem with the following code:

gradle.taskGraph.afterTask { Task task, TaskState state ->
    if (task.name == 'integrationTest') {
        jettyStop.execute();
    }
}

but this still suffers from the second issue.  Is there a clean way do this?





Reply | Threaded
Open this post in threaded view
|

Re: Running a task after execution of another task

Ken Sipe
I haven't tried this... but here's an idea :)

integrationTest.doFirst {
tasks.jettyRun.execute()
}

integrationTest.doLast {
tasks.jettyStop.execute()
}

you can probably shorten it... and as you can see... jetty will only run if the integrationTest runs... so if it skips or is up-to-date, you're good.



On May 17, 2011, at 10:34 PM, Glen Stampoultzis wrote:

Hi,

I have a little problem with getting a task to run after execution of another task.  In this case I have a task called integrationTest.  What I want to do is use the Jetty plugin to execute the jettyRun task before running the integrationTest task and to run jettyStop task after it has finished.

integrationTest.dependsOn(jettyRun) lets me easily start the jetty server but there doesn't seem to be a good way of hooking in jettyStop at the end.

Using integrationTest.doLast { jettyRun.execute() } lets me hook in an action at the end of the execution chain but this suffers from a couple of problems.  Firstly if integrationTest is up-to-date then the actions aren't run so the server doesn't stop.   Secondly executing a task this way seems to be non-standard (execute is a private API).

I found a solution to the first problem with the following code:

gradle.taskGraph.afterTask { Task task, TaskState state ->
    if (task.name == 'integrationTest') {
        jettyStop.execute();
    }
}

but this still suffers from the second issue.  Is there a clean way do this?






Reply | Threaded
Open this post in threaded view
|

Re: Running a task after execution of another task

Glen Stampoultzis
Thanks, that seems to work fairly well.  I had thought doFirst just adds the action to the start of the action queue rather than executing before the task itself but obviously that was an incorrect assumption.

It still leaves me with the smaller issue of using a non-public API to execute the tasks but I guess I can live with that.


On 18 May 2011 13:43, Ken Sipe <[hidden email]> wrote:
I haven't tried this... but here's an idea :)

integrationTest.doFirst {
tasks.jettyRun.execute()
}

integrationTest.doLast {
tasks.jettyStop.execute()
}

you can probably shorten it... and as you can see... jetty will only run if the integrationTest runs... so if it skips or is up-to-date, you're good.



On May 17, 2011, at 10:34 PM, Glen Stampoultzis wrote:

Hi,

I have a little problem with getting a task to run after execution of another task.  In this case I have a task called integrationTest.  What I want to do is use the Jetty plugin to execute the jettyRun task before running the integrationTest task and to run jettyStop task after it has finished.

integrationTest.dependsOn(jettyRun) lets me easily start the jetty server but there doesn't seem to be a good way of hooking in jettyStop at the end.

Using integrationTest.doLast { jettyRun.execute() } lets me hook in an action at the end of the execution chain but this suffers from a couple of problems.  Firstly if integrationTest is up-to-date then the actions aren't run so the server doesn't stop.   Secondly executing a task this way seems to be non-standard (execute is a private API).

I found a solution to the first problem with the following code:

gradle.taskGraph.afterTask { Task task, TaskState state ->
    if (task.name == 'integrationTest') {
        jettyStop.execute();
    }
}

but this still suffers from the second issue.  Is there a clean way do this?







Reply | Threaded
Open this post in threaded view
|

Re: Running a task after execution of another task

Adam Murdoch

On 18/05/2011, at 2:13 PM, Glen Stampoultzis wrote:

Thanks, that seems to work fairly well.  I had thought doFirst just adds the action to the start of the action queue rather than executing before the task itself but obviously that was an incorrect assumption.

It still leaves me with the smaller issue of using a non-public API to execute the tasks but I guess I can live with that.

There are a couple of other downsides to this approach.

We do want to add some way to solve this problem, as it's a pretty common one. One option we've discussed is to allow you to declare 'initializer' and 'finalizer' tasks for a given task. An initializer is a task which must run before the main task (like a dependency) and which is run only if the main task will be run. So, for example, jettyRun would be skipped if the integration tests are up-to-date. A finalizer is a task which must run after the main task, whether the main task succeeds or fails, and which is automatically added to the dag when the main task is added.




On 18 May 2011 13:43, Ken Sipe <[hidden email]> wrote:
I haven't tried this... but here's an idea :)

integrationTest.doFirst {
tasks.jettyRun.execute()
}

integrationTest.doLast {
tasks.jettyStop.execute()
}

you can probably shorten it... and as you can see... jetty will only run if the integrationTest runs... so if it skips or is up-to-date, you're good.



On May 17, 2011, at 10:34 PM, Glen Stampoultzis wrote:

Hi,

I have a little problem with getting a task to run after execution of another task.  In this case I have a task called integrationTest.  What I want to do is use the Jetty plugin to execute the jettyRun task before running the integrationTest task and to run jettyStop task after it has finished.

integrationTest.dependsOn(jettyRun) lets me easily start the jetty server but there doesn't seem to be a good way of hooking in jettyStop at the end.

Using integrationTest.doLast { jettyRun.execute() } lets me hook in an action at the end of the execution chain but this suffers from a couple of problems.  Firstly if integrationTest is up-to-date then the actions aren't run so the server doesn't stop.   Secondly executing a task this way seems to be non-standard (execute is a private API).

I found a solution to the first problem with the following code:

gradle.taskGraph.afterTask { Task task, TaskState state ->
    if (task.name == 'integrationTest') {
        jettyStop.execute();
    }
}

but this still suffers from the second issue.  Is there a clean way do this?









--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Reply | Threaded
Open this post in threaded view
|

Re: Running a task after execution of another task

jot1109
This post has NOT been accepted by the mailing list yet.
Any news on finalizer tasks? Right now i'm spanning multiple tasks (started programmatically via execute()) in a try/catch/finally block, which looks real ugly.
Reply | Threaded
Open this post in threaded view
|

Re: Running a task after execution of another task

Sergey
Task.finalizedBy is in action now, but seems that Gradle doesn't consider that configured finalizer task[s] may change (e.g. bytecode instrumentation) the finalizedTask.outputs.files...
And that eventually directs to a failed up-to-date check for finalized task.
Any comments ?
Reply | Threaded
Open this post in threaded view
|

Re: Running a task after execution of another task

Adam Murdoch

On 20/09/2013, at 10:58 PM, Sergey <[hidden email]> wrote:

Task.finalizedBy is in action now, but seems that Gradle doesn't consider
that configured finalizer task[s] may change (e.g. bytecode instrumentation)
the finalizedTask.outputs.files...
And that eventually directs to a failed up-to-date check for finalized task.
Any comments ?

This is true of any task that changes the output of another task in place, without copying it somewhere else.

It's something we plan to improve at some point. In the meantime, you need to give each task its own output directory, or use a Task.doLast() action instead of a finalizer task.


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



Reply | Threaded
Open this post in threaded view
|

Re: Running a task after execution of another task

Sergey
Adam Murdoch wrote
On 20/09/2013, at 10:58 PM, Sergey <[hidden email]> wrote:

> Task.finalizedBy is in action now, but seems that Gradle doesn't consider
> that configured finalizer task[s] may change (e.g. bytecode instrumentation)
> the finalizedTask.outputs.files...
> And that eventually directs to a failed up-to-date check for finalized task.
> Any comments ?

This is true of any task that changes the output of another task in place, without copying it somewhere else.

It's something we plan to improve at some point. In the meantime, you need to give each task its own output directory, or use a Task.doLast() action instead of a finalizer task.


--
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
Maybe that would be interesting to somebody ...
I've an example how to workaround this on compileJava & jibxBind pair sample.
Note that this approach allows execute jibxBind & compileJava tasks both separately and in context of overall build process execution with correct up-to-date check and mutual dependency:

    // add JiBX binding step to java compilation
    task jibxBind (dependsOn: compileJava) {
        String jibxBindingsDir = 'src/main/config/oxm-mapping/jibx/binding'
        inputs.files project.fileTree(dir: jibxBindingsDir, include: '**/*.xml'),
                     project.compileJava.outputs.files
        outputs.dir project.sourceSets.main.output.classesDir
        onlyIf {
            return (
                !project.compileJava.hasProperty('jibxAlreadyBinded') ||
                !project.compileJava.jibxAlreadyBinded 
            ) && owner.dependsOnTaskDidWork()
        }
        doLast {
            // To check an used classpath - uncomment this out...
            //sourceSets.main.runtimeClasspath.each { println("Classpath entry: " + it) }
            createJibxOutputPackageDirs(jibxBindingsDir)
            ant {
                taskdef(name:'jibxBind', classname: 'org.jibx.binding.ant.CompileTask', 
                           classpath: configurations.jibxBind.asPath)
                jibxBind(
                    verbose: true,
                    load: true,
                    classpath: sourceSets.main.runtimeClasspath.asPath//,
                    // Use either this attr or fileset below:
                    // binding:'src/main/jibx/hello-binding.xml'
                ){
                    bindingfileset(dir: "src/main/config/oxm-mapping/jibx/binding") {
                        include(name: '**/*.xml')
                    }
                }
            }
        }
    }
    compileJava << { 
        jibxBind.execute() 
        it.ext.jibxAlreadyBinded = true
    } // instead of this: compileJava.finalizedBy project.jibxBind