Understanding of the gradle series task

The previous articles have learned the basic knowledge of gradle construction task and understood the concepts of project and task. It is recommended to read the previous articles first:

Gradle is built by a series of tasks. This article will introduce tasks in detail. The main contents of this article are as follows:

There are many ways to create tasks in gradle, which are finally reflected in the shortcut method provided by project and the Create method provided by the built-in taskcontainer. The following are several common ways to create tasks:

/**
 * 第一种创建任务方式:
 * 方法原型:Task task(String name) throws InvalidUserDataException;
 */
//定义Task变量接收task()方法创建的Task,方法配置创建的Task
def Task taskA = task(taskA)
//配置创建的Task
taskA.doFirst {
    println "第一种创建任务的方式"
}

/**task
 * 第二种创建任务方式:可在Map参数中进行相关配置,如依赖、任务描述、组别等
 * 方法原型:Task task(Map<String,?> args,String name) throws InvalidUserDataException;
 */
def Task taskB = task(group: BasePlugin.BUILD_GROUP,taskB,description: "描述")
//配置创建的Task
taskB.doLast {
    println "第二种创建任务的方式"
    println "任务taskB分组:${taskB.group}"
    println "任务taskB描述:${taskB.description}"
}

/**
 * 第三种创建任务方式:通过闭包的方式创建Task,闭包里的委托对象就是Task,即可在闭包内调用Task
 * 的一切属性方法来进行Task的配置
 * 方法原型:Task task(String name,Closure configureClosure);
 */
task taskC{
    description 'taskC的描述'
    group BasePlugin.BUILD_GROUP
    doFirst{
        println "第三种创建任务的方式"
        println "任务taskC分组:${group}"
        println "任务taskC描述:${description}"
    }
}

/**
 * 第四种创建任务的方式:可在闭包中灵活配置,也可在Map参数中配置,闭包中中的配置父覆盖Map中相同的配置
 * 方法原型:Task task(Map<String,String name,Closure configureClosure);
 */
def Task taskD = task(group: BasePlugin.BUILD_GROUP,taskD,description: "描述"){
    description 'taskD的描述'
    group BasePlugin.UPLOAD_GROUP
    doFirst{
        println "第四种创建任务的方式"
        println "任务taskD分组:${group}"
        println "任务taskD描述:${description}"
    }
}

The above four methods for creating tasks can be selected. The above mentioned parameters of tasks can be configured in the map, and the following configurations can be used in the map:

type:基于一个已存在的Task来创建,类似于类的继承,认值DefaultTask
overwrite:是否替换存在的Task,一般和type配合使用,认值false
dependsOn:配置当前任务的依赖,认值[]
action:添加到任务中的一个Action或者是一个闭包,认值为null
description:任务描述,认值null
group:任务分组,认值null

Create a task through a closure. The delegate object in the closure is a task. You can call all the properties and methods of the task in the closure to configure the task. It can be said that the method of creating a task using a closure is more flexible. In addition, you can use a taskcontainer to create a task, as shown below:

//使用TaskContainer创建任务的方式
tasks.create("taskE"){
    description 'taskE的描述'
    group BasePlugin.BUILD_GROUP
    doFirst{
        println "第三种创建任务的方式"
        println "任务taskE分组:${group}"
        println "任务taskE描述:${description}"
    }
}

Tasks is a project attribute and its type is taskcontainer, so you can create tasks through tasks. Of course, taskcontainer also has other construction methods for creating tasks. This is the end of the basic introduction to task creation.

The created task belongs to an attribute of the project. Its attribute name is the task name. The type of the attribute is task. If the task name is known, you can directly access and manipulate the task through the task name, or you can understand the task object corresponding to the task. Refer to the following:

/**
 * 访问任务的第一种方式:Task名称.doLast{}
 */
task taskF{

}
taskF.doLast{
    println "第一种访问任务的方式"
}

Tasks are created through the Create method of taskcontainer, and taskcontainer is a collection of created tasks. In project, taskcontainer can be accessed through the tasks attribute. The type of tasks is taskcontainer. Therefore, for created tasks, the attributes and methods of created tasks can be accessed by accessing geometric elements. The reference code is as follows:

/**
 * 访问任务的第二种方式:使用TaskContainer访问任务
 */
task taskG{

}
tasks['taskG'].doLast {
    println "第二种访问任务的方式"
}

In groovy, [] is also an operator. The real meaning of tasks ['taskg '] above is tasks. Getat ('taskg'), and the getat () method is the method in taskcollection, so that related tasks can be accessed and operated by task name.

You can also access tasks through path access. There are two key methods to access tasks through path: findbypath and getbypath. The difference is that the former will return null when the specified task is not found, and the latter will throw an unknowtaskexception exception when the task is not found. The code reference is as follows:

/**
 * 访问任务的第三种方式:使用路径访问任务
 */
task taskH{
    println 'taskH'
    //通过路径访问任务,参数可以是路径(没有访问成功,写法如下)
    println tasks.findByPath(':GradleTask:taskG')
    //通过路径访问任务,参数可以是任务名称
    println tasks.findByPath('taskG')
    println tasks.getByPath('taskG')
}

The execution results of the above code are as follows:

PS E:\Gradle\study\GradleTask> gradle taskH

> Configure project :
taskH
null
task ':taskG'
task ':taskG'


FAILURE: Build Failed with an exception.

* Where:
Build file 'E:\Gradle\study\GradleTask\build.gradle' line: 98

* What went wrong:
A problem occurred evaluating root project 'GradleTask'.
> Task with path 'test' not found in root project 'GradleTask'.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

* Get more help at https://help.gradle.org

BUILD Failed in 2s

In the process of using the path to access the task, the parameter is written as the path to access the specific task, which may be a writing problem. I hope it can be solved in the later learning.

In addition, it can also be accessed through the task name. The main methods are findByName and getbyname. The difference is the same as the third access method. The code reference is as follows:

/**
 * 访问任务的第四种方式:使用任务名称访问
 */
task taskJ
tasks['taskJ'].doLast{
    println 'taskJ'
    println tasks.findByName('taskJ')
    println tasks.getByName('taskJ')
}

The four ways of accessing tasks have been learned above. Through the understanding of gradle's access tasks, it can be flexibly used in combination with the above ways of accessing tasks in specific project construction.

Task grouping and description have been mentioned and configured in the previous article. Let's briefly explain here. Task grouping and description are actually configuring grouping and description of created tasks, as follows:

//任务分组与描述
def Task task1 = task taskK
task1.group = BasePlugin.BUILD_GROUP
task1.description = '测试任务分组与描述'
task1.doLast {
    println "taskK is group = ${group},description = ${description}"
}

The following is the execution result of the above code. Refer to the following:

PS E:\Gradle\study\GradleTask> gradle taskK

> Task :taskK
taskK is group = build,description = 测试任务分组与描述


BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed

It can be seen from the execution results that if the relevant properties of the task are configured, all the information of the task can be accessed.

Learn an operator < <. In the previous test code, the task. Dolast() method will be called for testing. We can use the < < operator instead of the dolast method, that is, the dalast() method can be written as follows:

//<< 任务操作符
//简写方式,Gradle 5.0 开始以不推荐这种写法
task taskL <<{
    println "doLast"
}
//推荐写法
task taskL{
    doLast{
        println "doLast"
    }
}

The execution results of the above two methods are as follows:

PS E:\Gradle\study\GradleTask> gradle taskL

> Configure project :
The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead.
        at build_6syzx8ks0l09hby4j6yn247u9.run(E:\Gradle\study\GradleTask\build.gradle:123)

> Task :taskL
doLast


BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask> gradle taskL

> Task :taskL
doLast


BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask>

It can be seen from the output results that both writing methods output the desired results. At the same time, observing the log, it is found that this shorthand method has been abandoned since gradle 5.0. Therefore, it is recommended to set up dolast to configure tasks.

In the process of gradle task execution, we can configure tasks before or after task execution through dofirst and dolast. When we execute a task, we are actually executing the actions owned by the task. We can get all executable actions through getactions() method. Next, customize a task type customtask, The annotation @ taskaction is used to mark the method doself to represent the method to be executed by the task itself. The code is as follows:

//任务执行流程分析
def Task taskA = task taskB(type: CustomTask)
taskA.doFirst {
    println "Task执行之前调用:doFirst"
}

taskA.doLast {
    println "Task执行之后调用:doLast"
}

class CustomTask extends DefaultTask{
    @TaskAction
    def doSelf(){
        println "Task执行本身调用:doSelf"
    }
}

The execution results of the above code are as follows:

PS E:\Gradle\study\GradleTask2> gradle taskB

> Task :taskB
Task执行之前调用:doFirst
Task执行本身调用:doSelf
Task执行之后调用:doLast


BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed

Since task execution is traversing the action list to be executed, in order to ensure the execution order, the action corresponding to dofirst must be placed at the front of the action list, the action corresponding to dolast must be placed at the back of the action list, and the action corresponding to doself must be placed in the middle of the list, so as to ensure the corresponding execution order, Here is the pseudo code:

//创建任务的时候将使用@TaskAction标注的方法作为Task本身执行的Task
//此时,任务正在创建,actionList里面只有Task本身执行的Action
actionList.add(0,doSelfAction)
//任务创建完成之后,如果设置了doFirst则会在actionList最前面添加doFist对应的action
//此时,doFirst对应的action添加actionList的最前面,保证了doFirst方法在任务开始执行之前执行
actionList.add(0,doFirstAction)
//任务创建完成之后,如果设置了doLast则会在actionList最后面添加doLast对应的action,保证了doLast方法在任务开始执行之后执行
actionList.add(doLastAction)

The process of task execution is basically the same as above, and try to experience more in specific practice.

Task sorting in gradle uses two methods of task, showrunafter and mustrunafter, which can easily control who executes the two tasks first:

/**
 * 任务顺序
 * taskC.shouldRunAfter(taskD):表示taskC要在taskD的后面执行
 * taskC.mustRunAfter(taskD):表示taskC必须要在taskD的后面执行
 */
task taskC  {
    doFirst{
        println "taskC"
    }
}
task taskD  {
    doFirst{
        println "taskD"
    }
}
taskC.shouldRunAfter(taskD)

For the execution results of the above code, refer to the following:

PS E:\Gradle\study\GradleTask2> gradle taskC taskD

> Task :taskD
taskD

> Task :taskC
taskC


BUILD SUCCESSFUL in 2s
2 actionable tasks: 2 executed

There is an enabled attribute in the task, which can be used to enable and disable a task. If it is set to true, the task will be enabled; otherwise, the task will be disabled. The default value of this attribute is true, as shown below:

taskA.enabled = true

Assertion is a conditional expression. The task object has an onlyif method. This method can receive a closure as a parameter. If the parameter in the closure returns true, the task will be executed. Otherwise, the task will not be executed. In this way, those tasks that need to be executed can be controlled through the assertion of the task. Next, learn the assertion of the task through a packaged case, The code reference is as follows:

//任务的onlyIf断言
final String BUILD_ALL = 'all'
final String BUILD_FIRST = 'first'
final String BUILD_OTHERS = 'others'

task taskTencentRelease{
    doLast{
        println "打应用宝渠道包"
    }
}

task taskBaiduRelease{
    doLast{
        println "打百度手机助手渠道包"
    }
}

task taskMiuiRelease{
    doLast{
        println "打小米应用商店渠道包"
    }
}

task buildTask{
    group BasePlugin.BUILD_GROUP
    description "打渠道包"
}

//为buildTask添加依赖的具体任务
buildTask.dependsOn taskTencentRelease,taskBaiduRelease,taskMiuiRelease

taskTencentRelease.onlyIf{
    if (project.hasProperty("buildApp")){
        Object buildApp = project.property("buildApp")
        return BUILD_ALL == buildApp || BUILD_FIRST == buildApp
    }else{
        return true
    }
}

taskBaiduRelease.onlyIf{
    if (project.hasProperty("buildApp")){
        Object buildApp = project.property("buildApp")
        return BUILD_ALL == buildApp || BUILD_FIRST == buildApp
    }else{
        return true
    }
}

taskMiuiRelease.onlyIf{
    if (project.hasProperty("buildApp")){
        Object buildApp = project.property("buildApp")
        return BUILD_OTHERS == buildApp || BUILD_ALL == buildApp
    }else{
        return true
    }
}

The following is the execution result of the above code:

PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=first buildTask

> Task :taskBaiduRelease
打百度手机助手渠道包

> Task :taskTencentRelease
打应用宝渠道包


BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=others buildTask

> Task :taskMiuiRelease
打小米应用商店渠道包


BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=all buildTask

> Task :taskBaiduRelease
打百度手机助手渠道包

> Task :taskMiuiRelease
打小米应用商店渠道包

> Task :taskTencentRelease
打应用宝渠道包


BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 executed

It can be seen that when we execute buildtask, we configure the attribute buildapp for project. Through different values of buildapp and onlyif, we realize the customized packaging strategies of different channel packages, which can be used for reference in practical development.

Note that the above code execution commands are written as follows:

//其中buildApp和=后面的值others是键值对的关系,使用命令执行任务时可使用-P命令简写
//-P要为当前Project指定K-V的属性键值对,即-PK=V
gradle -PbuildApp=others buildTask

The created tasks are all in the taskcontainer. We can get the tasks we want to get by the task name from the project attribute tasks. We can add corresponding task rules through the addrule method of the taskcontainer. The reference code is as follows:

//任务规则
tasks.addRule("对该规则的一个描述"){
    //在闭包中常常将->作为参数与代码块之间的分隔符
    String taskName ->
        task(taskName) {
            doLast{
                println "${taskName} 不存在"
            }
        }
}

task taskTest{
    dependsOn taskX
}

Execution result of the above code:

PS E:\Gradle\study\GradleTask2> gradle taskTest

> Task :taskX
taskX 不存在


BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

If you do not specify the task processing for some special cases, an error will be reported. If you do, relevant prompt information will be output. This is the end of the understanding and learning of gradle tasks. We can pay attention to the official account: jzman-blog, and exchange learning.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>