Gradle tip #1: tasks
With this post I would like to start series of Gradle-related topics I wish I knew when I first started writing Gradle build scripts.
Today we will talk about Gradle tasks and specifically configuration and executionparts of the task. Since these terms might appear unknown to vast majority of readers, it will be easier to have real examples. Essentially (sorry for looking ahead), we will try to figure out what is the difference between these 3 examples:
task myTask {
println "Hello, World!"
}
task myTask {
doLast {
println "Hello, World!"
}
}
task myTask << {
println "Hello, World!"
}
My goal - is to create a task which prints "Hello, World!" when I execute it.
When I first started, my first guess was to implement it like this:
When I first started, my first guess was to implement it like this:
task myTask {
println "Hello, World!"
}
Now, let's try to execute my new task!
user$ gradle myTask
Hello, World!
:myTask UP-TO-DATE
It seems to be working! It prints "Hello, World!".
But! It doesn't work as we might expect it to work. And here is why. Let's try to call
But! It doesn't work as we might expect it to work. And here is why. Let's try to call
gradle tasks
to see what other tasks are available:user$ gradle tasks
Hello, World!
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
..........
Wait a second! Why my "Hello, World!" string is printed? I just called
tasks
, I didn't call my custom task!
The reason why this is happening - is that Gradle task has 2 major stages in its lifecycle:
- Configuration stage
- Execution stage
I might not be super precise with terminology here, but this analogy helped me to understand tasks.
The thing is that Gradle has to configure all tasks specified in build script beforeactual build is started. It doesn't matter if certain task will be executed - it still needs to be configured.
Knowing that, how do I know which part of my task is evaluated during configuration and which one during execution?
And the answer is - the part specified within the top-level of the task - is task configuration section. I.e:
And the answer is - the part specified within the top-level of the task - is task configuration section. I.e:
task myTask {
def name = "Pavel" //<-- this is evaluated during configuration
println "Hello, World!"////<-- this is also evaluated during configuration
}
That's why when I call
gradle tasks
I can see "Hello, World!" - this is our configuration section is executed. But that's not really what I want - I want "Hello, World!" to be printed only when I explicitly call my task.
So how do I tell Gradle to do something when my tasks is executed?
In order to do that I need to specify task Action. The easiest way to specify task action is via Task#doLast() method:
task myTask {
def text = 'Hello, World!' //configure my task
doLast {
println text //this is executed when my task is called
}
}
Now my "Hello, World!" string will be printed only when I explicitly call
gradle myTask
Cool, now I know how to configure and make my task do real work only when I invoke it. What about that third option with
<<
symbol?:task myTask2 << {
println "Hello, World!"
}
This version is just a shortcut of
doLast
version, i.e. it is exactly the same as I would write:task myTask {
doLast {
println 'Hello, World!' //this is executed when my task is called
}
}
However, since now everything goes into execution part, I cannot configure my task the same way I did it with
doLast
option (it is still possible to do, but in a slightly different way). So this option is good for really small tasks which do not require configuration, but if you have some task other than printing a "Hello, World!" - you might consider going with doLast
.
Happy gradling!
No comments:
Post a Comment