Gradle任务:如何等待文件操作完成

Gradle task: how to wait for the file operation to complete

这是我正在尝试做的事情:

  1. 将存档 (zip) 从构建脚本依赖项复制到临时目录
  2. 将存档解压缩到 build
  3. 中的另一个目录

这是复制存档的任务(有效)

task copyTpcds(type: Copy) {  
    file('build/zip').mkdirs()
    from buildscript.configurations.classpath
    include 'tpcds*'
    into 'build/zip'
}

以及解压缩然后删除存档的任务

task extractTpcds(type: Copy) {  
    def names = new FileNameFinder().getFileNames('build/zip', 'tpcds*')
    def outDir = file('build/cmd/tpcds')
    outDir.mkdirs() // make sure the directory exists
    from zipTree(file(names[0])) // generates error when 
    into outDir
    // now remove copied zip file
    //zipFile.delete() // deletes file before the extractions completes?
}

以下是几种情况:

  1. 如果我将两个任务都放入 build.gradle 并尝试 运行 任何东西,即使只是 gradle tasks 然后我会收到此错误:来自任务中的此代码的 Neither path nor baseDir may be null or empty string. path='null' basedir='C:\dev\code\td\pdo\tpcds-tpg' #2:file(names[0])
  2. 如果我在第二个任务中注释掉代码,第一个任务将 运行 并将 zip 文件复制到 build/zip
  3. 现在我可以在第二个任务中取消注释代码(删除除外)并执行 gradle extractTpcds 它将 运行 并提取存档

所以在我看来

  1. 无论执行哪个任务,都会对所有任务评估文件操作
  2. 如果我有一个复制文件的代码和一些试图对正在复制的文件进行操作的后续代码,那么该代码将不会等待复制过程完成并且会失败,因为文件还不存在

我不知道如何处理这个问题,非常感谢你的建议

像这样应该可以,但为什么需要删除 zip?使用 dependsOn 链接任务意味着您只需要 运行 第二个任务并且 copyTpcds 将自动 运行 除非输入或输出已更改(删除)

task extractTpcds(type: Copy) {

    dependsOn(copyTpcds) //make this execute after

    def names = new FileNameFinder().getFileNames('build/zip', 'tpcds*')
    def outDir = file('build/cmd/tpcds')
    outDir.mkdirs() // make sure the directory exists
    from zipTree(file(names[0])) // generates error when 
    into outDir
    // now remove copied zip file
    doLast { zipFile.delete() }// deletes file after the extractions completes
}

以下对我有用,使用 Gradle 2.12(并假设 zip 文件位于 files):

buildscript {
    configurations {
        classpath
    }

    dependencies {
        classpath files("files/tpcds.zip")
    }
}

def copyFiles = { ->
    ant.mkdir(dir: "build/zip")
    buildscript.configurations.classpath.each { def thisFile ->
        if (thisFile.name ==~ /tpcds.*/) {
            ant.copy(file: thisFile.absolutePath, todir: "build/zip")
        }
    }
}

tasks.whenTaskAdded { task ->
    if (task.name == "extractTpcds") {
        copyFiles()
    }
}

task copyTpcds << {  
    copyFiles()
}

task extractTpcds(type: Copy) {  
    def names = new FileNameFinder().getFileNames('build/zip', 'tpcds*')
    def outDir = file('build/cmd/tpcds')
    outDir.mkdirs() // make sure the directory exists
    from zipTree(file(names[0])) // generates error when 
    into outDir
    // now remove copied zip file
    //zipFile.delete() // deletes file before the extractions completes?
}

原件的一个问题涉及与 ICE 规则的阻抗不匹配:初始化阶段、配置阶段和执行阶段。特别是复制任务的规范在配置阶段;通常,在执行阶段强制执行任务依赖性(例如 dependsOn)。 extractTpcds 任务在 配置阶段 期间依赖于其他代码。

在我的例子中,有2种情况:

  • gradle copyTpcds 将在执行阶段调用 copyFiles 方法。 << 表示 "do this stuff last [during the Execution phase]".
  • gradle tasks 将在配置阶段触发 whenTaskAdded 中的代码,并调用 copyFiles。同样对于 gradle extractTpcds

另一种方法是在两个任务中都使用 AntBuilder,并完全避免 Type: Copy,如下所示:

buildscript {
    configurations {
        classpath
    }
    dependencies {
        classpath files("files/tpcds.zip")
    }
}

task copyTpcds << {  
    ant.mkdir(dir: "build/zip")
    buildscript.configurations.classpath.each { def thisFile ->
        if (thisFile.name ==~ /tpcds.*/) {
            ant.copy(file: thisFile.absolutePath, todir: "build/zip")
        }
    }
}

task extractTpcds(dependsOn: 'copyTpcds') << {  
    def outDir = "build/cmd/tpcds"
    ant.mkdir(dir: outDir)
    def names = new FileNameFinder().getFileNames('build/zip', 'tpcds*')
    names.eachWithIndex { zipFile, index ->
        if (index == 0) {
            ant.unzip(src: zipFile, dest: outDir)
        }
    }
}