国产gaysexchina男同gay,japanrcep老熟妇乱子伦视频,吃奶呻吟打开双腿做受动态图,成人色网站,国产av一区二区三区最新精品

第15章 More about Tasks 更多關于任務

2018-02-24 15:56 更新

在入門教程中(Chapter 06. Build Script Basics 構建腳本的基礎識),已經(jīng)學到了如何創(chuàng)建簡單 task。之后您還學習了如何將其他行為添加到這些 task 中,同時你已經(jīng)學會了如何創(chuàng)建 task 之間的依賴。這都是簡單的 task 。但 Gradle 讓 task 的概念更深遠。Gradle 支持增強的task,也就是,有自己的屬性和方法的 task 。這是真正的與你所使用的 Ant target(目標)的不同之處。這種增強的任務可以由你提供,或由 Gradle 構建。

15.1. Defining tasks 定義任務

在(Chapter 06. Build Script Basics 構建腳本的基礎識)中我們已經(jīng)看到如何通過關鍵字這種風格來定義 task 。在某些情況中,你可能需要使用這種關鍵字風格的幾種不同的變式。例如,在表達式中不能用這種關鍵字風格。

Example 15.1. Defining tasks

build.gradle

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

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

也可以使用字符串作為 task 名稱

Example 15.2. Defining tasks - using strings for task names

build.gradle

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

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

你可能更愿意使用另外一種替代的語法來定義任務:

Example 15.3. Defining tasks with alternative syntax

build.gradle

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

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

15.2. Locating tasks 定位任務

你經(jīng)常需要在構建文件中查找你所定義的 task,例如,為了去配置或是使用它們作為依賴。對這樣的情況,有很多種方法。首先,每個 task 都可作為 project 的一個屬性,并且使用 task 名稱作為這個屬性名稱:

Example 15.4. Accessing tasks as properties

build.gradle

task hello

println hello.name
println project.hello.name

task 也可以通過 task 集合來訪問

Example 15.5. Accessing tasks via tasks collection

build.gradle

task hello

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

您可以從任何 project 中,使用 tasks.getByPath() 方法獲取 task 路徑并且通過這個路徑來訪問 task。你可以用 task 名稱,相對路徑或者是絕對路徑作為參數(shù)調(diào)用 getByPath() 方法。

Example 15.6. Accessing tasks by path

build.gradle

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

執(zhí)行 gradle -q hello

> gradle -q hello
:hello
:hello
:projectA:hello
:projectA:hello

詳見?TaskContainer?關于更多定位 task 的選項

15.3. Configuring tasks 配置任務

作為一個例子,讓我們看看由 Gradle 提供的 Copy task。若要創(chuàng)建Copy task ,您可以在構建腳本中聲明:

Example 15.7. Creating a copy task

build.gradle

task myCopy(type: Copy)

上面的代碼創(chuàng)建了一個什么都沒做的復制 task 。可以使用它的 API 來配置這個任務 (見Copy)。下面的示例演示了幾種不同的方式來實現(xiàn)相同的配置。

要明白,意識到這項任務的名稱是 “myCopy”,但它的類型是“Copy”。你可以有多個同一類型的 task ,但具有不同的名稱。你會發(fā)現(xiàn)這給你一個很大的權力來實現(xiàn)橫切關注點在一個特定類型的所有 task。

Example 15.8. Configuring a task - various ways

build.gradle

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

這類似于我們通常在 Java 中配置對象的方式。您必須在每一次的配置語句重復上下文 (myCopy)。這顯得很冗余并且很不好讀。

還有另一種配置任務的方式。它也保留了上下文,且可以說是可讀性最強的。它是我們通常最喜歡的方式。

Example 15.9. Configuring a task - with closure

build.gradle

task myCopy(type: Copy)

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

這種方式適用于任何任務。該例子的第 3 行只是 tasks.getByName() 方法的簡潔寫法。特別要注意的是,如果您向 getByName() 方法傳入一個閉包,這個閉包的應用是在配置這個任務的時候,而不是任務執(zhí)行的時候。

您也可以在定義一個任務的時候使用一個配置閉包。

Example 15.10. Defining a task with closure

build.gradle

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

15.4. Adding dependencies to a task 給任務添加依賴

定義任務的依賴關系有幾種方法。在第 6.5 章節(jié),"任務依賴"中,已經(jīng)向你介紹了使用任務名稱來定義依賴。任務的名稱可以指向同一個項目中的任務,或者其他項目中的任務。要引用另一個項目中的任務,你需要把它所屬的項目的路徑作為前綴加到它的名字中。下面是一個示例,添加了從projectA:taskX 到 projectB:taskY 的依賴關系:

Example 15.11. Adding dependency on task from another project

build.gradle

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

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

執(zhí)行 gradle -q taskX

> gradle -q taskX
taskY
taskX

您可以使用一個 Task 對象而不是任務名稱來定義依賴,如下:

Example 15.12. Adding dependency using task object

build.gradle

task taskX << {
    println 'taskX'
}

task taskY << {
    println 'taskY'
}

taskX.dependsOn taskY

執(zhí)行 gradle -q taskX

> gradle -q taskX
taskY
taskX

對于更高級的用法,您可以使用閉包來定義 task 依賴。在計算依賴時,閉包會被傳入正在計算依賴的任務。這個閉包應該返回一個 Task 對象或是Task 對象的集合,返回值會被作為這個 task 的依賴項。下面的示例是從taskX 加入了 project 中所有名稱以 lib 開頭的 task 的依賴

Example 15.13. Adding dependency using closure

build.gradle

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'
}

執(zhí)行 gradle -q taskX

> gradle -q taskX
lib1
lib2
taskX

更多關于 task 依賴 ,見?Task?API

15.5. Ordering tasks 排序任務

任務排序還是一個孵化中的功能。請注意此功能在以后的 Gradle 版本中可能會改變。

在某些情況下,控制兩個任務的執(zhí)行的順序,而不引入這些任務之間的顯式依賴,是很有用的。任務排序和任務依賴之間的主要區(qū)別是,排序規(guī)則不會影響那些任務的執(zhí)行,而僅將執(zhí)行的順序。

任務排序在許多情況下可能很有用:

  • 強制任務順序執(zhí)行: 如,'build' 永遠不會在 'clean' 前面執(zhí)行。
  • 在構建中盡早進行構建驗證:如,驗證在開始發(fā)布的工作前有一個正確的證書。
  • 通過在長久驗證前運行快速驗證以得到更快的反饋:如,單元測試應在集成測試之前運行。
  • 一個任務聚合了某一特定類型的所有任務的結果:如,測試報告任務結合了所有執(zhí)行的測試任務的輸出。

有兩種排序規(guī)則是可用的:"必須在之后運行"和"應該在之后運行"。

通過使用 “必須在之后運行”的排序規(guī)則,您可以指定 taskB 必須總是運行在 taskA 之后,無論 taskA 和 taskB 這兩個任務在什么時候被調(diào)度執(zhí)行。這被表示為 taskB.mustRunAfter(taskA) ?!皯撛谥筮\行”的排序規(guī)則與其類似,但沒有那么嚴格,因為它在兩種情況下會被忽略。首先是如果使用這一規(guī)則引入了一個排序循環(huán)。其次,當使用并行執(zhí)行,并且一個任務的所有依賴項除了任務應該在之后運行之外所有條件已滿足,那么這個任務將會運行,不管它的“應該在之后運行”的依賴項是否已經(jīng)運行了。當傾向于更快的反饋時,會使用“應該在之后運行”的規(guī)則,因為這種排序很有幫助但要求不嚴格。

目前使用這些規(guī)則仍有可能出現(xiàn) taskA 執(zhí)行而 taskB 沒有執(zhí)行,或者taskB 執(zhí)行而 taskA 沒有執(zhí)行。

Example 15.14. Adding a 'must run after' task ordering

build.gradle

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

執(zhí)行 gradle -q taskY taskX

> gradle -q taskY taskX
taskX
taskY

Example 15.15. Adding a 'should run after' task ordering

build.gradle

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

執(zhí)行 gradle -q taskY taskX

> gradle -q taskY taskX
taskX
taskY

在上面的例子中,它仍有可能執(zhí)行 taskY 而不會導致 taskX 也運行:

Example 15.16. Task ordering does not imply task execution

執(zhí)行 gradle -q taskY

> gradle -q taskY
taskY

如果想指定兩個任務之間的“必須在之后運行”和“應該在之后運行”排序,可以使用?Task.mustRunAfter()?和Task.shouldRunAfter()?方法。這些方法接受一個任務實例、 任務名稱或?Task.dependsOn()?所接受的任何其他輸入作為參數(shù)。

請注意"B.mustRunAfter(A)"或"B.shouldRunAfter(A)"并不意味著這些任務之間的任何執(zhí)行上的依賴關系:

它是可以獨立地執(zhí)行任務 A 和 B 的。

  • 排序規(guī)則僅在這兩項任務計劃執(zhí)行時起作用。
  • 當--continue參數(shù)運行時,可能會是 A 執(zhí)行失敗后 B 執(zhí)行了。

如之前所述,如果“應該在之后運行”的排序規(guī)則引入了排序循環(huán),那么它將會被忽略。

Example 15.17. A 'should run after' task ordering is ignored if it introduces an ordering cycle

build.gradle

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

執(zhí)行 gradle -q taskX

> gradle -q taskX
taskZ
taskY
taskX

15.6. Adding a description to a task 給任務添加描述

可以給任務添加描述,這個描述將會在 task 執(zhí)行時顯示。

Example 15.18. Adding a description to a task

build.gradle

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

15.7. Replacing tasks 替換任務

有時您想要替換一個任務。例如,您想要把通過 Java 插件添加的一個任務與不同類型的一個自定義任務進行交換。你可以這樣實現(xiàn):

Example 15.19. Overwriting a task

build.gradle

task copy(type: Copy)

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

執(zhí)行 gradle -q copy

> gradle -q copy
I am the new one.

在這里我們用一個簡單的任務替換 Copy 類型的任務。當創(chuàng)建這個簡單的任務時,您必須將 overwrite 屬性設置為 true。否則 Gradle 將拋出異常,說這種名稱的任務已經(jīng)存在。

15.8. Skipping tasks 跳過任務

Gradle 提供多種方式來跳過任務的執(zhí)行。

15.8.1. Using a predicate 使用斷言

你可以使用 onlyIf() 方法將斷言附加到一項任務中。如果斷言結果為 true,才會執(zhí)行任務的操作。你可以用一個閉包來實現(xiàn)斷言。閉包會作為一個參數(shù)傳給任務,并且任務應該執(zhí)行時返回 true,或任務應該跳過時返回false。斷言只在任務要執(zhí)行前才計算。

Example 15.20. Skipping a task using a predicate

build.gradle

task hello << {
    println 'hello world'
}

hello.onlyIf { !project.hasProperty('skipHello') }

執(zhí)行 gradle hello -PskipHello

> gradle hello -PskipHello
:hello SKIPPED

BUILD SUCCESSFUL

Total time: 1 secs

15.8.2. Using StopExecutionException

如果跳過任務的規(guī)則不能與斷言同時表達,您可以使用StopExecutionException。如果一個操作(action)拋出了此異常,那么這個操作(action)接下來的行為和這個任務的其他 操作(action)都會被跳過。構建會繼續(xù)執(zhí)行下一個任務。

Example 15.21. Skipping tasks with StopExecutionException

build.gradle

task compile << {
    println 'We are doing the compile.'
}

compile.doFirst {
    // Here you would put arbitrary conditions in real life.
    // But this is used in an integration test so we want defined behavior.
    if (true) { throw new StopExecutionException() }
}
task myTask(dependsOn: 'compile') << {
   println 'I am not affected'
}

Output of gradle -q myTask

> gradle -q myTask
I am not affected

如果您使用由 Gradle 提供的任務,那么此功能將非常有用。它允許您向一個任務的內(nèi)置操作中添加執(zhí)行條件。(你可能會想,為什么既不導入StopExecutionException 也沒有通過其完全限定名來訪問它。原因是,Gradle 會向您的腳本添加默認的一些導入。這些導入是可自定義的 (見Appendix E. Existing IDE Support and how to cope without it 支持的 IDE 以及如何應對沒有它)。)

15.8.3. Enabling and disabling tasks 啟用和禁用任務

每一項任務有一個默認值為 true 的 enabled 標記。將它設置為 false,可以不讓這個任務的任何操作執(zhí)行。

Example 15.22. Enabling and disabling tasks

build.gradle

task disableMe << {
    println 'This should not be printed if the task is disabled.'
}
disableMe.enabled = false

執(zhí)行 gradle disableMe

> gradle disableMe
:disableMe SKIPPED

BUILD SUCCESSFUL

Total time: 1 secs

15.9. Skipping tasks that are up-to-date 跳過處于最新狀態(tài)的任務

如果您使用 Gradle 自帶的任務,如 Java 插件所添加的任務的話,你可能已經(jīng)注意到 Gradle 將跳過處于最新狀態(tài)的任務。這種行在您自己定義的任務上也有效,而不僅僅是內(nèi)置任務。

15.9.1. Declaring a task's inputs and outputs 聲明一個任務的輸入和輸出

讓我們來看一個例子。在這里我們的任務從一個 XML 源文件生成多個輸出文件。讓我們運行它幾次。

Example 15.23. A generator task

build.gradle

task transform {
    ext.srcFile = file('mountains.xml')
    ext.destDir = new File(buildDir, 'generated')
    doLast {
        println "Transforming source file."
        destDir.mkdirs()
        def mountains = new XmlParser().parse(srcFile)
        mountains.mountain.each { mountain ->
            def name = mountain.name[0].text()
            def height = mountain.height[0].text()
            def destFile = new File(destDir, "${name}.txt")
            destFile.text = "$name -> ${height}\n"
        }
    }
}

執(zhí)行 gradle transform

> gradle transform
:transform
Transforming source file.

執(zhí)行 gradle transform

> gradle transform
:transform
Transforming source file.

請注意 Gradle 第二次執(zhí)行執(zhí)行這項任務時,即使什么都未作改變,也沒有跳過該任務。我們的示例任務被用一個操作(action)閉包來定義。Gradle 不知道這個閉包做了什么,也無法自動判斷這個任務是否為最新狀態(tài)。若要使用 Gradle 的最新狀態(tài)(up-to-date)檢查,您需要聲明這個任務的輸入和輸出。

每個任務都有一個 inputs 和 outputs 的屬性,用來聲明任務的輸入和輸出。下面,我們修改了我們的示例,聲明它將 XML 源文件作為輸入,并產(chǎn)生輸出到一個目標目錄。讓我們運行它幾次。

Example 15.24. Declaring the inputs and outputs of a task

build.gradle

task transform {
    ext.srcFile = file('mountains.xml')
    ext.destDir = new File(buildDir, 'generated')
    inputs.file srcFile
    outputs.dir destDir
    doLast {
        println "Transforming source file."
        destDir.mkdirs()
        def mountains = new XmlParser().parse(srcFile)
        mountains.mountain.each { mountain ->
            def name = mountain.name[0].text()
            def height = mountain.height[0].text()
            def destFile = new File(destDir, "${name}.txt")
            destFile.text = "$name -> ${height}\n"
        }
    }
}

執(zhí)行 gradle transform

> gradle transform
:transform
Transforming source file.

執(zhí)行 gradle transform

> gradle transform
:transform UP-TO-DATE

現(xiàn)在,Gradle 知道哪些文件要檢查以確定任務是否為最新狀態(tài)。

任務的 inputs 屬性是?TaskInputs類型。任務的 outputs 屬性是?TaskOutputs?類型。

一個沒有定義輸出的任務將永遠不會被當作是最新的。對于任務的輸出并不是文件的場景,或者是更復雜的場景,TaskOutputs.upToDateWhen()?方法允許您以編程方式計算任務的輸出是否應該被判斷為最新狀態(tài)。

一個只定義了輸出的任務,如果自上一次構建以來它的輸出沒有改變,那么它會被判定為最新狀態(tài)。

15.9.2. How does it work 它是怎么實現(xiàn)的?

在第一次執(zhí)行任務之前,Gradle 對輸入進行一次快照。這個快照包含了輸入文件集和每個文件的內(nèi)容的哈希值。然后 Gradle 執(zhí)行該任務。如果任務成功完成,Gradle 將對輸出進行一次快照。該快照包含輸出文件集和每個文件的內(nèi)容的哈希值。Gradle 會保存這兩個快照,直到任務的下一次執(zhí)行。

之后每一次,在執(zhí)行任務之前,Gradle 會對輸入和輸出進行一次新的快照。如果新的快照和前一次的快照一樣,Gradle 會假定這些輸出是最新狀態(tài)的并跳過該任務。如果它們不一則, Gradle 則會執(zhí)行該任務。Gradle 會保存這兩個快照,直到任務的下一次執(zhí)行。

請注意,如果一個任務有一個指定的輸出目錄,在它上一次執(zhí)行之后添加到該目錄的所有文件都將被忽略,并且不會使這個任務成為過時狀態(tài)。這是不相關的任務可以在不互相干擾的情況下共用一個輸出目錄。如果你因為一些理由而不想這樣,請考慮使用?TaskOutputs.upToDateWhen

15.10. Task rules 任務規(guī)則

有時你想要有這樣一項任務,它的行為依賴于參數(shù)數(shù)值范圍的一個大數(shù)或是無限的數(shù)字。任務規(guī)則是提供此類任務的一個很好的表達方式:

Example 15.25. Task rule

build.gradle

tasks.addRule("Pattern: ping<ID>") { String taskName ->
    if (taskName.startsWith("ping")) {
        task(taskName) << {
            println "Pinging: " + (taskName - 'ping')
        }
    }
}

執(zhí)行 gradle -q pingServer1

> gradle -q pingServer1
Pinging: Server1

這個字符串參數(shù)被用作這條規(guī)則的描述。當對這個例子運行 gradle tasks 的時候,這個描述會被顯示。

規(guī)則不只是從命令行調(diào)用任務才起作用。你也可以對基于規(guī)則的任務創(chuàng)建依賴關系

Example 15.26. Dependency on rule based tasks

build.gradle

tasks.addRule("Pattern: ping<ID>") { String taskName ->
    if (taskName.startsWith("ping")) {
        task(taskName) << {
            println "Pinging: " + (taskName - 'ping')
        }
    }
}

task groupPing {
    dependsOn pingServer1, pingServer2
}

執(zhí)行 gradle -q groupPing

> gradle -q groupPing
Pinging: Server1
Pinging: Server2

執(zhí)行 gradle -q tasks 你找不到 “pingServer1” 或 “pingServer2” 任務,但腳本執(zhí)行邏輯是基于請求執(zhí)行這些任務的

15.11. Finalizer tasks 析構器任務

析構器任務是一個 孵化中 的功能 (請參閱Appendix C. The Feature Lifecycle 特性的生命周期?C.1.2 章節(jié), “Incubating”)。

當最終的任務準備運行時,析構器任務會自動地添加到任務圖中。

Example 15.27. Adding a task finalizer

build.gradle

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

taskX.finalizedBy taskY

執(zhí)行 gradle -q taskX

> gradle -q taskX
taskX
taskY

即使最終的任務執(zhí)行失敗,析構器任務也會被執(zhí)行。

Example 15.28. Task finalizer for a failing task

build.gradle

task taskX << {
    println 'taskX'
    throw new RuntimeException()
}
task taskY << {
    println 'taskY'
}

taskX.finalizedBy taskY

執(zhí)行 gradle -q taskX

> gradle -q taskX
taskX
taskY

另一方面,如果最終的任務什么都不做的話,比如由于失敗的任務依賴項或如果它被認為是最新的狀態(tài),析構任務不會執(zhí)行。

在不管構建成功或是失敗,都必須清理創(chuàng)建的資源的情況下,析構認為是很有用的。這樣的資源的一個例子是,一個 web 容器會在集成測試任務前開始,并且在之后關閉,即使有些測試失敗。

你可以使用 Task.finalizedBy()?方法指定一個析構器任務。這個方法接受一個任務實例、 任務名稱或Task.dependsOn()所接受的任何其他輸入作為參數(shù)。

15.12. Summary 總結

如果你是從 Ant 轉(zhuǎn)過來的,像 Copy 這種增強的 Gradle 任務,看起來就像是一個 Ant target(目標)和一個 Ant task (任務)之間的混合物。實際上確實是這樣子。Gradle 沒有像 Ant 那樣對任務和目標進行分離。簡單的 Gradle 任務就像 Ant 的目標,而增強的 Gradle 任務還包括 Ant 任務方面的內(nèi)容。Gradle 的所有任務共享一個公共 API,您可以創(chuàng)建它們之間的依賴性。這樣的一個任務可能會比一個 Ant 任務更好配置。它充分利用了類型系統(tǒng),更具有表現(xiàn)力而且易于維護。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號