跳過 up-to-date 的任務

2018-07-01 16:14 更新

如果你正在使用一些附加的任務, 比如通過 Java 插件加入的任務, 你可能會注意到 Gradle 會跳過一些任務, 這些任務后面會標注 up-to-date. 代表這個任務已經運行過了或者說是最新的狀態(tài), 不再需要產生一次相同的輸出. 不僅僅是這些內建任務, 其實你在運行自己的任務時, 也會碰到這種情況.

1. 聲明一個任務的輸入和輸出

讓我們先看一個例子. 這里我們的任務會根據一個 XML 文件生成好幾個輸出文件. 讓我們運行這個任務 2 次.

例子 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"
        }
    }
}

gradle transform 的輸出

> gradle transform
:transform
Transforming source file.

gradle transform 的輸出

> gradle transform
:transform
Transforming source file.

這里 Gradle 執(zhí)行了這個任務兩次, 即使什么都沒有改變, 它也沒有跳過這個任務. 這個例子里的任務, 它的行為是通過閉包定義的. Gradle 并不知道閉包會做什么, 也并不能自動指出是否這個任務是 up-to-date. 為了使用 Gradle 的 up-to-date 檢測, 你需要定義任務的輸入和輸出.

每個任務都有輸入和輸出屬性, 你需要使用這些屬性來聲明任務的輸入和輸出. 下面的例子中, 我們將聲明 XML 文件作為輸入, 并且把輸出放在一個指定的目錄. 讓我們運行這個任務 2 次.

例子 15.24. 聲明任務的輸入和輸出

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

gradle transform 的輸出

> gradle transform
:transform
Transforming source file.

gradle transform 的輸出

> gradle transform
:transform UP-TO-DATE

現在, Gradle 就能夠檢測出任務是否是 up-to-date 狀態(tài).

任務的輸入屬性是 TaskInputs 類型. 任務的輸出屬性是 TaskOutputs 類型.

一個任務如果沒有定義輸出的話, 那么它永遠都沒用辦法判斷 up-to-date. 對于某些場景, 比如一個任務的輸出不是文件, 或者更復雜的場景, TaskOutputs.upToDateWhen()) 方法會計算任務的輸出是否應被視為最新.

總而言之, 如果一個任務只定義了輸出, 如果輸出不變的話, 它就會被視為 up-to-date.

2. 它是如何工作的?

當一個任務是首次執(zhí)行時, Gradle 會取一個輸入的快照 (snapshot). 該快照包含組輸入文件和每個文件的內容的散列. 然后當 Gradle 執(zhí)行任務時, 如果任務成功完成,Gradle 會獲得一個輸出的快照. 該快照包含輸出文件和每個文件的內容的散列. Gradle 會保留這兩個快照用來在該任務的下一次執(zhí)行時進行判斷.

之后, 每次在任務執(zhí)行之前, Gradle 都會為輸入和輸出取一個新的快照, 如果這個快照和之前的快照一樣, Gradle 就會假定這個任務已經是最新的 (up-to-date) 并且跳過任務, 反之亦然.

需要注意的是, 如果一個任務有指定的輸出目錄, 自從該任務上次執(zhí)行以來被加入到該目錄的任務文件都會被忽略, 并且不會引起任務過時 (out of date). 這是因為不相關任務也許會共用同一個輸出目錄. 如果這并不是你所想要的情況, 可以考慮使用 TaskOutputs.upToDateWhen())


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號