gradle - cleanup after task complete with dependsOn - gradle

I have two custom tasks like --
task taskA(type: SomeTaskA) {
....
}
task taskB(type: SomeTaskB, dependsOn: 'taskA') {
....
}
taskA generates a file and performs some operations on it.
taskB also performs some operations on the file that is generated by taskA.
I can run both the tasks individually.
I need to delete this file when gradle command complete, ie., if I run gradle taskA then the file will delete when taskA completed and if I run gradle taskB then the file will delete when taskB completed.
I can achieve first part by adding doLast block and add delete logic there but when I run taskB then I have no file to perform operation (because taskA doLast already deleted the file).
Is then anyway to stop taskA doLast when I run taskB, or any other way to achieve this?

You could create a dedicated "cleanup" task to handle the file deletion, and make both tasks taskA and taskB be finalized by this task cleanup:
task cleanup{
doLast{
// DELETE the file
}
}
taskA.finalizedBy cleanup
taskB.finalizedBy cleanup
This way, the file will always be deleted, either you run taks A or B. And this will ensure that taskB is executed before the file is deleted by task cleanup as well.

Related

Is it possible to execute a task from within doLast?

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

Chained Gradle task cannot read file generated by previous task

I have gradle task, taskA, which when run will generate a html file. Then taskB will try opening that file. When I chain these like:
./gradlew taskA taskB
Then taskB cannot see the generated file. Incidentally IntelliJ is open and does not see the file at the same time.
However if I run the commands separately, e.g.
./gradlew taskA
./gradlew taskB
Then taskB can see the file fine. Do you know how I might chain the commands with the effect of running them separately? I have tried using clean at the start of taskB but it does not help.
The way you chain task in Gradle is by making taskA depend on taskB.
You can do it as follows:
apply plugin: 'base'
def file = project.file('shared-file.txt')
task taskA {
outputs.file(file)
doLast {
// Create the file
file.text = "Hello world!"
}
}
task taskB(dependsOn: taskA) {
inputs.file(file)
doLast {
// Print file content
println file.text
}
}
To clean up the file you can run cleanTaskA which will cleanup all outputs that taskA has defined. Or if you want to add the cleanup to the generic clean task then add clean.dependsOn(cleanTaskA, cleanTaskB).
The way I got it to work was by cd'ing back into the current directory.
This can be achieved with the following command, when you are in the correct directory:
cd .
This forces gradle to pick up any new files immediately.

gradle copy file task not working in build

I am new to gradle, I want copy the jar file generated by gradlew build to another dir.
task myCopyTask(type: Copy) {
from "build/libs/gs.jar"
into "D:/bin/gs"
}
I add above task to the build.gradle which belong to gs module which will generate gs.jar.
The problem is the command gradlew build will not do the copy and this task indeed executed(I add println in myCopyTask). However, the command gradlew myCopyTask works.
First I thought maybe the copy task running too early, so I change it to
task myCopyTask(type: Copy) {
doLast {
from "build/libs/gs.jar"
into "D:/bin/gs"
}
}
This is not working even by gradlew myCopyTask. Only first version can work by command gradlew myCopyTask, the terminal will show: 1 actionable task: 1 executed
What is the problem?
You haven't wired the task into Gradle's DAG so currently it will only executed when you do gradlew myCopyTask
You'll probably do something like
apply plugin: 'base' // adds build and assemble lifecycle tasks
task myJarTask(type:Jar) {...}
task myCopyTask(type: Copy) {
dependsOn myJarTask
...
}
assemble.dependsOn myCopyTask
See https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:task_dependencies

Gradle: execute tasks sequentially in some task

I have a library, which contains 3 lib modules and 1 example module. Before deploy task I want to execute some other tasks. In command line it looks like this: ./gradlew -x:example:clean -x:example:check -x:example:uploadArchives clean check :androidLib:assembleRelease uploadArchives.
I want to write gradle task to execute all tasks sequentially for all modules besides example module. That I can do: ./gradlew deployAll. How can i do it?
I try do this:
task deployAll {
doLast {
subprojects {
if(it.plugins.withType(com.android.build.gradle.AppPlugin)) return
it.tasks.getByName('clean').execute()
it.tasks.getByName('check').execute()
...
}
}
}
But execute() is deprecated and it execute only first task and ignore any.
You can use dependsOn inside of your gradle tasks to make sure your tasks run in the correct order
task task1{
dependsOn task2
//Task one code
}
task2{
dependsOn task3
//task 3 code
}
task3{
//task3 code
}
so in this example if you call task1, first task 3 will be executed, then task2 and then finally task one, but you need only call task1.
You can make another task and set other tasks its dependencies
task deployAll {
dependsOn tasks.getByName('clean')
dependsOn(tasks.getByName('check'))
}
To ensure the order add put this somewhere
tasks.getByName('check').mustRunAfter(tasks.getByName('clean'))

How do I make Gradle rerun a task when its dependencies are run?

Let's say that I have a task "main" that depends on another task "dependency." I would like "main" to be rerun any time its dependency (or its dependency's dependencies) is rebuilt because "main" relies on the artifacts produced by "dependency" (or the dependencies of "dependency").
A build.gradle file containing an example of what I'm dealing with is the following:
defaultTasks 'main'
task baseDependency {
outputs.file 'deps.out'
outputs.upToDateWhen { false }
doLast {
exec {
commandLine 'bash', '-c', 'echo hello world > deps.out'
}
}
}
task dependency(dependsOn: baseDependency)
task main(dependsOn: dependency) {
outputs.file 'main.out'
doLast {
exec {
commandLine 'bash', '-c', 'echo hello world > main.out'
}
}
}
Executing gradle the first time:
:baseDependency
:dependency
:main
BUILD SUCCESSFUL
Total time: 0.623 secs
Executing it a second time:
:baseDependency
:dependency
:main UP-TO-DATE
BUILD SUCCESSFUL
Total time: 0.709 secs
I would really love if "main" were not marked "UP-TO-DATE" if its dependencies had to be rebuilt. That seems essential. How do you make sure that's the case?
The standard way to specify dependency between tasks is via task's inputs and outputs. This can be any file, fileset or directory.
In your case you should modify main task and add inputs.file 'deps.out' to its definition.
Note that gradle has an optimization that may lead to unexpected behavior in a simplistic example that you provided.
Before a task is executed for the first time, Gradle takes a snapshot
of the inputs. This snapshot contains the set of input files and a
hash of the contents of each file. Gradle then executes the task. If
the task completes successfully, Gradle takes a snapshot of the
outputs. This snapshot contains the set of output files and a hash of
the contents of each file. Gradle persists both snapshots for the next
time the task is executed.
Each time after that, before the task is executed, Gradle takes a new
snapshot of the inputs and outputs. If the new snapshots are the same
as the previous snapshots, Gradle assumes that the outputs are up to
date and skips the task. If they are not the same, Gradle executes the
task. Gradle persists both snapshots for the next time the task is
executed.
So even if you specify correct inputs in a simple example where the same file is generated the dependent task will be marked as up to date on the second and subsequent runs.
If you do not want or cannot hardcode dependency on the file you can override upToDateWhen for dependent task and calculate the condition if the task is up to date based on dependencies of this task and their state like this:
outputs.upToDateWhen { task ->
task.taskDependencies.inject(true) { r, dep ->
r && dep.values.inject(true) { res, v ->
res && (!(v instanceof Task) || v?.state.getSkipped())
}
}
}
upToDateWhen should return true if this task should not be run at all (because its output are already up-to-date). And this is the case when no dependent task was run (the gradle documentation is a bit vague about this I must admit but getSkipped seems work as expected).

Resources