Is it possible to execute a task from within doLast? - gradle

I have the following:
task copyToLib(type: Copy) {
from configurations.runtime
into "$buildDir/output/lib"
doLast { copyOpcThirdParty() } // this doesnt get executed
}
task copyOpcThirdParty(type: Copy) {
from "$projectDir/libs/opc/thirdparty"
into "$buildDir/output/lib/thirdparty/"
}
How can I call copyOpcThirdParty from copyToLib.doLast?
I tried .execute(), tasks.copyOpcThirdParty, etc, nothing worked..
Is it unsupported?

In Gradle tasks are not executed directly. Instead you can register dependencies and Gradle then decides which tasks to execute in which order to achieve the execution of the tasks you specified (generally via command line). In older versions of Gradle you can call execute() directly on a task, but it should never be used.
When executing the tasks, the execution of one task must always be completely finished until another task can be executed. The execution of a task always covers running all doFirst closures, all internal task actions and all doLast closures.
For your specific example you can use the finalizedBy method. It tells Gradle that whenever a specific task runs, at some point after that another specific task also has to run:
copyToLib.finalizedBy copyOpcThirdParty

Related

Make gradle execute a finalizedBy task for each time it is set (multiple times)

I ran into the problem using the following situation:
To run different native testplugins in a row I dynamically create some tasks to prepare the environment appropriately for each plugin and then create a plugin_task for each testplugin that hosts the dependencies.
To start the tests on the device, the plugin_task is finalizedBy connectedAndroidTest.
So e.g. the call gradle plugin_name_1 works fine, it prepares the environment and starts the tests.
tasks.register("allTests"){}
name_list.each { test_name ->
def prepare_dir = tasks.register("${test_name}_Prepare_Dir") {...}
def copy_files = tasks.register("${test_name}_Copy_Files") {...}
def plugin_task = tasks.register(test_name){
dependsOn prepare_dir
dependsOn copy_files
finalizedBy connectedAndroidTest
}
allTests.configure {
dependsOn pluginTask
}
}
The problem now occurs, when I try run the allTests task:
gradle then correctly operates over all the dynamicly created tasks "prepare_dir", "copy_files" for each of the plugins, all of them are executed.
But the connectedAndroidTest will only be executed at the very end of allTests, so only runs once. But I need this task to be executed at every end of each plugin_task.
The behavior of gradle is correct, as it sees that all plugin_tasks shall be finalized by connectedAndroidTest and so puts it at the end of the graph.
Is there any possibility to make gradle execute this task multiple times?
Would be glad for help.
Wrapping the connectedAndroidTest task into dynamically created tasks and let the plugin_tasks depend on them, does not help. Also the parameter "rerun-tasks" has no effect.
That's not how Gradle works. Each task will execute either 1 or 0 times per Gradle invocation. If you want to execute the same task multiple times (with different task inputs) then you'll need multiple task instances, not one.

Gradle implicity run another task

I have two task
task Hello {
println 'Hello'
}
task World {
println 'Hello1'
}
If I run World task Hellowill run also. If I modify my tasks in this way
task Hello {
doLast {
println 'Hello'
}
}
task World {
println 'Hello1'
}
then task Hellowon't run. How do doLast{} or doFirst{} sections affect running tasks in gradle?
I can't find information in gradle docs about that. Thx.
The task Hello doesn't run. It's configured.
The code inside the curly braces is the code that configures the task. This code is always executed, whatever the task you tell gradle to run. It must run so that gradle knows what the task does, on which other task it depends, which other task it finalizes, etc.
Once the configuration phase has finished, the execution phase starts. And in that phase, the task that you asked to execute is executed/ In that phase, the code passed to doLast is being executed.
Here's the documentation.

Depend on multiple gradle tasks in multi project build

Currently I have task which starts Google Cloud server, runs tests and stops server. It is defined at root project:
buildscript {...}
allprojects {...}
task startServer (dependsOn: "backend:appengineStart") {}
task testPaid (dependsOn: "app:connectedPaidDebugAndroidTest") {}
task stopServer (dependsOn: "backend:appengineStop") {}
task GCEtesting {
dependsOn = ["startServer",
"testPaid",
"stopServer"]
group = 'custom'
description 'Starts GCE server, runs tests and stops server.'
testPaid.mustRunAfter 'startServer'
stopServer.mustRunAfter 'testPaid'
}
I tried multiple ways to write it something like this, short with only one task. I didn't get how to refer to task from another project and call mustRunAfter on it. This doesn't work (I also tried to refer from Project.tasks.getByPath, root.tasks, etc):
task GCEtesting {
dependsOn = ["backend:appengineStart",
"app:connectedPaidDebugAndroidTest",
"backend:appengineStop"]
group = 'custom'
description 'Starts GCE server, runs tests and stops server.'
"app:connectedPaidDebugAndroidTest".mustRunAfter "backend:appengineStart"
"backend:appengineStop".mustRunAfter "app:connectedPaidDebugAndroidTest"
}
Is it possible? What is correct syntax to make this work?
It looks like your problem is that you're treating dependsOn as meaning "invoke this task". It actually means "ensure the result of the depended on task is available before the dependent task starts". That's why your first solution didn't work: statements like testPaid.mustRunAfter only affect the actions of the testPaid task itself, not its dependencies.
Anyway, you can get the behaviour you want using dependsOn and finalizedBy, but they have to be declared in the build file of the app subproject.
app/build.gradle:
task connectedPaidDebugAndroidTest {
//
//...
//
dependsOn 'backend:appengineStart' // Ensure appengineStart is run at some point before this task
finalizedBy 'backend:appendginStop' // Ensure appengineStop is run at some point after this task
}
Then, you can run your tests simply with gradle app:connectedPaidDebugAndroidTest. If you really want to define a task in the root project to run the tests, then that's easy too:
build.gradle:
task GCEtesting {
dependsOn = "app:connectedPaidDebugAndroidTest"
}

Ensuring a Gradle task is executed after another task

I have the following issue with my gradle build: Heroku guarantees to execute the stage task (see below) but I need a custom cleanUp task (see below) to be executed just after the stage task.
I am not sure how to achieve this... Can anyone please help?
task cleanUp(type: Delete) {
delete 'bignibou-server/build/install'
}
//Executed/invoked by Heroku
task stage(dependsOn: [':bignibou-server:bootRepackage', ':bignibou-server:installDist'])
Basically task dependencies are configured with dependsOn and mustRunAfter, but it seems that what you need can be done with simple doLast:
stage.doLast {
project.file('bignibou-server/build/install').deleteDir()
}
you can declare a task which must always be executed after another task (regardless whether the task succeeded or not):
stage.finalizedBy "someOtherTask" //someOther task will always be executed after "stage"

Dynamically created task of type Copy is always UP-TO-DATE

I've prepared a very simple script, that illustrates the problem I see using Gradle 1.7 (need to stick with it because of some plugins not yet supporting newer versions).
I'm trying to dynamically create tasks each of which corresponds to a file in the project directory. This works fine, but the tasks I create never get executed as soon as I assign them type 'Copy'.
Here is my problem build.gradle:
file('templates').listFiles().each { File f ->
// THIS LINE DOES NOT WORK
task "myDist-${f.name}" (type: Copy) {
// NEXT LINE WORKS
//task "myDist-${f.name}" {
doLast {
println "MYDIST-" + f.name
}
}
}
task distAll(dependsOn: tasks.matching { Task task -> task.name.startsWith("myDist")}) {
println "MYDISTALL"
}
defaultTasks 'distAll'
in this way my tasks do not get executed when I call default task calling simply gradle:
MYDISTALL
:myDist-template1 UP-TO-DATE
:myDist-template2 UP-TO-DATE
:distAll UP-TO-DATE
BUILD SUCCESSFUL
If I remove type Copy from my dynamic task (uncommenting the line above), my tasks get executed:
MYDISTALL
:myDist-template1
MYDIST-template1
:myDist-template2
MYDIST-template2
:distAll
BUILD SUCCESSFUL
(You'll need to create a folder name templates in the same directory where build.gradle is located and put couple of empty files into there in order to run the test)
According to the debug output:
Skipping task ':myDist-template1' as it has no source files.
Skipping task ':myDist-template2' as it has no source files.
So how can I specify source files and make my Copy tasks execute?
I've tried adding
from( '/absolute/path/to/existing/file' ) {
into 'myfolder'
}
to the task body, I've tried assigning task's inputs.source file('/my/existing/file') with no success.
Could you please advise on how to modify my simple script leaving dynamic task creation and keeping my dynamic tasks of type Copy?
Thank you!
Edit:
All right, this way the task gets called:
file('templates').listFiles().each { File f ->
task "myDist-${f.name}" (type: Copy) {
from f
into 'dist'
doLast {
println "MYDIST-" + f.name
}
}
}
but it looks I must always specify from/into. It doesn't suffice to do that in the doLast{} body.
A Copy task only gets executed if it has something to copy. Telling it what to copy is part of configuring the task, and therefore needs to be done in the configuration phase, rather than the execution phase. These are very important concepts to understand, and you can read up on them in the Gradle User Guide or on the Gradle Forums.
doFirst and doLast blocks get executed in the execution phase, as part of executing the task. Both are too late to tell the task what to copy: doFirst gets executed immediately before the main task action (which in this case is the copying), but (shortly) after the skipped and up-to-date checks (which are based on the task's configuration). doLast gets executed after the main task action, and is therefore clearly too late.
I think the following Gradle User Guide quote answers my question the best:
Secondly, the copy() method can not honor task dependencies when a task is used as a copy source (i.e. as an argument to from()) because it's a method and not a task. As such, if you are using the copy() method as part of a task action, you must explicitly declare all inputs and outputs in order to get the correct behavior.
Having read most of the answers to "UP-TO-DATE" Copy tasks in gradle, it appears that the missing part is 'include' keyword:
task copy3rdPartyLibs(type: Copy) {
from 'src/main/jni/libs/'
into 'src/main/libs/armeabi/'
include '**/*.so'
}
Putting from and into as part of the doLast section does not work. An example of a working task definitions is:
task copyMyFile(type: Copy) {
def dockerFile = 'src/main/docker/Dockerfile'
def copyTo = 'build/docker'
from dockerFile
into copyTo
doLast {
println "Copied Docker file [$dockerFile] to [$copyTo]"
}
}
Not the behavior I was expecting.
Using gradle 3.2.1

Resources