Gradle 1.12 翻譯——第十六章. 使用文件

第十六章. 使用文件

大多數構建工做都要使用到文件。Gradle 添加了一些概念和 API 來幫助您實現這一目標。html

16.1. 定位文件

你可使用Project.file()方法來找到一個相對於項目目錄的文件 。java

示例 16.1. 查找文件web

build.gradleexpress

// Using a relative pathFile configFile = file('src/config.xml')// Using an absolute pathconfigFile = file(configFile.absolutePath)// Using a File object with a relative pathconfigFile = file(new File('src/config.xml'))

您能夠把任何對象傳遞給file()方法,而它將嘗試將其轉換爲一個絕對路徑的File對象。一般狀況下,你會傳給它一個StringFile的實例。而所提供的這個對象的tostring()方法的值會做爲文件路徑。若是這個路徑是一個絕對路徑,它會用於構構一個File實例。不然,會經過先計算所提供的路徑相對於項目目錄的相對路徑來構造File實例。這個file ()方法也能夠識別URL,例如是file:/some/path.xmlapache

這是把一些用戶提供的值轉換爲一個相對路徑的File對象的有用方法。因爲file()方法老是去計算所提供的路徑相對於項目目錄的路徑,最好是使用new File(somePath),由於它是一個固定的路徑,而不會由於用戶運行Gradle的具體工做目錄而改變。api

16.2..文件集合

一個文件集合只是表示一組文件。它經過FileCollection接口來表示。Gradle API 中的許多對象都實現了此接口。好比,依賴配置 就實現了 FileCollection 這一接口。數組

使用Project.files()方法是獲取一個FileCollection實例的其中一個方法。你能夠向這個方法傳入任意個對象,而它們會被轉換爲一組 File 對象。這個Files()方法接受任何類型的對象做爲其參數。根據16.1 章節 「定位文件」裏對file()方法的描述,它的結果會被計算爲相對於項目目錄的相對路徑。你也能夠將集合,迭代變量,map和數組傳遞給files()方法。它們會被展開,而且內容會轉換爲 File 實例。閉包

示例 16.2. 建立一個文件集合app

build.gradlewebapp

FileCollection collection = files('src/file1.txt', new File('src/file2.txt'), ['src/file3.txt', 'src/file4.txt'])

一個文件集合是可迭代的,而且可使用as操做符轉換爲其餘類型的對象集合。您還可使用+運算符把兩個文件集合相加,或使用-運算符減去一個文件集合。這裏是一些使用文件集合的例子。

示例 16.3. 使用一個文件集合

build.gradle

// Iterate over the files in the collectioncollection.each {File file ->
    println file.name
}// Convert the collection to various typesSet set = collection.files
Set set2 = collection as Set
List list = collection as List
String path = collection.asPath
File file = collection.singleFile
File file2 = collection as File// Add and subtract collectionsdef union = collection + files('src/file3.txt')
def different = collection - files('src/file3.txt')

你也能夠向files()方法傳一個閉包或一個Callable實例。它會在查詢集合內容,而且它的返回值被轉換爲一組文件實例時被調用。這個閉包或Callable實例的返回值能夠是files()方法所支持的任何類型的對象。這是 「實現」 FileCollection接口的簡單方法。

示例 16.4. 實現一個文件集合

build.gradle

task list << {
    File srcDir    // Create a file collection using a closure
    collection = files { srcDir.listFiles() }

    srcDir = file('src')
    println "Contents of $srcDir.name"
    collection.collect { relativePath(it) }.sort().each { println it }

    srcDir = file('src2')
    println "Contents of $srcDir.name"
    collection.collect { relativePath(it) }.sort().each { println it }
}

gradle -q list的輸出結果

> gradle -q list
Contents of src
src/dir1
src/file1.txt
Contents of src2
src2/dir1
src2/dir2

你能夠向files()傳入一些其餘類型的對象:

  • FileCollection

  • 它們會被展開,而且內容會被包含在文件集合內。

  • Task

  • 任務的輸出文件會被包含在文件集合內。

  • TaskOutputs

  • TaskOutputs 的輸出文件會被包含在文件集合內。

要注意的一個地方是,一個文件集合的內容是緩計算的,它只在須要的時候才計算。這意味着您能夠,好比建立一個FileCollection 對象而裏面的文件會在之後才建立,比方說在一些任務中才建立。

16.3. 文件樹

文件樹是按層次結構排序的文件集合。例如,文件樹可能表示一個目錄樹或 ZIP 文件的內容。它經過FileTree接口表示。FileTree接口繼承自FileCollection,因此你能夠用對待文件集合同樣的方式來對待文件樹。Gradle 中的幾個對象都實現了FileTree接口,例如source sets

使用Project.fileTree()方法是獲取一個FileTree實例的其中一種方法。它將定義一個基目錄建立FileTree對象,並能夠選擇加上一些 Ant風格的包含與排除模式。

示例 16.5. 建立一個文件樹

build.gradle

// Create a file tree with a base directoryFileTree tree = fileTree(dir: 'src/main')// Add include and exclude patterns to the treetree.include '**/*.java'tree.exclude '**/Abstract*'// Create a tree using pathtree = fileTree('src').include('**/*.java')// Create a tree using closuretree = fileTree('src') {
    include '**/*.java'}// Create a tree using a maptree = fileTree(dir: 'src', include: '**/*.java')
tree = fileTree(dir: 'src', includes: ['**/*.java', '**/*.xml'])
tree = fileTree(dir: 'src', include: '**/*.java', exclude: '**/*test*/**')

你能夠像使用一個文件集合的方式同樣來使用一個文件樹。你也可使用Ant風格的模式來訪問文件樹的內容或選擇一個子樹:

示例 16.6. 使用文件樹

build.gradle

// Iterate over the contents of a treetree.each {File file ->
    println file
}// Filter a treeFileTree filtered = tree.matching {
    include 'org/gradle/api/**'}// Add trees togetherFileTree sum = tree + fileTree(dir: 'src/test')// Visit the elements of the treetree.visit {element ->
    println "$element.relativePath => $element.file"}

16.4. 使用歸檔文件的內容做爲文件樹

您可使用檔案的內容,如 ZIP 或者 TAR 文件,做爲一個文件樹。你能夠經過使用Project.zipTree()Project.tarTree()方法來實現這一過程。這些方法返回一個FileTree實例,您能夠像使用任何其餘文件樹或文件集合同樣使用它。例如,您能夠用它來經過複製內容擴大歸檔,或把一些檔案合併到另外一個歸檔文件中。

示例 16.7. 使用歸檔文件做爲文件樹

build.gradle

// Create a ZIP file tree using pathFileTree zip = zipTree('someFile.zip')// Create a TAR file tree using pathFileTree tar = tarTree('someFile.tar')//tar tree attempts to guess the compression based on the file extension//however if you must specify the compression explicitly you can:FileTree someTar = tarTree(resources.gzip('someTar.ext'))

16.5. 指定一組輸入文件

Gradle 中的許多對象都有一個接受一組輸入文件的屬性。例如, JavaCompile任務有一個source屬性,定義了要編譯的源代碼文件。你可使用上面所示的files()方法所支持的任意類型的對象設置此屬性。這意味着您能夠經過如FileString、 集合、 FileCollection對象,或甚至是一個閉包來設置此屬性。這裏有一些例子:

示例 16.8. 指定一組文件

build.gradle

// Use a File object to specify the source directorycompile {
    source = file('src/main/java')
}// Use a String path to specify the source directorycompile {
    source = 'src/main/java'}// Use a collection to specify multiple source directoriescompile {
    source = ['src/main/java', '../shared/java']
}// Use a FileCollection (or FileTree in this case) to specify the source filescompile {
    source = fileTree(dir: 'src/main/java').matching { include 'org/gradle/api/**' }
}// Using a closure to specify the source files.compile {
    source = {        // Use the contents of each zip file in the src dir
        file('src').listFiles().findAll {it.name.endsWith('.zip')}.collect { zipTree(it) }
    }
}

一般狀況下,有一個與屬性相同名稱的方法,能夠追加這個文件集合。再者,這個方法接受files()方法所支持的任何類型的參數。

示例 16.9. 指定一組文件

build.gradle

compile {    // Add some source directories use String paths
    source 'src/main/java', 'src/main/groovy'

    // Add a source directory using a File object
    source file('../shared/java')    // Add some source directories using a closure
    source { file('src/test/').listFiles() }
}

16.6. 複製文件

你可使用Copy任務來複制文件。複製任務很是靈活,並容許您進行,好比篩選要複製的文件的內容,或映射文件的名稱。

若要使用Copy任務,您必須提供用於複製的源文件和目標目錄。您還能夠在複製文件的時候指定如何轉換文件。你可使用一個複製規範來作這些。一個複製規範經過 CopySpec 接口來表示。Copy任務實現了此接口。你可使用CopySpec.from()方法指定源文件,使用CopySpec.into()方法使用目標目錄。

示例 16.10. 使用copy任務複製文件

build.gradle

task copyTask(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'}

from()方法接受和files()方法同樣的任何參數。當參數解析爲一個目錄時,該目錄下的全部文件(不包含目錄自己) 都會遞歸複製到目標目錄。當參數解析爲一個文件時,該文件會複製到目標目錄中。當參數解析爲一個不存在的文件時,參數會被忽略。若是參數是一個任務,那麼任務的輸出文件 (即該任務建立的文件)會被複制,而且該任務會自動添加爲Copy任務的依賴項。into()方法接受和files()方法同樣的任何參數。這裏是另外一個示例:

示例 16.11. 指定複製任務的源文件和目標目錄

build.gradle

task anotherCopyTask(type: Copy) {    // Copy everything under src/main/webapp
    from 'src/main/webapp'
    // Copy a single file
    from 'src/staging/index.html'
    // Copy the output of a task
    from copyTask    // Copy the output of a task using Task outputs explicitly.
    from copyTaskWithPatterns.outputs    // Copy the contents of a Zip file
    from zipTree('src/main/assets.zip')    // Determine the destination directory later
    into { getDestDir() }
}

您可使用 Ant 風格的包含或排除模式,或使用一個閉包,來選擇要複製的文件:

示例 16.12. 選擇要複製的文件

build.gradle

task copyTaskWithPatterns(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
    include '**/*.html'
    include '**/*.jsp'
    exclude { details -> details.file.name.endsWith('.html') && details.file.text.contains('staging') }
}

此外,你也可使用Project.copy()方法來複制文件。它是與任務同樣的工做方式,儘管它有一些主要的限制。首先, copy()不能進行增量操做(見15.9章節,"跳過處於最新狀態的任務")。

示例 16.13. 使用沒有最新狀態檢查的 copy() 方法複製文件

build.gradle

task copyMethod << {
    copy {
        from 'src/main/webapp'
        into 'build/explodedWar'
        include '**/*.html'
        include '**/*.jsp'
    }
}

第二,當一個任務用做複製源(即做爲 from() 的參數)的時候,copy()方法不能創建任務依賴性,由於它是一個方法,而不是一個任務。所以,若是您在任務的action裏面使用copy()方法,必須顯式聲明全部的輸入和輸出以獲得正確的行爲。

示例 16.14. 使用有最新狀態檢查的 copy() 方法複製文件

build.gradle

task copyMethodWithExplicitDependencies{
    inputs.file copyTask // up-to-date check for inputs, plus add copyTask as dependency
    outputs.dir 'some-dir' // up-to-date check for outputs
    doLast{
        copy {            // Copy the output of copyTask
            from copyTask
            into 'some-dir'
        }
    }
}

在可能的狀況下,最好是使用Copy任務,由於它支持增量構建和任務依賴關係推理,而不須要你額外付出。copy()方法能夠做爲一個任務執行的部分來複制文件。即,這個copy()方法旨在用於自定義任務 (見第 57 章,編寫自定義任務類)中,須要文件複製做爲其一部分功能的時候。在這種狀況下,自定義任務應充分聲明與複製操做有關的輸入/輸出。

16.6.1. 重命名文件

示例 16.15. 重命名複製的文件

build.gradle

task rename(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
    // Use a closure to map the file name
    rename { String fileName ->
        fileName.replace('-staging-', '')
    }    // Use a regular expression to map the file name
    rename '(.+)-staging-(.+)', '$1$2'
    rename(/(.+)-staging-(.+)/, '$1$2')
}

16.6. 過濾文件

示例 16.16. 過濾要複製的文件

build.gradle

import org.apache.tools.ant.filters.FixCrLfFilterimport org.apache.tools.ant.filters.ReplaceTokens

task filter(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
    // Substitute property references in files
    expand(copyright: '2009', version: '2.3.1')
    expand(project.properties)    // Use some of the filters provided by Ant
    filter(FixCrLfFilter)
    filter(ReplaceTokens, tokens: [copyright: '2009', version: '2.3.1'])    // Use a closure to filter each line
    filter { String line ->        "[$line]"
    }
}

16.6.3. 使用CopySpec

複製規範用來組織一個層次結構。一個複製規範繼承其目標路徑,包含模式,排除模式,複製操做,名稱映射和過濾器。

示例 16.17. 嵌套的複製規範

build.gradle

task nestedSpecs(type: Copy) {
    into 'build/explodedWar'
    exclude '**/*staging*'
    from('src/dist') {
        include '**/*.html'
    }
    into('libs') {
        from configurations.runtime
    }
}

16.7. 使用Sync任務

Sync任務繼承了Copy任務。當它執行時,它會將源文件複製到目標目錄中,而後從目標目錄移除全部不是它複製的文件。這能夠用來作一些事情,好比安裝你的應用程序、 建立你的歸檔文件的exploded副本,或維護項目的依賴項的副本。

這裏是一個例子,維護在build/libs目錄中的項目運行時依賴的副本。

示例 16.18. 使用同步任務複製依賴項

build.gradle

task libs(type: Sync) {
    from configurations.runtime
    into "$buildDir/libs"}

16.8. 建立歸檔文件

一個項目能夠有你所想要的同樣多的 JAR 文件。您也能夠將WAR、 ZIP 和TAG文件添加到您的項目。使用各類歸檔任務能夠建立如下的歸檔文件: ZipTarJarWar, and Ear. 他們的工做方式都同樣,因此讓咱們看看如何建立一個 ZIP 文件。

示例 16.19. 建立一個 ZIP 文件

build.gradle

apply plugin: 'java'task zip(type: Zip) {
    from 'src/dist'
    into('libs') {
        from configurations.runtime
    }
}

爲何要用 Java 插件?

Java 插件對歸檔任務添加了一些默認值。若是你願意,使用歸檔任務時能夠不須要Java插件。您須要提供一些值給附加的屬性。

歸檔任務與Copy任務的工做方式同樣,而且實現了相同的CopySpec接口。像使用Copy任務同樣,你須要使用from() 的方法指定輸入的文件,並能夠選擇是否經過 into() 方法指定最終在存檔中的位置。您能夠經過一個複製規範來篩選文件的內容、 重命名文件和進行其餘你能夠作的事情。

16.8.1. 歸檔命名

生成的歸檔的默認名稱是projectName-version.type。舉個例子:

示例 16.20. 建立 ZIP 文件

build.gradle

apply plugin: 'java'version = 1.0task myZip(type: Zip) {
    from 'somedir'}

println myZip.archiveName
println relativePath(myZip.destinationDir)
println relativePath(myZip.archivePath)

gradle -q myZip 的輸出結果

> gradle -q myZip
zipProject-1.0.zip
build/distributions
build/distributions/zipProject-1.0.zip

它添加了一個名稱爲myZipZIP歸檔任務,產生 ZIP 文件 zipProject 1.0.zip。區分歸檔任務的名稱和歸檔任務生成的歸檔文件的名稱是很重要的。歸檔的默認名稱能夠經過項目屬性 archivesBaseName 來更改。還能夠在之後的任什麼時候候更改歸檔文件的名稱。

這裏有不少你能夠在歸檔任務中設置的屬性。它們在如下的表 16.1,"存檔任務-命名屬性"中列出。你能夠,比方說,更改歸檔文件的名稱:

示例 16.21. 配置歸檔任務-自定義歸檔名稱

build.gradle

apply plugin: 'java'version = 1.0task myZip(type: Zip) {
    from 'somedir'
    baseName = 'customName'}

println myZip.archiveName

gradle -q myZip 的輸出結果

> gradle -q myZip
customName-1.0.zip

您能夠進一步自定義存檔名稱:

示例 16.22. 配置歸檔任務 - appendix & classifier

build.gradle

apply plugin: 'java'archivesBaseName = 'gradle'version = 1.0task myZip(type: Zip) {
    appendix = 'wrapper'
    classifier = 'src'
    from 'somedir'}

println myZip.archiveName

gradle -q myZip 的輸出結果

> gradle -q myZip
gradle-wrapper-1.0-src.zip

表 16.1. 歸檔任務-命名屬性

屬性名稱 類型 默認值 描述
archiveName String baseName-appendix-version-classifier.extension

若是這些屬性中的任何一個爲空,那後面的-不會被添加到該名稱中。

生成的歸檔文件的基本文件名
archivePath File destinationDir/archiveName 生成的歸檔文件的絕對路徑。
destinationDir File 依賴於歸檔類型。JAR包和 WAR包會生成到 project.buildDir/libraries中。ZIP文件和 TAR文件會生成到project.buildDir/distributions中。 存放生成的歸檔文件的目錄
baseName String project.name 歸檔文件的名稱中的基本名稱部分。
appendix String null 歸檔文件的名稱中的附錄部分。
version String project.version 歸檔文件的名稱中的版本部分。
classifier String null 歸檔文件的名稱中的分類部分。
extension String 依賴於歸檔的類型,用於TAR文件,能夠是如下壓縮類型: zipjarwartartgz or tbz2. 歸檔文件的名稱中的擴展名稱部分。

16.8.2. 共享多個歸檔之間的內容

你可使用Project.copySpec()方法在歸檔之間共享內容。

你常常會想要發佈一個歸檔文件,這樣就可從另外一個項目中使用它。這一過程在第 51章,發佈文件中會講到。

相關文章
相關標籤/搜索