【问题标题】:Gradle task: how to wait for the file operation to completeGradle任务:如何等待文件操作完成
【发布时间】:2016-05-14 02:21:33
【问题描述】:

这就是我想要做的:

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

这是复制档案的任务(作品)

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. 如果我有一个复制文件的代码以及一些尝试对正在复制的文件进行操作的后续代码,那么该代码将不会等待复制过程完成并且会因为文件不存在而失败

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

【问题讨论】:

    标签: file-io gradle groovy unzip


    【解决方案1】:

    以下内容适用于我,使用 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 规则的阻抗不匹配:初始化阶段、配置阶段和执行阶段。特别是Copy任务的规范处于Configuration阶段;通常,在执行阶段会强制执行任务相关性(例如dependsOn)。 extractTpcds 任务在配置阶段依赖于其他代码。

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

    • gradle copyTpcds 将在执行阶段调用copyFiles 方法。 &lt;&lt; 的意思是“最后[在执行阶段]做这些事情”。
    • 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)
            }
        }
    }
    

    【讨论】:

    • 这很好用,谢谢迈克尔!为了补全,可以举个使用Ant解压的例子吗?
    • 好的,我已经添加了第二个示例……请注意,它会解压缩第一个 zip 文件,但可以根据需要轻松更改。
    【解决方案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
    }
    

    【讨论】:

    • 这不起作用。就像我说的 - 无论您尝试运行包括内联在内的所有变量的任务如何,例如names[0] 会立即在整个 build.gradle 中进行评估。所以要强调一点,如果我尝试运行看似无关的任务,例如 gradle tasksgradle clean gradle 将退出 Neither path nor baseDir may be null or empty string. path='null' 错误
    • 除非我的示例中 build/zip 目录中存在 zip 文件
    • Michael Ester 解释了为什么这在他的回答中不起作用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多