gradle构建脚本的基本

半兽人 发表于: 2016-09-03   最后更新时间: 2017-09-06 14:28:30  
{{totalSubscript}} 订阅, 4,890 游览

在 Gradle 中两个顶级概念:project(项目)和 task (任务)

所有 Gradle 都有一个或多个 project 构成。project 的展现取决于 Gradle 所做的工作。举例。 project可以是一个 JAR 库或者是 web 应用。它可以是由项目生产 JAR 组成发布的 ZIP。一个 project 不一定代表一个东西要构建。它可能是一件要做的事,如将应用程序部署到工作台或生产环境。如果这看起来有点模糊,现在不要担心。Gradle 基于约定的构建支持增加一个更具体的定义的 project。

每个项目都是由一个或多个 task。一个 task 代表了一个构建生成的原子的作品。这可能是编写一些类,创建一个 JAR ,生成 Javadoc,或发布一些库。

现在,我们将看看在构建一个 project 时定义一些简单的 task 。后面的章节将介绍多个 project 和更多的 task 。

Hello world

运行 Gradle 是使用 gradle 命令行。命令行会寻找项目的根目录下 build.gradle 的文件(有关命令行,详见 Appendix D. Gradle Command Line 命令行),这个就是构建的脚本,或者严格说是构建的配置脚本。他定义了project(项目)和 task 任务)。

尝试输出,创建一个 build.gradle 命名的文件:

build.gradle

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

命令行切换到包含 build.gradle 文件的目录,执行 gradle -q hello

screenshot

输出为:

> gradle -q hello
Hello world!

这个脚本定义了一个名字是 hello 的 task,并且添加了动作。当运行 gradle hello ,Gradle 执行这个 hello task,接着执行里面的动作。这里的动作只是简单的包含了一些可以执行的 Groovy 代码。

看上去很像 Ant,是的,Gradle task 是相当于 Ant 的 target,但是你将看到,他们更强大。我们使用了跟 Ant 不同的术语,因为 task 比 target 更富表现力。

不幸的是,这一术语与 Ant 有冲突,Ant 调用它的命令行,如 javac 或copy 称之为 task 。所以当我们谈论的 task ,默认说的是 Gradle task ,这是相当 Ant 的 target。如果我们谈论的 Ant 的 task (Ant 命令),我们明确地说的 Ant task。

命令行加中 -q 的作用

q 是 quiet 的简写,意思是要安静、干净的输出。如果不加 -q 则会输出日志。详见日志.下面是对比

快捷 task 定义

定义 task 可以使用快捷方式,这样更简明。

build.gradle

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

再次执行,得到相同的输出。在下面的文章中,我们都会采用这种定义方式。
screenshot

构建的脚本都是代码

工具的构建脚本给你完整的 Groovy 的功能。作为开胃菜,看看这个:

build.gradle

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

执行 gradle -q upper 输出

> gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME

或者

build.gradle

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

执行 gradle -q count 输出

> gradle -q count
0 1 2 3

依赖

可以声明 task 与 其他 task 的依赖

build.gradle

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

执行 gradle -q intro 输出

> gradle -q intro
Hello world!
I'm Gradle

添加一个依赖,相应的 task 不需要存在

build.gradle

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

执行 gradle -q taskX输出

> gradle -q taskX
taskY
taskX

taskX 的依赖 taskY 是在 taskY 定义之前 声明的。这个在多 project 构建时很重要。关于 task 的依赖详见 更多关于任务

请注意不要使用快捷符号,当引用的 task 还没有定义的情况下。

动态 task

Groovy 的能力不仅仅是定义一个 task。例如,你也可以用它来动态创建的 task。

build.gradle

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

执行 gradle -q task1 输出

> gradle -q task1
I'm task number 1

screenshot

利用现有的任务

一旦 task 创建,他们可以通过一个 API 访问。例如,在运行时您可以使用此动态添加依赖到 task 。Ant 不允许这样的事情。

build.gradle

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

执行 gradle -q task0 输出

> gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0

或者 可以添加行为到一个已经存在 task 中

build.gradle

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

执行 gradle -q hello 输出

> gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter

doFirst 和 doLast 可以多次执行调用。他们在开始或结束的 task 动作清单中添加动作。task 执行时,按动作列表的顺序执行的动作。操作符 << 仅仅是 doLast 的别名。

快捷符号
在前面的示例中已经注意到,有一个方便的符号访问现有的 task 。每个 task 可以作为构建脚本的一个属性:

build.gradle

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

执行 gradle -q hello输出

> gradle -q hello
Hello world!
Greetings from the hello task.

这使得代码可读性增强,尤其是当使用的插件提供的 task ,如 compile task

额外 task 属性
可以添加自己属性到 task ,添加 myProperty属性,设置 、ext.myProperty 初始值,从这一点上,该属性可以读取和设置就像一个预定义的任务属性。

build.gradle

    task myTask {
        ext.myProperty = "myValue"
    }

    task printTaskProperties << {
        println myTask.myProperty
    }

执行 gradle -q printTaskProperties输出

> gradle -q printTaskProperties
myValue

task 不对额外属性做限制,更多详见编写构建脚本

使用 Ant task

Ant task 是 Gradle 一等公民。 Gradle 给 Ant task 提供了不错的整合通过简单依靠于 Gradle 。Groovy 被奇异的 AntBuilder 装载。从 Gradle 使用 Ant task 比使用 build.xml 文件更方便和更强大。从下面的例子中,你可以学习如何执行 Ant task 和如何访问 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输出

> 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输出

> gradle -q loadfile
I'm fond of agile.manifesto.txt
I'm fond of gradle.manifesto.txt

以后你会发现这样的方法可以在多 project 构建的子 project 之间共享。如果你建立逻辑变得越来越复杂,Gradle 为您提供其他工具很方便的方式来组织它。

默认 task

Gradle 允许你定义一个或多个默认 task 给你的构建

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 输出

> gradle -q
Default Cleaning!
Default Running!

这个等于执行了 gradle clean run ,在多 project 中构建所有的子 project 都可以有自己具体的默认 task 。如果 子 project 没有明确的默认 task,则执行父 project 的默认 task(如果定义的话)

通过 DAG 配置

以后会详细描述,Gradle 有配置阶段和执行阶段。配置阶段后,Gradle 知道所有的 task 应该执行。Gradle 提供给你一个钩子来利用这些信息。这个用例将检查发布 的 task 是否是要执行的 task。基于此,你可以赋予不同的值到一些变量。

在下面的例子中,在不同 version 变量中的 distribution 和 release task 执行结果不同。

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 输出

> gradle -q distribution
We build the zip with version=1.0-SNAPSHOT

执行 gradle -q release 输出

> gradle -q release
We build the zip with version=1.0
We release now

whenReady影响了 release task 在 release task 被执行之前。同样适用于 release task 不是 主 task 的情况(比如,task 被 gradle 命令通过了)

更新于 2017-09-06
在线,4小时前登录

查看gradle更多相关的文章或提一个关于gradle的问题,也可以与我们一起分享文章