Building and Testing with Gradle笔记2——Gradle Tasks

声明一个Task

task hello

执行gradle tasks输出当前Project中所有task

:tasks

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]

Help tasks
----------
components - Displays the components produced by root project 'gradle-test-2'. [incubating]
dependencies - Displays all dependencies declared in root project 'gradle-test-2'.
dependencyInsight - Displays the insight into a specific dependency in root project 'gradle-test-2'.
help - Displays a help message.
model - Displays the configuration model of root project 'gradle-test-2'. [incubating]
projects - Displays the sub-projects of root project 'gradle-test-2'.
properties - Displays the properties of root project 'gradle-test-2'.
tasks - Displays the tasks runnable from root project 'gradle-test-2'.

Other tasks
-----------
hello

Gradle每当开始执行一个Task,都会输出一个冒号加上该task的名字,如:tasks。因此tasks也是一个task,正如输出所示。

添加Task要执行的操作

声明后的Task可以作为一个可编程的对象,使用左移操作符给其添加要执行的操作

task hello

hello << {
    print 'hello, '
}

hello << {
    println 'world'
}

配置Task

task initializeDatabase
initializeDatabase << { println 'connect to database' }
initializeDatabase << { println 'update database schema' }
initializeDatabase { println 'configuring database connection' }

执行gradle -b scratch.gradle initializeDatabase输出:

configuring database connection
:initializeDatabase
connect to database
update database schema

首先,-b选项可以执行gradle要执行的build文件。
其次,没有使用左移操作符的代码块是指定task的配置部分。在Gradle的声明周期的配置阶段执行,早于task的执行阶段。比配置阶段更早的是初始化阶段。

配置代码块同样可以追加,如下:

task initializeDatabase
initializeDatabase << { println 'connect to database' }
initializeDatabase << { println 'update database schema' }
initializeDatabase { print 'configuring ' }
initializeDatabase { println 'database connection' }

Task是对象

Task对象的默认类型是DefaultTask,Gradle中的所有Task都是派生自该类型。正如Java中的所有对象都派生自java.lang.Object

DefaultTask的方法

dependsOn(task)
// Declare that world depends on hello
// Preserves any previously defined dependencies as well
task loadTestData {
    dependsOn createSchema
}

// An alternate way to express the same dependency
task loadTestData {
    dependsOn << createSchema
}

// Do the same using single quotes (which are usually optional)
task loadTestData {
    dependsOn 'createSchema'
}

// Explicitly call the method on the task object
task loadTestData
loadTestData.dependsOn createSchema

// A shortcut for declaring dependencies
task loadTestData(dependsOn: createSchema)

如果一个Task有多个依赖,如下:

// Declare dependencies one at a time
task loadTestData {
    dependsOn << compileTestClasses
    dependsOn << createSchema
}

// Pass dependencies as a variable-length list
task world {
    dependsOn compileTestClasses, createSchema
}

// Explicitly call the method on the task object
task world
world.dependsOn compileTestClasses, createSchema

// A shortcut for dependencies only
// Note the Groovy list syntax
task world(dependsOn: [ compileTestClasses, createSchema ])
doFirst(closure)

传递一个closure在指定Task执行之前执行,注意和Task配置区分。

task setupDatabaseTests << {
    // This is the task's existing action
    println 'load test data'
}

setupDatabaseTests.doFirst {
    println 'create schema'
}

执行gradle setupDatabaseTests输出,

:setupDatabaseTests
create schema
load test data

当然,这个closure可以在Task配置块中指定:

task setupDatabaseTests << {
    println 'load test data'
}

setupDatabaseTests {
    doFirst {
        println 'create schema'
    }
}

doFirst也可以追加closure:

task setupDatabaseTests << {
    println 'load test data'
}

setupDatabaseTests.doFirst {
    println 'create database schema'
}

setupDatabaseTests.doFirst {
    println 'drop database schema'
}

输出如下:

:setupDatabaseTests
drop database schema
create database schema
load test data
doLast(closure)

示例如下:

task setupDatabaseTests << {
    println 'create database schema'
}

setupDatabaseTests.doLast {
    println 'load test data'
}

setupDatabaseTests.doLast {
    println 'update version table'
}

本质上,<<操作符等同于doLast方法。

onlyIf(closure)

在Task执行以前,进行判断,是否要执行该Task。

task createSchema << {
    println 'create database schema'
}

task loadTestData(dependsOn: createSchema) << {
    println 'load test data'
}

loadTestData.onlyIf {
    System.properties['load.data'] == 'true'
}

直接执行build loadTestData输出:

:createSchema
create database schema
:loadTestData SKIPPED

指定一个系统属性并执行gradle -Dload.data=true loadTestData,输出:

:createSchema
create database schema
:loadTestData
load test data

DefaultTask的属性

didWork

判断一个Task是否执行成功

apply plugin: 'java'

task emailMe(dependsOn: compileJava) << {
    if(tasks.compileJava.didWork) {
        println 'SEND EMAIL ANNOUNCING SUCCESS'
    }
}
enabled

是否启用Task

task templates << {
    println 'process email templates'
}

task sendEmails(dependsOn: templates) << {
    println 'send emails'
}

sendEmails.enabled = false

执行gradle -b enabled.gradle sendEmails,输出:

:templates
process email templates
:sendEmails SKIPPED
path
task echoMyPath << {
    println "THIS TASK'S PATH IS ${path}"
}

执行gradle -b path.gradle echoMyPath,输出:

THIS TASK'S PATH IS :echoMyPath

这表示该Task位于顶层Project,如果是子项目subProject的Task,那么path应该是:subProject:echoMyPath

logger

Gradle内部的logger引用,看代码:

task logLevel << {
    def levels = ['DEBUG',
                'INFO',
                'LIFECYCLE',
                'QUIET',
                'WARN',
                'ERROR']

    levels.each { level ->
        logging.level = level
        def logMessage = "SETTING LogLevel=${level}"
        logger.error logMessage
        logger.error '-' * logMessage.size()
        logger.debug 'DEBUG ENABLED'
        logger.info 'INFO ENABLED'
        logger.lifecycle 'LIFECYCLE ENABLED'
        logger.warn 'WARN ENABLED'
        logger.quiet 'QUIET ENABLED'
        logger.error 'ERROR ENABLED'
        println 'THIS IS println OUTPUT'
        logger.error ' '
    }
}

总而言之,logger的级别优先级,从低到高。

logging
description

设置一个Task的描述信息:

task helloWorld(description: 'Says hello to the world') << {
    println 'hello, world'
}

或者

task helloWorld << {
    println 'hello, world'
}

helloWorld {
    description = 'Says hello to the world'
}

又或者:

task helloWorld << {
    println 'hello, world'
}

helloWorld.description = 'Says hello to the world'
temporaryDir

以File对象的形式返回属于当前build文件的一个临时目录

动态属性

每个Task除了上述固有属性外还可以任意添加属性,本质上就是添加键值对。

task copyFiles {
    // Find files from wherever, copy them
    // (then hardcode a list of files for illustration)
    fileManifest = [ 'data.csv', 'config.json' ]
}

task createArtifact(dependsOn: copyFiles) << {
    println "FILES IN MANIFEST: ${copyFiles.fileManifest}"
}

执行gradle -b dynamic.gradle createArtifact,输出:

FILES IN MANIFEST: [data.csv, config.json]

Task类型

除了DefaultTask,还有一些用于复制,打包,执行程序的Task类型。声明一个Task类型就好像在面向对象编程中扩展一个类。

Copy

task copyFiles(type: Copy) {
    from 'resources'
    into 'target'
    include '**/*.xml', '**/*.txt', '**/*.properties'
}

from,into,和include方法都是继承自Copy。

Jar

这是java插件中引入的一个Task,Jar用于将源码打包成一个jar文件。我们同样可以扩展这个Task。

apply plugin: 'java'

task customJar(type: Jar) {
    manifest {
        attributes firstKey: 'firstValue', secondKey: 'secondValue'
    }
    archiveName = 'hello.jar'
    destinationDir = file("${buildDir}/jars")
    from sourceSets.main.classes
}

jar包的清单文件属性可以轻易的使用Groovy的map字面量创建。file方法用于从字符串构造一个java.io.File对象。from方法是Jar从Copy继承而来。

JavaExec

该Task用于执行一个带有main方法的Java类

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    runtime 'commons-codec:commons-codec:1.5'
}

task encode(type: JavaExec, dependsOn: classes) {
    main = 'org.gradle.example.commandline.MetaphoneEncoder'
    args = "The rain in Spain falls mainly in the plain".split().toList()
    classpath sourceSets.main.classesDir
    classpath configurations.runtime
}

自定义Task类型

在build文件中创建自定义Task类型

task createDatabase(type: MySqlTask) {
    sql = 'CREATE DATABASE IF NOT EXISTS example'
}

task createUser(type: MySqlTask, dependsOn: createDatabase) {
    sql = "GRANT ALL PRIVILEGES ON example.* TO exampleuser@localhost IDENTIFIED BY 'passw0rd'"
}

task createTable(type: MySqlTask, dependsOn: createUser) {
    username = 'exampleuser'
    password = 'passw0rd'
    database = 'example'
    sql = 'CREATE TABLE IF NOT EXISTS users(id BIGINT PRIMARY KEY, username VARCHAR(100))'
}

class MySqlTask extends DefaultTask {
    def hostname = 'localhost'
    def port = 3306
    def sql
    def database
    def username = 'root'
    def password = 'password'

    @TaskAction
    def runQuery() {
        def cmd
        if(database) {
            cmd = "mysql -u ${username} -p ${password} -h ${hostname} -P ${port} ${database} -e "
        } else {
            cmd = "mysql -u ${username} -p ${password} -h ${hostname} -P ${port} -e "
        }
        project.exec {
            commandLine = cmd.split().toList() + sql
        }
    }
}

上面定义的每个Task都用于执行一条sql语句。

在源码树中创建自定义Task类型

如果自定的Task较为复杂,应该将它们保存为单独的Groovy文件。上面的例子还可以写成这样,将build文件中的class移到一个单独的文件中MySqlTask.groovy,项目的结构如下:

|---build.gradle
\---buildSrc
    \---src
        \---main
            \---groovy
                \---org
                    \---gradle
                        \---example
                            \---task
                                \---MySqlTask.groovy
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值