动态创建的Copy任务始终是UP-TO-DATE状态

8

我准备了一个非常简单的脚本,演示了我在使用Gradle 1.7时遇到的问题(由于一些插件尚未支持更新版本,因此需要坚持使用它)。

我正在尝试动态创建任务,每个任务对应项目目录中的一个文件。这很好用,但是我创建的任务只要将它们指定为“Copy”类型,就无法执行。

这是我的问题:build.gradle

file('templates').listFiles().each { File f ->

    // THIS LINE DOES NOT WORK
    task "myDist-${f.name}" (type: Copy) {

    // NEXT LINE WORKS
    //task "myDist-${f.name}" {
        doLast {
            println "MYDIST-" + f.name
        }
    }
}

task distAll(dependsOn: tasks.matching { Task task -> task.name.startsWith("myDist")}) {
    println "MYDISTALL"
}

defaultTasks 'distAll'

这样做可以避免在我简单调用gradle的默认任务时执行我的任务:

MYDISTALL
:myDist-template1 UP-TO-DATE
:myDist-template2 UP-TO-DATE
:distAll UP-TO-DATE

BUILD SUCCESSFUL

如果我从动态任务中移除类型Copy(取消上面的注释),我的任务将被执行:
MYDISTALL
:myDist-template1
MYDIST-template1
:myDist-template2
MYDIST-template2
:distAll

BUILD SUCCESSFUL

您需要在与build.gradle位于同一目录下创建一个名为templates的文件夹,并将几个空文件放到其中,以便运行测试。
根据调试输出:

跳过任务“:myDist-template1”,因为它没有源文件。

跳过任务“:myDist-template2”,因为它没有源文件。

那么我该如何指定源文件并使我的Copy任务执行? 我已经尝试添加了。
from( '/absolute/path/to/existing/file' ) {
    into 'myfolder'
}

针对任务主体,我尝试过使用inputs.source file('/my/existing/file')来指定任务,但没有成功。请问如何修改我的简单脚本,保留动态任务创建并保持任务类型为Copy

谢谢!

编辑: 好的,这样任务会被调用:

file('templates').listFiles().each { File f ->
    task "myDist-${f.name}" (type: Copy) {
        from f
        into 'dist'
        doLast {
            println "MYDIST-" + f.name
        }
    }
}

但是看起来我必须总是指定from/into。在doLast{}中这样做是不够的。

4个回答

12
一个Copy任务只有在有文件要复制时才会执行。告诉它要复制什么是配置任务的一部分,因此需要在“配置阶段”而不是“执行阶段”完成。这些是非常重要的概念,您可以在Gradle用户指南Gradle论坛上了解更多信息。 doFirstdoLast块在执行任务时作为其一部分执行。但两者都太晚告诉任务要复制什么: doFirst在主任务操作之前立即执行(在本例中为复制),但是(稍后)在“跳过”和“更新”的检查之后进行(这些检查基于任务的配置)。doLast在主任务操作之后执行,因此显然为时已晚。

我在配置时间告诉复制任务需要复制哪个文件夹(该文件夹在配置时间为空)。到执行时间,当任务开始复制文件夹时,另一个任务已经执行并将我需要的文件复制到源目录中。看起来工作正常。 - Adam

2
我认为以下Gradle用户指南引用最好地回答了我的问题:

其次,当任务被用作复制源(即作为from()的参数)时,copy()方法无法遵守任务依赖关系,因为它是一个方法而不是一个任务。因此,如果您将copy()方法用作任务操作的一部分,则必须明确声明所有输入和输出,以获得正确的行为。


该段落讨论了project.copy方法及其相对于Copy任务的缺点。它与您的问题无关。 - Peter Niederwieser
不确定您所说的“我将复制移出了doLast块”的确切含义。 - Peter Niederwieser
你的旧代码在doLast操作中配置任务,正如我所解释的那样,这太晚了。(这与project.copy方法无关。)现在你正在配置任务的配置阶段,这是正确的做法。 - Peter Niederwieser
对我来说,最重要的是一个复制任务必须定义输入源才能被调用(并且在 doLast 中使用 project.copy 方法也不会被调用,就像用户指南示例中所强调的那样)。 - Sergey Shcherbakov
doLast 中,project.copy 将总是被调用,但是你展示的代码中没有使用到 project.copyproject.copyCopy 任务的替代方案,你不会同时使用它们。 - Peter Niederwieser
显示剩余4条评论

2
阅读了关于gradle中“UP-TO-DATE”拷贝任务的大多数答案后,发现缺失的部分是“include”关键字。
task copy3rdPartyLibs(type: Copy) {
    from 'src/main/jni/libs/'
    into 'src/main/libs/armeabi/'
    include '**/*.so'
}

0
frominto作为doLast部分的一部分放置不起作用。工作任务定义的一个示例是:
task copyMyFile(type: Copy) {

    def dockerFile = 'src/main/docker/Dockerfile'
    def copyTo = 'build/docker'

    from dockerFile
    into copyTo

    doLast {
        println "Copied Docker file [$dockerFile] to [$copyTo]"
    }
}

这不是我预期的行为。 使用gradle 3.2.1


你是不是想说 def dockerFile = 'src/main/docker/Dockerfile' - Gabriel Kohen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接