Gradle学习笔记 (未完)


在现有的基础上工作

Gradle资料

Maven和Gradle对比: http://www.importnew.com/18008.html
Gradle官网的与Maven对比: https://gradle.org/maven_vs_gradle/

下载: https://services.gradle.org/distributions/gradle-3.0-all.zip

Gradle官方用户指南文档: https://docs.gradle.org/current/userguide/userguide.html
Gradle2用户指南中文版: https://waylau.gitbooks.io/gradle-2-user-guide/content/

安装

Gradle3.0后,需要java7或更高版本
Gradle会装载自己的Groovy库,所以,不需要安装Groovy,就算安装了Groovy也会被忽略掉。

下载

下载完整包后,里面会包含 Gradle、用户指南、API文档、示例
https://gradle.org/gradle-download/

配置环境变量

GRADLE_HOME=D:\resource\Gradle\gradle-3.0
path=%GRADLE_HOME%/bin (linux: path=$GRADLE_HOME/bin)
GRADLE_OPTS=-Xms256m -Xmx512m (指定用于启动JVM命令行参数,选择配置)

GRADLE_USER_HOME=D:\resource\Gradle\repo (配置本地仓库的位置)

检查是否安装成功

执行命令 gradle -v

Gradle命令

  • 执行多task(列出每个task): gradle dist test
task compile << {
    println 'compiling source'
}

task compileTest(dependsOn: compile) << {
    println 'compiling unit tests'
}

task test(dependsOn: [compile, compileTest]) << {
    println 'running unit tests'
}

task dist(dependsOn: [compile, test]) << {
    println 'building the distribution'
}
  • 排除task(-x): gradle dist -x test -x compile

  • 当task执行失败时,继续执行不依赖这个task的其它task gradle --continue dist

  • 任务名称缩写(只需提供足够的可以唯一区分出该 task 的字符): gradle di

  • 选择需要执行的脚本: C:\>gradle -q -b D:/empty/build.gradle hello
    在多子项目时,应该使用-pgradle -q -p subdir hello

  • 忽略新版本检查(ignoring any up-to-date checks): gradle --rerun-tasks di

  • 查看构建信息
    gradle -q projects: 列出当前项目及其子项目(一并输出description)
    gradle -q tasks (gradle -q tasks --all): 列出当前项目的所有task
    gradle help --task task1 task2: 显示匹配到的task的详细信息
    gradle -q dependencies api:dependencies webapp:dependencies: 列出指定项目的依赖
    gradle -q api:dependencies --configuration testCompile: 列出指定项目及指定阶段的依赖
    gradle buildEnvironment: ?
    gradle -q webapp:dependencyInsight --dependency groovy --configuration compile: ? (对追踪为何依赖出现的版本很有帮助)
    gradle -q api:properties: 列出当前项目的属性

  • 生成构建耗时报告 --profile

  • 干跑(不真正执行,用来查看执行了哪些task) gradle -m someTask1 someTask2

Gradle命令列表
https://docs.gradle.org/current/userguide/gradle_command_line.html
包括几个环境变量的说明:GRADLE_OPTS GRADLE_USER_HOME JAVA_HOME

Gradle Wrapper

  • Wrapper的使用

Gradle Wrapper解决在未安装Gradle的情况下也能构建项目,并且避免用户选择了不正确的Gradle版本
每个Gradle Wrapper都会指定Gradle版本,当首次使用Wrapper时,将下载指定的Gradle版本,并使用它进行构建
Wrapper下载的Gradle保存到目录$USER_HOME/.gradle/wrapper/dists

  • 为项目添加Wrapper

只需要项目根目录下执行gradle wrapper --gradle-version 版本号

也可以在构建脚本build.gradle中添加task

task wrapper(type: Wrapper) {
    gradleVersion = '2.0'
}

执行命令后,将生成以下几个文件

demo/
  gradlew
  gradlew.bat
  gradle/
    wrapper/
      gradle-wrapper.jar
      gradle-wrapper.properties

配置文件gradle-wrapper.properties中的各项配置说明(一般不需要变更):
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.wrapper.Wrapper.html

  • 校验Wrapper下载的Gradle文件

执行命令shasum -a 256 gradle-3.0-all.zip生成hash码
windows下可以使用Git Bash来执行

将生成 的hash吗,配置到gradle-wrapper.properties

distributionSha256Sum=9c8b7564ea6a911b5b9fcadd60f3a6cea4238413c8b1e1dd14400a50954aab99
  • unix权限

在Unix系统中,如果遇到文件权限问题,可以这样执行sh gradlew

Gradle Daemon

可以通过Gradle Daemon来解决,Gradle启动会比较慢的问题
Gradle启动慢是因为,它运行中Java Virtual Machine (JVM)上,并还会依赖几个比较耗时的支持库
Gradle Daemon,是一直存活的,避免了JVM的启动耗时,并且缓存项目结构、文件、tasks等信息

Gradle 3.0中,Gradle Daemon是默认启动的,不需要作其它的变动
在低版本Gradle中,可以使用--daemon来启用Gradle Daemon

使用了Gradle Daemon,将会提升15-75%的构建速度
可以通过--profile来生成耗时报告

可以通过命令gradle --status来查看 Gradle Daemon的状态
如果安装了JDK,可以使用jps命令来查看
注意:目前,只有相同版本的GradleGradle Daemon才能一起工作

禁用Gradle Daemon
可以通过配置文件,也可以直接使用命令gradle --stop
目前,建议,在持续集成服务器中禁用Gradle Daemon,提高可靠性
https://docs.gradle.org/current/userguide/gradle_daemon.html

Gradle Daemon,若存活时间超过3个小时,将会被回收

依赖管理基础

  • 声明依赖
// java插件
apply plugin: 'java'

// 设定使用Maven中心仓库
repositories {
    mavenCentral()
}

dependencies {
	// 声明依赖hibernate-core版本为3.6.7.Final,在编译及运行时依赖它
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
	// 声明从仓库中获取版本>=4.0的junit,在test时依赖它
    testCompile group: 'junit', name: 'junit', version: '4.+'
}
  • 依赖配置

java插件中定义了以下几个标准的依赖配置
compile 编译时的依赖
runtime 程序运行时的依赖,默认包含compile
testCompile 单元测试编译时的依赖,默认包含compile
testRuntime 单元测试程序运行时的依赖,默认包含compileruntimetestCompile

  • 依赖的声明方式

依赖由group、name与version组成,除了上面的声明方式,还可以写成下面这样

dependencies {
    compile 'org.hibernate:hibernate-core:3.6.7.Final'
	testCompile 'junit:junit:4.+'
}
  • 仓库

默认情况下,Gradle不会定义依赖仓库,如果构建时需要第三方依赖,必须定义依赖仓库

如下设置仓库为Maven中心仓库

repositories {
    mavenCentral()
}

如下设置仓库为Maven远程仓库

repositories {
    maven {
        url "https://repo1.maven.org/maven2/"
    }
}
  • 发部项目

通过执行命令gradle uploadArchives,Gradle将构建并上传生成的jar包

apply plugin: 'maven'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "D:/resource/maven/repo/")
        }
    }
}

多项目构建

共同点

  • 在根项目中都有一个settings.gradle的文件
  • 在根项目中都有一个build.gradle的构建文件
  • 子项目中都有它们自己的*.gradle的构建文件

可以通过命令gradle -q projects查询项目列表

官方建议,每个项目都在settings.gradle中配置根项目名,示例spring源码中的rootProject.name = "spring"

不需要每个子项目都要有构建文件,但根项目中必须要有

子项目中构建文件的文件名不一定是build.gradle,只要以.gradle为后缀即可

在根项目中执行命令gradle test,将都在各子项目中执行这个gradle test命令

指定子项目的方法类似于路径,但不是用/\\,而是使用:
gradle :services:webservice:tasks,首个:表示根项目,其它的:表示路径分隔

持续构建

至目前3.0版本,这个特性尚未非常完善

通常,当前执行完所有指定的task后,就算是一次构建完毕,当下一次调用gradle命令时,才会进行下一次的构建动作

但持续构建时,Gradle会保持构建的功能,只有接收到停止命令时,才会停止。
如,对于编译JAVA文件,每当java文件变更时,Gradle自动对这个文件进行再次编译。
在一些情景下,持续构建能够发挥很大作用。

  • 启动:添加参数--continuous-t。示例,gradle build --continuous
  • 停止:如果是启动是在终端命令中,可以通过CTRL+D之后再接ENTER来结束;否则,需要使用kill命令来结束进程;某些工具或许会提供这个功能

只有在当前持续构建中,命令所涉及到的文件(构建脚本不算),被更改时,才会触发再次构建
当前构建脚本变更时,只有手动重启持续构建后,新的构建方案才会生效

注意事项:

  • 循环构建:在构建的过程中,构建脚本更改了被Gradle监视着的文件,就会形成循环构建
  • java9的限制:在Mac OS X中,Gradle为每10秒检测一遍文件的变更,而不是2秒;在Windows在,大项目可能运行不了持续构建
  • 性能与稳定性:在Mac OS X中,由于依赖于它低效率的系统轮询,所以对文件变更的感知会延迟;此外,在Mac OS X中,重负载情况下,可能会导致死锁;在linux中,如使用的是OpenJDK,有可能会错过文件变更的事件通知
  • 删除目标目录,不会引起新的构建

复合构建

至目前3.0版本,这个特性也尚未非常完善

复合构建与多项目构建有许多类似的地方

gradle 图形界面

使用命令gradle --gui就可以弹出图形界面

构建环境

通过gradle.properties配置编译环境
通过本地环境变量的配置,如GRADLE_OPTSJAVA_OPTS等,会作用于所有项目构建
如果某个项目需要特殊配置时,可以使用gradle.properties的配置来覆盖环境变更的配置

在下面三个地方中,如果存在相同的配置,后一个覆盖前一个

  • 项目构建目录中的gradle.properties
  • Gradle用户目录下的gradle.properties
  • 系统属性,如,命令行输入的-Dsome.property

这个功能需要jdk7或以上版本

下面列出用于配置Gradle构建环境的配置

  • org.gradle.daemon 当设置为true时,将使用Gradle daemon去构建。本地是默认使用的,在CI持续构建时,建议为false
  • org.gradle.java.home 指定Gradle构建程序使用的Java路径
  • org.gradle.jvmargs 指定daemon程序的jvm参数,这个设置是非常有用的,因为默认分配的daemon内存是比较大的
  • org.gradle.configureondemand 按需配置,只配置关联项目,使用大型项目能够快速构建 Configuration on demand
  • org.gradle.parallel 当配置了这个设置后,Gradle将以parallel模式执行
  • org.gradle.workers.max 配置并发执行的最大数
  • org.gradle.debug 当设置为true时,以远程(监听端口5005)debug模式运行,相当于在jvm命令行中添加-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
  • org.gradle.daemon.performance.enable-monitoring 当设置为false时,Gradle将不监控daemons运行时的内存使用情况

可以在gradle.properties配置文件中,配置http/https的访问代理

systemProp.http.proxyHost=www.somehost.org
systemProp.http.proxyPort=8080
systemProp.http.proxyUser=userid
systemProp.http.proxyPassword=password
systemProp.http.nonProxyHosts=*.nonproxyrepos.com|localhost

gradle的嵌入式编程

Gradle提供Tooling API,使用者可以自行调用。主要使用者是IDE、CI server等,但,API是开放的,任何人都可以在项目中使用

  • Gradle TestKit
  • Eclipse Buildship
  • IntelliJ IDEA

API有如下特性

  • 查询构建明细,包括项目结构与依赖
  • 执行构建,并监听输出日志
  • 执行指定的测试类或测试方法
  • 接收构建过程的事件,如项目配置,执行的task或test
  • 取消正在执行的构建
  • 将多个单独构建,组合与复合构建
  • 下载合适的Gradle版本
  • 轻量级的实现,可以非常方便的嵌入到应用中

samples/toolingApi中有示例

编写Gradle构建脚本

构建脚本基础

1). Projects and tasks

Projectstasks 是Gradle最顶部的两个基本概念
每个构建包含一个或多个Projects,一个Project由一个或多个tasks组成

2). Hello world

当执行gradle命令时,将会在当前目录中查找一个叫build.gradle的构建脚本

第一个构建脚本:执行gradle -q hello-q的作用是不输出gradle的日志)

task hello {
    doLast {
        println 'Hello world!'
    }
}

Gradle的task,与Ant的target很类似,但比target强大

3). 更简捷的书写方式

task hello << {
    println 'Hello world!'
}

4). 构建脚本,本身就是编程

通过强大的Groovy进行编写Gradle构建脚本

下面为在Task中使用Groovy的示例

task upper << {
    String someString = 'mY_nAmE'
    println "Original: " + someString 
    println "Upper case: " + someString.toUpperCase()
}

示例2

task count << {
    4.times { print "$it " }
}

5). Task之间的依赖

示例1:

task hello << {
    println 'Hello world!'
}
task intro(dependsOn: hello) << {
    println "I'm Gradle"
}

在示例1中,执行gradle -q intro,将输出如下:

D:\Learning\gradle\hello>gradle -q intro
Hello world!
I'm Gradle

示例2:延迟依赖,所依赖task,在当前task之后

task taskX(dependsOn: 'taskY') << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}

示例2将输出:

D:\Learning\gradle\hello>gradle -q taskX
taskY
taskX

6). 动态tasks

利用功能强大的Groovy,可以动态的创建tasks
示例:

4.times { counter ->
    task "task$counter" << {
        println "I'm task number $counter"
    }
}

在示例中,执行task0task1task2task3都是正常的

7). 调整已存在的tasks

当tasks被创建后,就可以通过一此API进行访问。通过这个特性,可以动态的实现task之间的依赖。Ant是不允许这么做的

示例1:

4.times { counter ->
    task "task$counter" << {
        println "I'm task number $counter"
    }
}
task0.dependsOn task2, task3

输出如下:

D:\Learning\gradle\hello>gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0

示例2:添加behaviour

task hello << {
    println 'Hello Earth'
}
hello.doFirst {
    println 'Hello Venus'
}
hello.doLast {
    println 'Hello Mars'
}
hello << {
    println 'Hello Jupiter'
}

输出如下:

D:\Learning\gradle\hello>gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter

doFirstdoLast可以被调用多次,表示在一个action之前或之后执行。
他们是依赖执行,操作符<<就类似于doLast的别名

8). 快捷符号

像在之前的示例中,可以通过一个快捷符号来访问已经存在的任务

task hello << {
    println 'Hello world!'
}
hello.doLast {
    println "Greetings from the $hello.name task."
}

这使用得代码更具可读性,特别是其它插件提供的tasks,比如compile

9). task的全局属性

在task中,可在属性中添加ext.前缀,并赋值,这样在其它的task中,就可读取到这个属性值了

示例:

task myTask {
    ext.myProperty = "myValue"
}

task printTaskProperties << {
    println myTask.myProperty
}

Extra properties

10). 编写Ant Tasks

Ant tasks are first-class citizens in Gradle.
Using Ant tasks from Gradle is as convenient and more powerful than using Ant tasks from a build.xml file.

下面示例如何访问Ant tasks及访问Ant properties

task loadfile << {
    def files = file('../antLoadfileResources').listFiles().sort()
    files.each { File file ->
        if (file.isFile()) {
            ant.loadfile(srcFile: file, property: file.name)
            println " *** $file.name ***"
            println "${ant.properties[file.name]}"
        }
    }
}

执行这个脚本,需要在当前脚本父目录中,创建文件夹antLoadfileResources,并在其下创建几个文件
更多关于Gradle中使用Ant的教程:Using Ant from Gradle

11). 使用公共方法

Gradle是有考虑如何组织脚本逻辑的。通过提取公共方法,可更好的组织脚本代码

示例:

task checksum << {
    fileList('../antLoadfileResources').each {File file ->
        ant.checksum(file: file, property: "cs_$file.name")
        println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
    }
}

task loadfile << {
    fileList('../antLoadfileResources').each {File file ->
        ant.loadfile(srcFile: file, property: file.name)
        println "I'm fond of $file.name"
    }
}

File[] fileList(String dir) {
    file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}

在后面将有章节,专门说明如果组织脚本代码的 Organizing Build Logic

12). 定义默认tasks

如果没有指定tasks,将执行默认的tasks

定义默认tasks示例:

defaultTasks 'clean', 'run'

task clean << {
    println 'Default Cleaning!'
}

task run << {
    println 'Default Running!'
}

task other << {
    println "I'm not a default task!"
}

如果只执行命令gradle -q,由于没有指定tasks,就会执行默认的cleanrun,相当于gradle -q clean run
如果子项目中没有指定默认tasks,则将执行父项目中的默认tasks

13). 通过DAG配置

在后面的构建生命周期中将有讲到,Gradle有一个配置阶段与一个执行阶段
配置阶段之后,Gradle就知道了所有需要被执行的tasks。此时,Gradle提供了一个可以利用的切入点,在这里,可以为变量设定不同的值

示例:

task distribution << {
    println "We build the zip with version=$version"
}

task release(dependsOn: 'distribution') << {
    println 'We release now'
}

gradle.taskGraph.whenReady {taskGraph ->
    if (taskGraph.hasTask(release)) {
        version = '1.0'
    } else {
        version = '1.0-SNAPSHOT'
    }
}

当执行gradle -q distribution命令时,将输出:

D:\Learning\gradle\hello>gradle -q distribution
We build the zip with version=1.0-SNAPSHOT

当执行gradle -q release命令时,将输出:

D:\Learning\gradle\hello>gradle -q release
We build the zip with version=1.0
We release now

非常重要的whenReady,它是在relese这个task执行之前起使用。

构建初始化插件

这个构建初始化插件正在不断完善中,在以后的版本中,DSL及其他配置可能会改变

这个构建初始化插件可以引导Gradle项目的创建。支持创建各种类型的Gradle项目,同时支持将其它构建方式转化为Gradle项目。

通常,Gradle插件是应用中项目。这个构建初始化插件是会自动应用于项目的,所以不需要特别配置。只需要在准备创建Gradle项目的地方,执行init这个task。
当使用这个构建初始化插件时,Gradle Wrapper也会自动被安装到当前项目中。

1). 插件包含的tasks

Task name depends on Type Description
init wrapper InitBuild Generates a Gradle project.
wrapper - Wrapper Generates Gradle wrapper files.

2). 初始设定

可以通过--type参数,指定构建的项目类型
如:创建一个java项目 gradle init --type java-library

若没有设定type参数,则Gradle将根据当前环境做出适当的判断,比如,当发现有pom.xml文件时,就会将type设定为pom,即将maven项目转换为gradle项目
如果没有指定或判断出type值,则将使用默认的basic

3). 初始化的项目类型

由于这个功能还在孵化中,所以只提供几种类型,更多的类型将在后续的版本中提供。

  • pom 在当前路径中查找文件pom.xml,并将其转化为gradle项目
  • java-library 创建java项目
  • scala-library
  • groovy-library
  • basic

编写Gradle构建脚本

Gradle构建脚本语言

Gradle为构建脚本提供了一个领域特定语言(DSL)。基于Groovy,并添加了一些更易于描述脚本的语法。

Gradle构建脚本可以包含任何Groovy语言标识。默认UTF-8编码。

API: Project

  • 调用当前脚本中没有的任何方法,都将委托给Project这个对象。
  • 调用当前脚本中没有的任何属性,都将委托给Project这个对象。
println name
println project.name

第一行,是由于当前脚本未定义name属性,则委托给project这个对象,所以第一行与第二行输出是一样的

标准的项目属性

Project这个对象,提供了几个标准的属性,可以构建脚本中直接使用,下面列出常用的几个

Name Type Default Value
project Project The Project instance
name String The name of the project directory.
path String The absolute path of the project.
description String A description for the project.
projectDir File The directory containing the build script.
buildDir File projectDir/build
group Object unspecified
version Object unspecified
ant AntBuilder An AntBuilder instance

API: Script

当Gradle执行构建脚本时,会将这个脚本编译成实现接口Script的类。也就是说,接口Script中的所有属性和方法,在构建脚本中都可以调用。
Script的官方文档: https://docs.gradle.org/current/dsl/org.gradle.api.Script.html

声明变更

在构建脚本中,有两种方式声明变更。本地变更(Local variables)和全局变量(Extra properties)

使用关键字def来进行声明本地变量(只在所声明范围有效)。这是Groovy的语法。
def示例:

def dest = "dest"

task copy(type: Copy) {
    from "source"
    into dest
}

使用关键字ext.作为前缀来声明全局变量。 这种变量,在子项目中,也是可见的。
包括但不限于,projectstaskssource都可以定义、改变及使用这种全局变量
ext.示例:

apply plugin: "java"

ext {
    springVersion = "3.1.0.RELEASE"
    emailNotification = "build@master.org"
}

sourceSets.all { ext.purpose = null }

sourceSets {
    main {
        purpose = "production"
    }
    test {
        purpose = "test"
    }
    plugin {
        purpose = "production"
    }
}

task printProperties << {
    println springVersion
    println emailNotification
    sourceSets.matching { it.purpose == "production" }.each { println it.name }
}

对上面的脚本,执行命令gradle -q printProperties,将输出:

D:\Learning\gradle\Extra properties>gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin

关于ext.的更多用法,参考: https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html

配置对象

可以使用如下示例的方式,配置任意对象,这样的脚本具有非常高的可读性。

task configure << {
    def pos = configure(new java.text.FieldPosition(10)) {
        beginIndex = 1
        endIndex = 5
    }
    println pos.beginIndex
    println pos.endIndex
}

执行命令gradle -q configure,将输出:

D:\Learning\gradle\Configuring arbitrary objects>gradle -q configure
1
5

使用外部脚本配置对象

示例,使用外部的other.gradle来对build.gradle的pos对象进行配置
build.gradle

task configure << {
    def pos = new java.text.FieldPosition(10)
    // Apply the script
    apply from: 'other.gradle', to: pos
    println pos.beginIndex
    println pos.endIndex
}

other.gradle

// Set properties.
beginIndex = 1
endIndex = 5

Groovy简单入门

Groovy提供了非常的DSL特性,而Gradle也继承了这些特性。懂得构建语言对编写脚本,特别是自定义插件和tasks时,是非常有用的。

1). Groovy JDK

在java的基础上,groovy添加了许多有用的方法。如,迭代(Iterable),在Groovy中,可以直接使用each方法。

// Iterable gets an each() method
configurations.runtime.each { File f -> println f }

http://groovy-lang.org/gdk.html 在详细的说明。

2). Property accessors

Groovy会自动将对属性的调用,转换为getter或setter方法。

// Using a getter method
println project.buildDir
println getProject().getBuildDir()

// Using a setter method
project.buildDir = 'target'
getProject().setBuildDir('target')

3). 方法调用可省略圆括号

test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')

4). List与map集合

Groovy提供了简捷的List与map的实例化方式。

// List literal
test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']

List<String> list = new ArrayList<String>()
list.add('org/gradle/api/**')
list.add('org/gradle/internal/**')
test.includes = list

// Map literal.
Map<String, String> map = [key1:'value1', key2: 'value2']

// Groovy will coerce named arguments
// into a single map argument
apply plugin: 'java'

5). 闭包作为方法的最后参数

Gradle DSL 在很多地方都使用了闭包。
参考: http://docs.groovy-lang.org/latest/html/documentation/index.html#_closures

repositories {
    println "in a closure"
}
repositories() { println "in a closure" }
repositories({ println "in a closure" })

6). 闭包委派

每个闭包,都会委派一个用于查找变量及方法的对象。

示例: 闭包委派

dependencies {
    assert delegate == project.dependencies
    testCompile('junit:junit:4.12')
    delegate.testCompile('junit:junit:4.12')
}

默认导入

为了使用脚本更简捷,Gradle自动导入一系列重要的声明。
主要是import org.gradle.*及这个包下的子包

深入tasks

区别于Ant的target,Gradle支持增强的tasks,它可以有自己的属性和方法。

定义task

示例1: 定义task

task(hello) << {
    println "hello"
}

task(copy, type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

示例2:使用strings作为task名字

task('hello') <<
{
    println "hello"
}

task('copy', type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

示例3:对示例2的替代语法

tasks.create(name: 'hello') << {
    println "hello"
}

tasks.create(name: 'copy', type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

对于task的create方法,参考: https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskContainer.html

定位tasks

示例1:通过tasks的属性访问task

task hello

println hello.name
println project.hello.name

示例2:通过tasks集合访问task

task hello

println tasks.hello.name
println tasks['hello'].name

示例3:通过路径访问task

project(':projectA') {
    task hello
}

task hello

println tasks.getByPath('hello').path
println tasks.getByPath(':hello').path
println tasks.getByPath('projectA:hello').path
println tasks.getByPath(':projectA:hello').path

对于示例3,需要在当前路径中,添加名为projectA的文件夹,并在配置文件settings.gradle中添加include 'projectA'
示例3的输出如下:

D:\Learning\gradle\Locating tasks>gradle -q hello
:hello
:hello
:projectA:hello
:projectA:hello

对于更多的定位tasks的介绍,访问 https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskContainer.html

配置tasks

首先来看一下Gradle提供的Copy task。可以如下定义一个Copy task

task myCopy(type: Copy)

这个myCopy并没有定义默认的操作,但它可以使用Copy的API了。下面会举几个例子,有不同的方式达到同样的目的。
Copy API: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html
当然,这个myCopy只是一个Copy类型的task,同样还可以定义更多的Copy类型的task。

示例1: 使用不同的方式配置task

Copy myCopy = task(myCopy, type: Copy)
myCopy.from 'resources'
myCopy.into 'target'
myCopy.include('**/*.txt', '**/*.xml', '**/*.properties')

对于示例1的方式,很类似于java。但这种方式比较冗余,而且代码可读性不强。

下面示例比较常用的方式。
示例2: 使用闭包配置task

task myCopy(type: Copy)

myCopy {
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

也可以直接使用如下方式:

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

为task添加依赖

示例1: 直接使用task名字关联

project('projectA') {
    task taskX(dependsOn: ':projectB:taskY') << {
        println 'taskX'
    }
}

project('projectB') {
    task taskY << {
        println 'taskY'
    }
}

执行gradle -q taskX,将输出:

D:\Learning\gradle\Adding dependencies to a task>gradle -q taskX
taskY
taskX

示例2: 使用对应task对象关联

task taskX << {
    println 'taskX'
}

task taskY << {
    println 'taskY'
}

taskX.dependsOn taskY

执行gradle -q taskX,也将输出:

D:\Learning\gradle\Adding dependencies to a task>gradle -q taskX
taskY
taskX

示例3: 使用闭包添加依赖

task taskX << {
    println 'taskX'
}

taskX.dependsOn {
    tasks.findAll { task -> task.name.startsWith('lib') }
}

task lib1 << {
    println 'lib1'
}

task lib2 << {
    println 'lib2'
}

task notALib << {
    println 'notALib'
}

执行gradle -q taskX,将输出:

D:\Learning\gradle\Adding dependencies to a task>gradle -q taskX
lib1
lib2
taskX

关于task的更多用法,参考: https://docs.gradle.org/current/dsl/org.gradle.api.Task.html

tasks排序

这是一个还在孵化中的特性,在以后的Gradle版本中可能变更。

排序与依赖的区别在于,排序并不会影响到task的执行,只是设定tasks的执行顺序。

排序,在下面情况下会很有用处:

  • 有强制顺序的tasks排序:如build永远不会在clean之前执行
  • build之前执行构建校验:如校验是否有权限执行build
  • 在耗时长的验证task之前,通过执行一个快速验证获得反馈:如在集成测试之前,应该先执行单元测试
  • 一个收集所有特定类型task执行结果的task:如,测试报告task,它会收集所有测试task的运行结果。

只支持两排序方式: must run aftershould run after

示例1

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
taskY.mustRunAfter taskX

执行gradle -q taskY taskX输出:

D:\Learning\gradle\Ordering tasks>gradle -q taskY taskX
taskX
taskY

示例2

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
taskY.shouldRunAfter taskX

执行gradle -q taskY taskX输出:

D:\Learning\gradle\Ordering tasks>gradle -q taskY taskX
taskX
taskY

示例3

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
task taskZ << {
    println 'taskZ'
}
taskX.dependsOn taskY
taskY.dependsOn taskZ
taskZ.shouldRunAfter taskX

执行gradle -q taskX输出:

D:\Learning\gradle\Ordering tasks>gradle -q taskY taskX
taskZ
taskY
taskX

为task添加扫描信息

示例:

task copy(type: Copy) {
   description 'Copies the resource directory to the target directory.'
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

tasks覆盖

使用overwrite,示例:

task copy(type: Copy)

task copy(overwrite: true) << {
    println('I am the new one.')
}

执行 gradle -q copy,将输出

> gradle -q copy
I am the new one.

跳过task的执行

1). 使用断言

可以使用方式onlyIf()为task添加断言。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM