声明一个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