Deep into the Task
Tasks work as the smallest atom of Gradle builds and can flexibly define the build of a project through inter-dependencies between tasks.
Task contains the following properties
- The related properties of the task itself, which contain all getters and setters
- Extentsions properties
- Conventions properties
- Extra attributes
Task allocation
Define the Task
You can define a set of tasks for a Project. Each task has its own set of actions, which can be added via doFirst or doLast
// Create default task
tasks.register("hello") {
// The code for the configuration phase
group = "custiom"
doLast {
// Execute the code
println("hello")}}// Create tasks based on the Task template
tasks.register<Copy>("copy") {
// Configure the copy source
from(file("srcDir"))
// Set the copy destination
into(buildDir)
}
Copy the code
To get the Task
You can get a defined task, get its configuration, or reconfigure it
// Get task by name
println(tasks.named("hello").get().name)
// Get the task of the specified type by name
println(tasks.named<Copy>("copy").get().destinationDir)
// Get task by type
tasks.withType<Copy>().configureEach {
group = "customCopy"
}
Copy the code
You can see more about the API for getting tasks in the TaskContainer source code
Task dependencies and sorting
A task may have dependencies on another task or may need to be executed after a task. Gradle ensures that all task dependencies and ordering rules are followed when executing the task. Use mustRunAfter and shouldRunAfter to manipulate the execution order of tasks.
The following objects are used to specify task dependencies or ordering
- Task string path
- Task object
- TaskDenpendcy object
- TaskRefrence object
- RegularFileProperty, File, and DirectoryProperty objects
- Provider object that contains the return value of the above type
- A collection containing the above types
- Contains closures of the above type
- Tasks that depend on other projects
project("project-a") {
// Depend on project B's taskY
tasks.register("taskX") {
// Task path through: split
dependsOn(":project-b:taskY")
doLast {
println("taskX")
}
}
}
project("project-b") {
tasks.register("taskY") {
doLast {
println("taskY")}}}Copy the code
TaskY is executed before taskX
- Rely on a closure
val taskX by tasks.registering {
doLast {
println("taskX")}}// Rely on a closure
taskX {
dependsOn(provider {
tasks.filter { task -> task.name.startsWith("lib") }
})
}
tasks.register("lib1") {
doLast {
println("lib1")
}
}
tasks.register("lib2") {
doLast {
println("lib2")
}
}
tasks.register("notALib") {
doLast {
println("notALib")}}Copy the code
Lib1, lib2 will be executed before taskX
- Sort the execution flow of tasks
val taskX by tasks.registering {
doLast {
println("taskX")}}val taskY by tasks.registering {
doLast {
println("taskY")
}
}
taskY {
mustRunAfter(taskX)
}
Copy the code
The output of the following command
> gradle -q taskY taskX
taskX
taskY
Copy the code
> gradle -q taskY
taskY
Copy the code
You can see the difference between dependency and order
If a task depends on another task, the dependent task is preferentially executed
The order in which tasks are executed does not mean that the reference tasks will be executed, but that they will be executed together in the agreed order
- When a Task already has a dependent process, the sort process is ignored
val taskX by tasks.registering {
doLast {
println("taskX")}}val taskY by tasks.registering {
doLast {
println("taskY")}}val taskZ by tasks.registering {
doLast {
println("taskZ")
}
}
taskX { dependsOn(taskY) }
taskY { dependsOn(taskZ) }
taskZ { shouldRunAfter(taskX) }
Copy the code
> gradle -q taskX
taskZ
taskY
taskX
Copy the code
Skip the task
-
By judging conditions
val hello by tasks.registering { doLast { println("hello world") } } hello { onlyIf { ! project.hasProperty("skipHello")}}Copy the code
-
With an exception, a StopExecutionException is thrown
-
Settings unavailable
val disableMe by tasks.registering { doLast { println("This should not be printed if the task is disabled.") } } disableMe { enabled = false } Copy the code
-
Example Set the task timeout period
tasks.register("hangingTask") { doLast { Thread.sleep(100000) } timeout.set(Duration.ofMillis(500))}Copy the code
Add a Rule to TaskContainer
TaskContainer inherited from NamedDomainObjectCollection, it can add a rule, when given a name unknown domain object, applies to rules, you can to ignore, or to create the named domain object
tasks.addRule("Pattern: ping<ID>") {
val taskName = this
if (startsWith("ping")) {
task(taskName) {
doLast {
println("Pinging: " + (taskName.replace("ping".""))}}}}Copy the code
Customize the Task template
Define a simple Task Class
open class GreetingTask : DefaultTask() {
var greeting = "hello from GreetingTask"
//TaskAction writes the specific execution logic of the task. This method is executed during the execution phase
@TaskAction
fun greet(a) {
println(greeting)
}
}
tasks.register<GreetingTask>("hello")
Copy the code
Configure tasks through setter methods
tasks.register<GreetingTask>("greeting") {
// Configure the greeting parameters
greeting = "greetings from GreetingTask"
}
Copy the code
Configure tasks using constructors
open class GreetingTask() : DefaultTask() {
var greeting = "hello from GreetingTask"
@javax.inject.Inject
constructor(greeting: String) : this() {
this.greeting = greeting
}
@TaskAction
fun greet(a) {
println(greeting)
}
}
// Pass the constructor arguments directly
tasks.register<GreetingTask>("greeting"."hello gradle")
Copy the code
Configure tasks using command-line options
open class GreetingTask() : DefaultTask() {
@Option(option = "m", description = "Configure greeting text")
var greeting = "hello from GreetingTask"
@TaskAction
fun greet(a) {
println(greeting)
}
}
tasks.register<GreetingTask>("greeting")
// Run gradlew greeting -m hellogradle
Copy the code
An incremental
To improve Gradle’s build efficiency and avoid repetitive work, Gradle introduces the concept of incremental builds.
In most cases, a task will contain both input and output. Take the ZipResTask from Gradle Level 3 as an example. The resource file is the input and the packaged ZIP file is the output. If the input and output of a Task are the same when executed multiple times, then it is considered unnecessary to repeat the execution of such a Task. Each Task has inputs and outputs, whose types are TaskInputs and TaskOutputs, respectively. In an incremental build, we define inputs and outputs for each Task. Gradle considers a Task TO be UP TO DATE if its inputs and outputs have not changed since the last execution. Therefore Gradle will not execute. Inputs and outputs of a Task can be one or more files, folders, a Property of a Project, or even conditions defined by a closure.
Modify ZipResTask to an incremental build
//custom_build.gradle.kts
import org.gradle.kotlin.dsl.support.zipTo
open class ZipResExtensions {
var resPath: String = ""
var outputPath: String = ""
}
extensions.create<ZipResExtensions>("zipRes")
abstract class ZipResTask : DefaultTask() {
@get:InputDirectory
abstract val resDir: Property<File>
@get:OutputFile
abstract val outputFile: Property<File>
@TaskAction
fun zipRes(a) {
zipTo(outputFile.get(), resDir.get())
}
}
tasks.register("zipRes", ZipResTask::class)
afterEvaluate {
tasks.named("zipRes", ZipResTask::class) {
val zipResExtensions = project.extensions.getByName<ZipResExtensions>("zipRes")
resDir.set(file(zipResExtensions.resPath))
outputFile.set(file(zipResExtensions.outputPath))
}
}
Copy the code
Output from zipRes execution
First execution
16:39:11: Executing task 'zipRes'...
> Task :zipRes
BUILD SUCCESSFUL in 88ms
1 actionable task: 1 executed
16:39:11: Task execution finished 'zipRes'.
Copy the code
Second execution
16:39:57: Executing task 'zipRes'...
> Task :zipRes UP-TO-DATE
BUILD SUCCESSFUL in 83ms
1 actionable task: 1 up-to-date
16:39:57: Task execution finished 'zipRes'.
Copy the code
If no changes are made, the execution of the task is skipped and the tag up-to-date is marked
conclusion
Tasks are the smallest atomic work of Gradle building. We need to be able to create tasks, configure them, and adjust the dependencies between tasks to complete our build