为什么复制任务会在第一次构建时删除陈旧的输出?

Why copy task delete stale output on first build?

我有这个 kotlin gradle 构建脚本代表我的用例。 我正在使用 Gradle 6.7.

这是我的 kotlin gradle 构建文件:

plugins {
    java
}

tasks.register("createFile"){

    doLast{
        projectDir.resolve("tmp.txt").createNewFile()
        projectDir.resolve("tmp.txt").writeText("tmp")
    }

    dependsOn("assemble")
}

tasks.register("createExecFile", Exec::class){

    workingDir(buildDir)
    commandLine("cmd", "/c", "mkdir destdir\subdir")

    dependsOn("createFile")
}

tasks.register("copyBug", Copy::class){

    from(projectDir.resolve("tmp.txt"))
    into(buildDir.resolve("destDir"))

    dependsOn("createExecFile")
}

现在运行gradle copyBug -i.

第一次这会给你这个输出:

> Task :copyBug Deleting stale output file: E:\repo\BugCOpy\build\destDir Caching disabled for task ':copyBug' because:   Build cache is disabled Task ':copyBug' is not up-to-date because:   No history is available.

复制任务删除了前一个执行任务创建的文件。

现在,如果您重新运行此命令,复制任务将不会删除陈旧文件。

那些陈旧的文件是什么?我怎样才能防止这些文件被删除?我的第一个构建与其他构建不同。

我应该提交错误吗?

在您的 createExecFile 任务中,您无需告知 Gradle 就可以生成输出文件。所以 Gradle 不知道这个任务和 copyBug 任务使用相同的输出目录。相反,Gradle 认为 copyBug 是唯一在 build/destdir 下产生输出的任务,因此假设该目录中的任何现有文件不应该存在(并且“陈旧”)是更安全的.

解决方案是告诉 Gradle 你的 createExecFile 任务输出到 build/destdir:

tasks.register("createExecFile", Exec::class) {

    workingDir(buildDir)
    commandLine("cmd", "/c", "mkdir destdir\subdir")

    // tell Gradle about the output directory
    outputs.dir(buildDir.resolve("destdir"))

    dependsOn("createFile")
}

如果您需要更多背景信息,请参阅 this release notes section for why this behavior was introduced and this explanation to a very similar issue

我的构建过程看起来像

  1. 运行 gradle(第 1 部分)
  2. 做点别的事
  3. 运行 gradle(第 2 部分)

令我恼火的是 运行ning gradle 在第 3 步中不仅会向输出目录添加一些文件,而且会首先删除该文件夹作为陈旧文件夹。连加

outputs.dir(...)

没有阻止 Gradle 将其删除。计算我的任务的输入和输出看起来太乏味了,但幸运的是我找到了一种方法告诉 Gradle 不要执行任何最新的跟踪:

Example 37. Ignoring up-to-date checks 提及要添加

doNotTrackState("Comment why this is needed")

这最终帮助我保留了构建步骤 1 中的文件。