Gradle第六章:Build腳本基礎

本文來源於:http://blog.csdn.net/maosidiaoxian/article/details/45664943

6.1. Projects and tasks

projects 和 tasks是Gradle中最重要的兩個概念
Everything in Gradle sits on top of two basic concepts: projects and tasks.

任何一個Gradle構建都是由一個或多個 projects 組成.每個project包括許多可構建組成部分. 這完全取決於你要構建些什麼.舉個栗子.每個project或許是一個jar包或者一個web應用, 它也可以是一個由許多其他項目中產生的jar構成的zip壓縮包.一個project不必描述它只能進行構建操作. 它也可以部署你的應用或搭建你的環境.不要擔心它像聽上去的那樣龐大. Gradle的build-by-convention可以讓您來具體定義一個project到底該做什麼.
Every Gradle build is made up of one or more projects. What a project represents depends on what it is that you are doing with Gradle. For example, a project might represent a library JAR or a web application. It might represent a distribution ZIP assembled from the JARs produced by other projects. A project does not necessarily represent a thing to be built. It might represent a thing to be done, such as deploying your application to staging or production environments. Don't worry if this seems a little vague for now. Gradle's build-by-convention support adds a more concrete definition for what a project is.

每個project都由多個tasks組成.每個task都代表了構建執行過程中的一個原子性操作.如編譯,打包,生成javadoc,發佈到某個倉庫等操作
Each project is made up of one or more tasks. A task represents some atomic piece of work which a build performs. This might be compiling some classes, creating a JAR, generating javadoc, or publishing some archives to a repository.

到目前爲止,可以發現我們可以在一個project中定義一些簡單任務,後續章節將會闡述多項目構建和多項目多任務的內容.
For now, we will look at defining some simple tasks in a build with one project. Later chapters will look at working with multiple projects and more about working with projects and tasks.

6.2. Hello world

6.2. Hello world

你可以通過在命令行運行gradle命令來執行構建, gradle命令會從當前目錄下尋找 build.gradle 文件來執行構建.我們稱 build.gradle 文件爲構建腳本. 嚴格來說這其實是一個構建配置腳本,後面你會瞭解到這個構建腳本定義了一個project和一些默認的task
You run a Gradle build using the gradle command. The gradle command looks for a file called build.gradle in the current directory. [2We call this build.gradle file a build script, although strictly speaking it is a build configuration script, as we will see later. The build script defines a project and its tasks.

你可以創建如下腳本到 build.gradle 中 To try this out, create the following build script named build.gradle .

例6.1. 第一個構建腳本
Example 6.1. The first build script

build.gradle

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

然後在該文件所在目錄執行 gradle -q hello
In a command-line shell, enter into the containing directory and execute the build script by running gradle -q hello:

-q 參數的作用是什麼?

What does -q do?

該文檔的示例中很多地方在調用gradle命令時都加了 -q 參數. 該參數用來控制gradle的日誌級別,可以保證只輸出我們需要的內容. 具體可參閱本文檔 第十八章 日誌 來了解更多參數和信息.
Most of the examples in this user guide are run with the -qcommand-line option. This suppresses Gradle's log messages, so that only the output of the tasks is shown. This keeps the example output in this user guide a little clearer. You don't need to use this option if you don't want. See Chapter 18, Logging for more details about the command-line options which affect Gradle's output.

例6.2. 執行腳本
Example 6.2. Execution of a build script

Output of gradle -q hello

> gradle -q hello
Hello world!

上面的腳本定義了一個叫做 hello 的 task,並且給它添加了一個動作. 當執行gradle hello的時候, Gralde便會去調用 hello 這個任務來執行給定操作.這些操作其實就是一個用groovy書寫的閉包
What's going on here? This build script defines a single task, called hello , and adds an action to it. When you run gradle hello, Gradle executes the hello task, which in turn executes the action you've provided. The action is simply a closure containing some Groovy code to execute.

如果你覺得它看上去跟Ant中的targets很像,那麼是對的. Gradle的tasks就相當於Ant中的targets.不過你會發現他功能更加強大. 我們只是換了一個比target更形象的另外一個術語.不幸的是這恰巧與Ant中的術語有些衝突. ant 命令中有諸如javac、copy、tasks.所以當該文檔中提及tasks時,除非特別指明 ant task. 否則指的均是指Gradle中的tasks.
If you think this looks similar to Ant's targets, well, you are right. Gradle tasks are the equivalent to Ant targets. But as you will see, they are much more powerful. We have used a different terminology than Ant as we think the word task is more expressive than the word target. Unfortunately this introduces a terminology clash with Ant, as Ant calls its commands, such as javac or copy , tasks. So when we talk about tasks, we alwaysmean Gradle tasks, which are the equivalent to Ant's targets. If we talk about Ant tasks (Ant commands), we explicitly say ant task.

6.3. 快速定義任務

6.3. A shortcut task definition

用一種更簡潔的方式來定義 上面的 hello 任務.
There is a shorthand way to define a task like our hello task above, which is more concise.

例6.3.快速定義任務
Example 6.3. A task definition shortcut

build.gradle

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

上面的腳本又一次採用閉包的方式來定義了一個叫做hello的任務,本文檔後續章節中我們將會更多的採用這種風格來定義任務.
Again, this defines a task called hello with a single closure to execute. We will use this task definition style throughout the user guide.

6.4. 代碼即腳本

6.4. Build scripts are code

Gradle腳本採用Groovy書寫,作爲開胃菜,看下下面這個栗子. Gradle's build scripts expose to you the full power of Groovy. As an appetizer, have a look at this:

•例6.4 在gradle任務中採用groovy
Example 6.4. Using Groovy in Gradle's tasks

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

或者
or

•例6.5 在gradle任務中採用groovy
Example 6.5. Using Groovy in Gradle's tasks

build.gradle

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

Output of gradle -q count

> gradle -q count
0 1 2 3

6.5. 任務依賴

6.5. Task dependencies

你可以按如下方式創建任務間的依賴關係
As you probably have guessed, you can declare dependencies between your tasks.

在兩個任務之間指明依賴關係
Example 6.6. Declaration of dependencies between tasks

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.
To add a dependency, the corresponding task does not need to exist.

Example 6.7. 延遲依賴 .Lazy dependsOn - the other task does not exist (yet)

build.gradle

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

Output of gradle -q taskX

> gradle -q taskX
taskY
taskX

可以看到, taskX 是 在 taskY 之前定義的,這在多項目構建中非常有用 關於任務依賴的更多信息可以查看章節 15.4, “給任務添加依賴”..
The dependency of taskX to taskY is declared before taskY is defined. This is very important for multi-project builds. Task dependencies are discussed in more detail in Section 15.4, “Adding dependencies to a task”.

注意:當引用的任務尚未定義的時候不可使用短標記法(see 章節 6.8, “短標記法”) 來運行任務.
Please notice that you can't use shortcut notation (see Section 6.8, “Shortcut notations”) when referring to a task that is not yet defined.

6.6. 動態任務

6.6. Dynamic tasks

藉助Groovy的強大不僅可以定義簡單任務還能做更多的事.例如,可以動態定義任務.
The power of Groovy can be used for more than defining what a task does. For example, you can also use it to dynamically create tasks.

例 6.8. 創建動態任務
Example 6.8. Dynamic creation of a task

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

6.7. 任務操縱

6.7. Manipulating existing tasks

一旦任務被創建後,任務之間可以通過API進行相互訪問.這也是與Ant的不同之處.比如可以增加一些依賴.
Once tasks are created they can be accessed via an API. This is different to Ant. For example you can create additional dependencies.

例 6.9. 通過API進行任務之間的通信 - 增加依賴
Example 6.9. Accessing a task via API - adding a dependency

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

爲已存在的任務增加行爲.
Or you can add behavior to an existing task.

例 6.10. 通過API進行任務之間的通信 - 增加任務行爲
Example 6.10. Accessing a task via API - adding behaviour

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 的簡寫方式.
The calls doFirst and doLast can be executed multiple times. They add an action to the beginning or the end of the task's actions list. When the task executes, the actions in the action list are executed in order. The <<operator is simply an alias for doLast .

6.8. 短標記法

6.8. Shortcut notations

你早就注意到了吧,沒錯,每個任務都是一個腳本的屬性,你可以訪問它:
As you might have noticed in the previous examples, there is a convenient notation for accessing an existing task. Each task is available as a property of the build script:

例 6.11. 以屬性的方式訪問任務
Example 6.11. Accessing task as a property of the build script

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)
This enables very readable code, especially when using the out of the box tasks provided by the plugins (e.g. compile ).

6.9. 增加自定義屬性

6.9. Extra task properties

你可以爲一個任務添加額外的屬性.例如,新增一個叫做 myProperty 的屬性,用 ext.myProperty 的方式給他一個初始值.這樣便增加了一個自定義屬性.
You can add your own properties to a task. To add a property named myProperty , set ext.myProperty to an initial value. From that point on, the property can be read and set like a predefined task property.

例 6.12. 爲任務增加自定義屬性
Example 6.12. Adding extra properties to a task

build.gradle

task myTask {
    ext.myProperty = "myValue"
}

task printTaskProperties << {
    println myTask.myProperty
}

gradle -q printTaskProperties的輸出結果
Output of gradle -q printTaskProperties

> gradle -q printTaskProperties
myValue
自定義屬性不僅僅侷限於任務上,還可以做更多事情.你可以閱讀章節 13.4.2, “自定義屬性”來了解更多內容.
Extra properties aren't limited to tasks. You can read more about them in Section 13.4.2, “Extra properties”.

6.10. 調用Ant任務

6.10. Using Ant Tasks

Ant任務是Gradle中的一等公民.Gradle藉助Groovy對Ant任務進行了優秀的整合. Gradle自帶了一個AntBuilder,在Gradle中調用Ant任務比在 build.xml中調用更加的方便和強大. 通過下面的例子你可以學到如何調用一個Ant任務以及如何與Ant中的屬性進行通信.
Ant tasks are first-class citizens in Gradle. Gradle provides excellent integration for Ant tasks by simply relying on Groovy. Groovy is shipped with the fantastic AntBuilder . Using Ant tasks from Gradle is as convenient and more powerful than using Ant tasks from a build.xml file. From the example below, you can learn how to execute ant tasks and how to access ant properties:

例 6.13. 利用AntBuilder執行 ant.loadfile 
Example 6.13. Using AntBuilder to execute ant.loadfile target

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做更多的事情.想了解更多請參閱 章節 17, 在Gradle中調用Ant
There is lots more you can do with Ant in your build scripts. You can find out more in Chapter 17, Using Ant from Gradle .

6.11. 方法抽取

6.11. Using methods

Gradle的強大要看你如何編寫腳本邏輯.針對上面的例子,首先要做的就是要抽取方法. 
Gradle scales in how you can organize your build logic. The first level of organizing your build logic for the example above, is extracting a method.

例 6.14 利用方法組織腳本邏輯
Example 6.14. Using methods to organize your build logic

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都可以提供給你一種簡便的方式來組織它們.想了解更多請參閱 章節 59, 組織構建邏輯
Later you will see that such methods can be shared among subprojects in multi-project builds. If your build logic becomes more complex, Gradle offers you other very convenient ways to organize it. We have devoted a whole chapter to this. See Chapter 59, Organizing Build Logic.

6.12. 定義默認任務

6.12. Default tasks

Gradle允許在腳本中定義多個默認任務. 
Gradle allows you to define one or more default tasks for your build.

例 6.15. 定義默認任務
Example 6.15. Defining a default tasks

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效果是一樣的. 在多項目構建中,每個子項目都可以指定單獨的默認任務.如果子項目未進行指定將會調用父項目指定的的默認任務. 
This is equivalent to running gradle clean run. In a multi-project build every subproject can have its own specific default tasks. If a subproject does not specify default tasks, the default tasks of the parent project are used (if defined).

6.13.  Configure by DAG

稍後會對Gradle的配置階段和運行階段進行詳細說明 (詳見 章節 55, 構建的生命週期 )配置階段後,Gradle會了解所有要執行的任務 Gradle提供了一個鉤子來捕獲這些信息.一個例子就是可以檢查已經執行的任務中有沒有被釋放.藉由此,你可以爲一些變量賦予不同的值. 
As we later describe in full detail (see Chapter 55, The Build Lifecycle), Gradle has a configuration phase and an execution phase. After the configuration phase, Gradle knows all tasks that should be executed. Gradle offers you a hook to make use of this information. A use-case for this would be to check if the release task is among the tasks to be executed. Depending on this, you can assign different values to some variables.

在下面的例子中,爲distributionrelease任務賦予了不同的 version值.
In the following example, execution of the distribution and release tasks results in different value of the version variable.

例 6.16. 依賴任務的不同輸出
Example 6.16. Different outcomes of build depending on chosen tasks

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會在已發佈的任務之前影響到已發佈任務的執行. 即使已發佈的任務不是 主要任務(也就是說,即使這個任務不是通過命令行直接調用)
The important thing is that whenReady affects the release task before the release task is executed. This works even when the release task is not the primary task (i.e., the task passed to the gradle command).

6.14. 下一步目標

6.14. Where to next?

在本章中,我們瞭解了什麼是task,但這還不夠詳細.欲知更多請參閱 章節 15, 任務進階
In this chapter, we have had a first look at tasks. But this is not the end of the story for tasks. If you want to jump into more of the details, have a look at Chapter 15, More about Tasks .

另外,可以目錄繼續學習 第七章 , Java 快速入門 和 第八章 , 依賴管理基礎.
Otherwise, continue on to the tutorials in Chapter 7, Java Quickstart and Chapter 8, Dependency Management Basics.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章