跳過(guò) up-to-date 的任務(wù)

2018-07-01 16:14 更新

如果你正在使用一些附加的任務(wù), 比如通過(guò) Java 插件加入的任務(wù), 你可能會(huì)注意到 Gradle 會(huì)跳過(guò)一些任務(wù), 這些任務(wù)后面會(huì)標(biāo)注 up-to-date. 代表這個(gè)任務(wù)已經(jīng)運(yùn)行過(guò)了或者說(shuō)是最新的狀態(tài), 不再需要產(chǎn)生一次相同的輸出. 不僅僅是這些內(nèi)建任務(wù), 其實(shí)你在運(yùn)行自己的任務(wù)時(shí), 也會(huì)碰到這種情況.

1. 聲明一個(gè)任務(wù)的輸入和輸出

讓我們先看一個(gè)例子. 這里我們的任務(wù)會(huì)根據(jù)一個(gè) XML 文件生成好幾個(gè)輸出文件. 讓我們運(yùn)行這個(gè)任務(wù) 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í)行了這個(gè)任務(wù)兩次, 即使什么都沒(méi)有改變, 它也沒(méi)有跳過(guò)這個(gè)任務(wù). 這個(gè)例子里的任務(wù), 它的行為是通過(guò)閉包定義的. Gradle 并不知道閉包會(huì)做什么, 也并不能自動(dòng)指出是否這個(gè)任務(wù)是 up-to-date. 為了使用 Gradle 的 up-to-date 檢測(cè), 你需要定義任務(wù)的輸入和輸出.

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

例子 15.24. 聲明任務(wù)的輸入和輸出

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

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

任務(wù)的輸入屬性是 TaskInputs 類(lèi)型. 任務(wù)的輸出屬性是 TaskOutputs 類(lèi)型.

一個(gè)任務(wù)如果沒(méi)有定義輸出的話(huà), 那么它永遠(yuǎn)都沒(méi)用辦法判斷 up-to-date. 對(duì)于某些場(chǎng)景, 比如一個(gè)任務(wù)的輸出不是文件, 或者更復(fù)雜的場(chǎng)景, TaskOutputs.upToDateWhen()) 方法會(huì)計(jì)算任務(wù)的輸出是否應(yīng)被視為最新.

總而言之, 如果一個(gè)任務(wù)只定義了輸出, 如果輸出不變的話(huà), 它就會(huì)被視為 up-to-date.

2. 它是如何工作的?

當(dāng)一個(gè)任務(wù)是首次執(zhí)行時(shí), Gradle 會(huì)取一個(gè)輸入的快照 (snapshot). 該快照包含組輸入文件和每個(gè)文件的內(nèi)容的散列. 然后當(dāng) Gradle 執(zhí)行任務(wù)時(shí), 如果任務(wù)成功完成,Gradle 會(huì)獲得一個(gè)輸出的快照. 該快照包含輸出文件和每個(gè)文件的內(nèi)容的散列. Gradle 會(huì)保留這兩個(gè)快照用來(lái)在該任務(wù)的下一次執(zhí)行時(shí)進(jìn)行判斷.

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

需要注意的是, 如果一個(gè)任務(wù)有指定的輸出目錄, 自從該任務(wù)上次執(zhí)行以來(lái)被加入到該目錄的任務(wù)文件都會(huì)被忽略, 并且不會(huì)引起任務(wù)過(guò)時(shí) (out of date). 這是因?yàn)椴幌嚓P(guān)任務(wù)也許會(huì)共用同一個(gè)輸出目錄. 如果這并不是你所想要的情況, 可以考慮使用 TaskOutputs.upToDateWhen())


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)