From e67008c861311343c5dee831111762b16fdef348 Mon Sep 17 00:00:00 2001 From: bot-gradle Date: Thu, 1 Jul 2021 04:07:29 +0200 Subject: [PATCH] Merge pull request #17578 Let FileCollection ElementsProvider expose a changing execution time value when appropriate --- .../file/FileCollectionIntegrationTest.groovy | 162 ++++++++++++++++++ .../internal/file/AbstractFileCollection.java | 6 +- 2 files changed, 164 insertions(+), 4 deletions(-) diff --git a/subprojects/file-collections/src/integTest/groovy/org/gradle/api/file/FileCollectionIntegrationTest.groovy b/subprojects/file-collections/src/integTest/groovy/org/gradle/api/file/FileCollectionIntegrationTest.groovy index 07817d0080f2..dfc496e87636 100644 --- a/subprojects/file-collections/src/integTest/groovy/org/gradle/api/file/FileCollectionIntegrationTest.groovy +++ b/subprojects/file-collections/src/integTest/groovy/org/gradle/api/file/FileCollectionIntegrationTest.groovy @@ -312,4 +312,166 @@ class FileCollectionIntegrationTest extends AbstractIntegrationSpec implements T 'three.txt' ) } + + def "can filter a file collection using a closure hitting the filesystem"() { + given: + file("files/file0.txt") << "" + file("files/dir1/file1.txt") << "" + file("files/dir2/file2.txt") << "" + + and: + buildFile """ + def files = files("files/file0.txt", "files/dir1", "files/dir2", "files/dir3").filter { file -> + file.isDirectory() + } + tasks.register("sync", Sync) { + from files + into "output" + } + """ + + when: + run "sync" + + then: + file("output").assertHasDescendants("file1.txt", "file2.txt") + + when: + run "sync" + + then: + result.assertTaskSkipped(':sync') + + when: + file("files/dir2").deleteDir() + file("files/dir3/file3.txt") << "" + run "sync" + + then: + result.assertTaskNotSkipped(":sync") + file("output").assertHasDescendants("file1.txt", "file3.txt") + } + + @ToBeFixedForConfigurationCache(because = "provider assumed to be of fixed value but hits the filesystem") + def "can filter the elements of a file collection using a closure hitting the filesystem"() { + given: + file("files/file0.txt") << "" + file("files/dir1/file1.txt") << "" + file("files/dir2/file2.txt") << "" + + and: + buildFile """ + def files = files("files/file0.txt", "files/dir1", "files/dir2", "files/dir3").elements.map { + it.findAll { file -> + file.asFile.isDirectory() + } + } + tasks.register("sync", Sync) { + from files + into "output" + } + """ + + when: + run "sync" + + then: + file("output").assertHasDescendants("file1.txt", "file2.txt") + + when: + run "sync" + + then: + result.assertTaskSkipped(':sync') + + when: + file("files/dir2").deleteDir() + file("files/dir3/file3.txt") << "" + run "sync" + + then: + result.assertTaskNotSkipped(":sync") + file("output").assertHasDescendants("file1.txt", "file3.txt") + } + + @Issue("https://github.com/gradle/gradle/issues/17542") + def "can map task generated FC to a filtered List of Directory (#useCase)"() { + given: + buildFile """ + import static org.gradle.util.internal.TextUtil.normaliseFileSeparators + + abstract class Producer extends DefaultTask { + @OutputDirectory abstract DirectoryProperty getOutputClasses() + + Producer() { outputs.upToDateWhen { false } } // TODO doesn't matter, remove this + + @TaskAction void doStuff() { + File f = outputClasses.get().asFile + f.mkdirs() + new File(f, "some.txt") << "some text" + } + } + + TaskProvider prod = tasks.register("prod", Producer) { + outputClasses = layout.buildDirectory.dir("producerOutput") + } + + abstract class MyTask extends DefaultTask { + @Classpath abstract ConfigurableFileCollection getClasses() + @Inject abstract ProjectLayout getLayout() + @TaskAction void doStuff() { + def root = layout.projectDirectory.asFile + classes.files.each { file -> + println("CONSUMING ${'$'}{normaliseFileSeparators(root.relativePath(file))}") + } + } + } + + Provider> dirsFromFilteredFcMappedElements(FileCollection fc, Directory projectDir) { + def root = layout.projectDirectory.asFile + fc.filter { File f -> + f.isDirectory() + }.elements.map { + it.collect { fileSystemLocation -> + projectDir.dir(fileSystemLocation.asFile.absolutePath) + } + } + } + + Provider> dirsFromFcElementsSetFiltered(FileCollection fc, Directory projectDir) { + fc.elements.map { + it.findAll { FileSystemLocation fsl -> + fsl.asFile.isDirectory() + }.collect { fileSystemLocation -> + projectDir.dir(fileSystemLocation.asFile.absolutePath) + } + } + } + + FileCollection myFc = project.files(prod.map { it.outputClasses }) + + tasks.register("myTask", MyTask.class) { + classes.from( + files(${methodName}(myFc, project.layout.buildDirectory.get())) + ) + } + """ + + when: + run "myTask" + + then: + outputContains("CONSUMING build/producerOutput") + + when: + run "myTask" + + then: + outputContains("CONSUMING build/producerOutput") + + where: + methodName | useCase + "dirsFromFilteredFcMappedElements" | "dirs from filtered FC elements mapped" + "dirsFromFcElementsSetFiltered" | "dirs from FC elements set filtered" + } } diff --git a/subprojects/file-collections/src/main/java/org/gradle/api/internal/file/AbstractFileCollection.java b/subprojects/file-collections/src/main/java/org/gradle/api/internal/file/AbstractFileCollection.java index b20882547e30..9ec9ac31c89d 100644 --- a/subprojects/file-collections/src/main/java/org/gradle/api/internal/file/AbstractFileCollection.java +++ b/subprojects/file-collections/src/main/java/org/gradle/api/internal/file/AbstractFileCollection.java @@ -366,12 +366,10 @@ public void visitProducerTasks(Action visitor) { @Override public ExecutionTimeValue> calculateExecutionTimeValue() { - ExecutionTimeValue> value = ExecutionTimeValue.fixedValue(get()); if (contentsAreBuiltByTask()) { - return value.withChangingContent(); - } else { - return value; + return ExecutionTimeValue.changingValue(this); } + return ExecutionTimeValue.fixedValue(get()); } private boolean contentsAreBuiltByTask() {