- 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加
- 915. Partition Array into Disjoint Intervals 分割数组
- 932. Beautiful Array 漂亮数组
- 940. Distinct Subsequences II 不同的子序列 II
projects 和 tasks是 Gradle 中最重要的两个概念。
任何一个 Gradle 构建都是由一个或多个 projects 组成。每个 project 包括许多可构建组成部分。 这完全取决于你要构建些什么。举个例子,每个 project 或许是一个 jar 包或者一个 web 应用,它也可以是一个由许多其他项目中产生的 jar 构成的 zip 压缩包。一个 project 不必描述它只能进行构建操作。它也可以部署你的应用或搭建你的环境。不要担心它像听上去的那样庞大。 Gradle 的 build-by-convention 可以让您来具体定义一个 project 到底该做什么。
每个project 都由多个 tasks 组成。每个 task 都代表了构建执行过程中的一个原子性操作。如编译,打包,生成 javadoc,发布到某个仓库等操作。
到目前为止,可以发现我们可以在一个 project 中定义一些简单任务,后续章节将会阐述多项目构建和多项目多任务的内容。
你可以通过在命令行运行 gradle 命令来执行构建,gradle 命令会从当前目录下寻找 build.gradle 文件来执行构建。我们称 build.gradle 文件为构建脚本。严格来说这其实是一个构建配置脚本,后面你会了解到这个构建脚本定义了一个 project 和一些默认的 task。
你可以创建如下脚本到 build.gradle 中 To try this out,create the following build script named build.gradle。
build.gradle
task hello {
doLast {
println 'Hello world!'
}
}
然后在该文件所在目录执行 gradle -q hello
-q 参数的作用是什么?
该文档的示例中很多地方在调用 gradle 命令时都加了 -q 参数。该参数用来控制 gradle 的日志级别,可以保证只输出我们需要的内容。具体可参阅本文档第十八章日志来了解更多参数和信息。
Output of gradle -q hello
> gradle -q hello
Hello world!
上面的脚本定义了一个叫做 hello 的 task,并且给它添加了一个动作。当执行 gradle hello 的时候, Gralde 便会去调用 hello 这个任务来执行给定操作。这些操作其实就是一个用 groovy 书写的闭包。
如果你觉得它看上去跟 Ant 中的 targets 很像,那么是对的。Gradle 的 tasks 就相当于 Ant 中的 targets。不过你会发现他功能更加强大。我们只是换了一个比 target 更形象的另外一个术语。不幸的是这恰巧与 Ant 中的术语有些冲突。ant 命令中有诸如 javac、copy、tasks。所以当该文档中提及 tasks 时,除非特别指明 ant task。否则指的均是指 Gradle 中的 tasks。
用一种更简洁的方式来定义上面的 hello 任务。
build.gradle
task hello << {
println 'Hello world!'
}
上面的脚本又一次采用闭包的方式来定义了一个叫做 hello 的任务,本文档后续章节中我们将会更多的采用这种风格来定义任务。
Gradle 脚本采用 Groovy 书写,作为开胃菜,看下下面这个例子。
build.gradle
task upper << {
String someString = 'mY_nAmE'
println "Original: " + someString
println "Upper case: " + someString.toUpperCase()
}
Output of gradle -q upper
> gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME
或者
build.gradle
task count << {
4.times { print "$it " }
}
Output of gradle -q count
> gradle -q count
0 1 2 3
你可以按如下方式创建任务间的依赖关系
build.gradle
task hello << {
println 'Hello world!'
}
task intro(dependsOn: hello) << {
println "I'm Gradle"
}
gradle -q intro 的输出结果
Output of gradle -q intro
\> gradle -q intro
Hello world!
I'm Gradle
添加依赖 task 也可以不必首先声明被依赖的 task。
build.gradle
task taskX(dependsOn: 'taskY') << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
Output of gradle -q taskX
\> gradle -q taskX
taskY
taskX
可以看到,taskX 是 在 taskY 之前定义的,这在多项目构建中非常有用。
注意:当引用的任务尚未定义的时候不可使用短标记法来运行任务。
借助Groovy 的强大不仅可以定义简单任务还能做更多的事。例如,可以动态定义任务。
build.gradle
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
gradle -q task1 的输出结果。
Output of gradle -q task1
\> gradle -q task1
I'm task number 1
一旦任务被创建后,任务之间可以通过 API 进行相互访问。这也是与 Ant 的不同之处。比如可以增加一些依赖。
build.gradle
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
task0.dependsOn task2, task3
gradle -q task0的输出结果。
Output of gradle -q task0
\> gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0
为已存在的任务增加行为。
build.gradle
task hello << {
println 'Hello Earth'
}
hello.doFirst {
println 'Hello Venus'
}
hello.doLast {
println 'Hello Mars'
}
hello << {
println 'Hello Jupiter'
}
Output of gradle -q hello
> gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter
doFirst 和 doLast 可以进行多次调用。他们分别被添加在任务的开头和结尾。当任务开始执行时这些动作会按照既定顺序进行。其中 << 操作符 是 doLast 的简写方式。
你早就注意到了吧,没错,每个任务都是一个脚本的属性,你可以访问它:
build.gradle
task hello << {
println 'Hello world!'
}
hello.doLast {
println "Greetings from the $hello.name task."
}
gradle -q hello 的输出结果
Output of gradle -q hello
\> gradle -q hello
Hello world!
Greetings from the hello task.
对于插件提供的内置任务。这尤其方便(例如:complie)
你可以为一个任务添加额外的属性。例如,新增一个叫做 myProperty 的属性,用 ext.myProperty 的方式给他一个初始值。这样便增加了一个自定义属性。
build.gradle
task myTask {
ext.myProperty = "myValue"
}
task printTaskProperties << {
println myTask.myProperty
}
gradle -q printTaskProperties 的输出结果
Output of gradle -q printTaskProperties
\> gradle -q printTaskProperties
myValue
自定义属性不仅仅局限于任务上,还可以做更多事情。
Ant任务是 Gradle 中的一等公民。Gradle 借助 Groovy 对 Ant 任务进行了优秀的整合。Gradle 自带了一个 AntBuilder,在 Gradle 中调用 Ant 任务比在 build.xml 中调用更加的方便和强大。 通过下面的例子你可以学到如何调用一个 Ant 任务以及如何与 Ant 中的属性进行通信。
build.gradle
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]}"
}
}
}
gradle -q loadfile 的输出结果
Output of gradle -q loadfile
\> gradle -q loadfile
*** agile.manifesto.txt ***
Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan
*** gradle.manifesto.txt ***
Make the impossible possible, make the possible easy and make the easy elegant.
(inspired by Moshe Feldenkrais)
在你脚本里还可以利用 Ant 做更多的事情。想了解更多请参阅在 Gradle 中调用 Ant。
Gradle 的强大要看你如何编写脚本逻辑。针对上面的例子,首先要做的就是要抽取方法。
build.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()
}
gradle -q loadfile 的输出结果
Output of gradle -q loadfile
\> gradle -q loadfile
I'm fond of agile.manifesto.txt
I'm fond of gradle.manifesto.txt
在后面的章节你会看到类似出去出来的方法可以在多项目构建中的子项目中调用。无论构建逻辑多复杂,Gradle 都可以提供给你一种简便的方式来组织它们。
Gradle 允许在脚本中定义多个默认任务。
build.gradle
defaultTasks 'clean', 'run'
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
gradle -q 的输出结果。
Output of gradle -q
\> gradle -q
Default Cleaning!
Default Running!
这与直接调用 gradle clean run 效果是一样的。在多项目构建中,每个子项目都可以指定单独的默认任务。如果子项目未进行指定将会调用父项目指定的的默认任务。
稍后会对 Gradle 的配置阶段和运行阶段进行详细说明 配置阶段后,Gradle 会了解所有要执行的任务 Gradle 提供了一个钩子来捕获这些信息。一个例子就是可以检查已经执行的任务中有没有被释放。借由此,你可以为一些变量赋予不同的值。
在下面的例子中,为 distribution 和 release 任务赋予了不同的 version 值。
build.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 的输出结果
Output of gradle -q distribution
\> gradle -q distribution
We build the zip with version=1.0-SNAPSHOT
gradle -q release 的输出结果
Output of gradle -q release
\> gradle -q release
We build the zip with version=1.0
We release now
whenReady 会在已发布的任务之前影响到已发布任务的执行。即使已发布的任务不是主要任务(也就是说,即使这个任务不是通过命令行直接调用)
在本章中,我们了解了什么是 task,但这还不够详细。欲知更多请参阅章节任务详述。
我在使用 gradle 构建一个特定应用程序时遇到问题。该应用程序可以用 eclipse 编译和构建,它在平板电脑上运行良好。当我尝试使用 Gradle 构建它时,“compileDebugJava”
我有一个 C 程序,是一位离开的开发人员留给我的。我试图弄清楚他到底在做什么,并将软件重新安排成更合乎逻辑的东西,这样我就可以更轻松地构建它。我正在使用 CMake 构建,而他使用的是 Make。 有
我刚开始阅读“Pro Spring MVC with web flow”,它附带了一个我想遵循的代码示例。 我要什么 - 我想像书中那样构建应用程序,使用 Gradle 有什么问题 - 我没用过 Gr
我希望有人已经这样做了。我正在尝试为我的一个 angular 2 项目在 teamcity 中建立一个连续的构建。在做了一些研究之后,我按照以下步骤操作: 构建步骤 1:为 teamcity 安装 j
我有一个旧的 ASP.Net 网站解决方案,看起来像: 当我在 Visual Studio 中构建解决方案时,我得到以下输出: ------ Build started: Project: C:\..
我使用 gulp-usref、gulp-if、gulp-uglify、gulp-csso 和 gulp-file-include 来构建我的应用程序。除了 HTML 保持原样外,构建中的一切都运行良好
我正在使用 ionic2 开发内部移动应用程序。我可以通过以下方式成功构建 ios: ionic build ios and ionic build ios --prod 但当我这样做时,它一直失败
我是一位经验丰富的 .NET/C# 开发人员,但对这里的几乎所有技术/库(包括 SQL/DB 工作)都是新手。 我正在开发一个具有 Azure/Entity Framework .NET 后端和可移植
我正在使用 VS 2008。我可以使用 IDE 成功编译我的解决方案。但是,当我尝试使用 devenv.com 构建它时,它失败并提示“错误:找不到项目输出组'(无法确定名称)的输出”。该组、其配置或
版本: ember.js 2.7,ember-data 2.7 ember-cli 2.9.1//同样适用于 ember-cli 2.7 node 6.9.1, npm 3.10.9//也适用于 no
我第一次修补 AzureDevops,设置一些 CI 任务。 我有一个公共(public)存储库(开源)和一个包含 3 个 F# 项目的解决方案(.sln)。该解决方案在 Windows/Mac/Li
目前 5.1.5 版本或 STLPort CVS 存储库似乎仍不支持 VS2008。如果有人已经完成了这项工作,那么如果可能的话,分享会很有用:) 同样,了解 VS2005 或 2008 x64 构建
我有一个 Python 2.7 项目,到目前为止一直使用 gfortran 和 MinGW 来构建扩展。我使用 MinGW,因为它似乎支持 Fortran 代码中的写入语句和可分配数组,而 MSVC
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 9年前关闭。 Improve this que
我想知道为什么在 Zimbra Wiki 中只列出了构建过程的特定平台。这意味着不可能在其他 Linux 发行版上构建 Zimbra? Zimbra 社区选择一个特殊的 Linux 发行版来构建 Zi
我将在 Swift 中构建一个 CLI 工具。我用这个命令创建了项目 swift package init --type executable当我构建我的项目并解析 时读取别名 Xcode 中的参数并
我想为添加到 docker 镜像的文件设置文件权限。我有这个简单的 Dockerfile: FROM ubuntu:utopic WORKDIR /app RUN groupadd -g 1000 b
当我使用 clBuildProgram在我的 OpenCl 代码中,它失败并显示错误代码 -11,没有任何日志信息。 这是我的代码的样子: ret = clBuildProgram(program
我有一个底部导航栏,它有一个列表页面,该页面使用状态块。 class _MainPageState extends State { int _index = 0; @override Wi
我在本地计算机上使用Jenkins(Jenkins URL未通过Internet公开,但该计算机上已启用Internet。) 我进行了以下配置更改: 在Jenkins工具上安装了Git和Github插
我是一名优秀的程序员,十分优秀!