diff --git a/src/main/groovy/com/google/protobuf/gradle/ProtobufExtract.groovy b/src/main/groovy/com/google/protobuf/gradle/ProtobufExtract.groovy index 514900e7..03843bb4 100644 --- a/src/main/groovy/com/google/protobuf/gradle/ProtobufExtract.groovy +++ b/src/main/groovy/com/google/protobuf/gradle/ProtobufExtract.groovy @@ -35,11 +35,9 @@ import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DuplicatesStrategy import org.gradle.api.file.FileCollection -import org.gradle.api.file.FileSystemLocation import org.gradle.api.file.FileTree import org.gradle.api.logging.Logger import org.gradle.api.model.ObjectFactory -import org.gradle.api.provider.ProviderFactory import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Internal import org.gradle.api.tasks.OutputDirectory @@ -71,6 +69,13 @@ abstract class ProtobufExtract extends DefaultTask { @Internal public abstract ConfigurableFileCollection getInputFiles() + /** + * A dummy task dependency to delay provider calculation for input proto files to execution time + * even with configuration cache enabled. + */ + @Internal + abstract ConfigurableFileCollection getDummyTaskDependency() + /** * Inputs for this task containing only proto files, which is enough for up-to-date checks. * Add inputs to inputFiles. Uses relative path sensitivity as directory layout changes impact output. @@ -99,9 +104,6 @@ abstract class ProtobufExtract extends DefaultTask { @Inject protected abstract ObjectFactory getObjectFactory() - @Inject - protected abstract ProviderFactory getProviderFactory() - private ArchiveActionFacade instantiateArchiveActionFacade() { if (GradleVersion.current() >= GradleVersion.version("6.0")) { // Use object factory to instantiate as that will inject the necessary service. @@ -117,14 +119,17 @@ abstract class ProtobufExtract extends DefaultTask { // Provider.map seems broken for excluded tasks. Add inputFiles with all contents excluded for // the dependency it provides, but then provide the files we actually care about in our own // provider. https://github.com/google/protobuf-gradle-plugin/issues/550 - PatternSet protoFilter = new PatternSet().include("**/*.proto") + // Additionally depend on a dummy task for the own provider so that it is executed at + // execution time even with configuration cache enabled. + // https://github.com/google/protobuf-gradle-plugin/issues/711 + def inputFiles = inputFiles return objectFactory.fileCollection() .from(inputFiles.filter { false }) - .from( - inputFiles.getElements().map { elements -> + .from(dummyTaskDependency.elements.map { unused -> + Set files = inputFiles.files + PatternSet protoFilter = new PatternSet().include("**/*.proto") Set protoInputs = [] as Set - for (FileSystemLocation e : elements) { - File file = e.asFile + for (File file : files) { if (file.isDirectory()) { protoInputs.add(file) } else if (file.path.endsWith('.proto')) { @@ -151,7 +156,7 @@ abstract class ProtobufExtract extends DefaultTask { || file.path.endsWith('.tgz')) { protoInputs.add(archiveFacade.tarTree(file.path).matching(protoFilter)) } else { - logger.debug "Skipping unsupported file type (${file.path});" + + logger.debug "Skipping unsupported file type (${file.path}); " + "handles only jar, tar, tar.gz, tar.bz2 & tgz" } } diff --git a/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy b/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy index ac693d72..0c68bd2b 100644 --- a/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy +++ b/src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy @@ -44,6 +44,7 @@ import org.gradle.api.GradleException import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.type.ArtifactTypeDefinition import org.gradle.api.attributes.LibraryElements @@ -129,12 +130,13 @@ class ProtobufPlugin implements Plugin { // extract included protos from {@code variant.compileConfiguration} // of each variant. Collection postConfigure = [] + Provider dummyTask = project.tasks.register("dummy") if (isAndroid) { project.android.sourceSets.configureEach { sourceSet -> ProtoSourceSet protoSourceSet = protobufExtension.sourceSets.create(sourceSet.name) addSourceSetExtension(sourceSet, protoSourceSet) Configuration protobufConfig = createProtobufConfiguration(protoSourceSet) - setupExtractProtosTask(protoSourceSet, protobufConfig) + setupExtractProtosTask(protoSourceSet, protobufConfig, dummyTask) } NamedDomainObjectContainer variantSourceSets = @@ -142,7 +144,7 @@ class ProtobufPlugin implements Plugin { new DefaultProtoSourceSet(name, project.objects) } ProjectExt.forEachVariant(this.project) { BaseVariant variant -> - addTasksForVariant(variant, variantSourceSets, postConfigure) + addTasksForVariant(variant, variantSourceSets, postConfigure, dummyTask) } } else { project.sourceSets.configureEach { sourceSet -> @@ -150,7 +152,7 @@ class ProtobufPlugin implements Plugin { addSourceSetExtension(sourceSet, protoSourceSet) Configuration protobufConfig = createProtobufConfiguration(protoSourceSet) Configuration compileProtoPath = createCompileProtoPathConfiguration(protoSourceSet) - addTasksForSourceSet(sourceSet, protoSourceSet, protobufConfig, compileProtoPath, postConfigure) + addTasksForSourceSet(sourceSet, protoSourceSet, protobufConfig, compileProtoPath, postConfigure, dummyTask) } } project.afterEvaluate { @@ -237,11 +239,11 @@ class ProtobufPlugin implements Plugin { */ private void addTasksForSourceSet( SourceSet sourceSet, ProtoSourceSet protoSourceSet, Configuration protobufConfig, - Configuration compileProtoPath, Collection postConfigure) { - Provider extractProtosTask = setupExtractProtosTask(protoSourceSet, protobufConfig) + Configuration compileProtoPath, Collection postConfigure, Provider dummyTask) { + Provider extractProtosTask = setupExtractProtosTask(protoSourceSet, protobufConfig, dummyTask) Provider extractIncludeProtosTask = setupExtractIncludeProtosTask( - protoSourceSet, compileProtoPath) + protoSourceSet, compileProtoPath, dummyTask) // Make protos in 'test' sourceSet able to import protos from the 'main' sourceSet. // Pass include proto files from main to test. @@ -295,7 +297,8 @@ class ProtobufPlugin implements Plugin { private void addTasksForVariant( Object variant, NamedDomainObjectContainer variantSourceSets, - Collection postConfigure + Collection postConfigure, + Provider dummyTask ) { Boolean isTestVariant = variant instanceof TestVariant || variant instanceof UnitTestVariant ProtoSourceSet variantSourceSet = variantSourceSets.create(variant.name) @@ -318,7 +321,7 @@ class ProtobufPlugin implements Plugin { } } - setupExtractIncludeProtosTask(variantSourceSet, classPathConfig) + setupExtractIncludeProtosTask(variantSourceSet, classPathConfig, dummyTask) // GenerateProto task, one per variant (compilation unit). variant.sourceSets.each { SourceProvider sourceProvider -> @@ -422,7 +425,8 @@ class ProtobufPlugin implements Plugin { */ private Provider setupExtractProtosTask( ProtoSourceSet protoSourceSet, - Configuration protobufConfig + Configuration protobufConfig, + Provider dummyTask ) { String sourceSetName = protoSourceSet.name String taskName = getExtractProtosTaskName(sourceSetName) @@ -430,6 +434,7 @@ class ProtobufPlugin implements Plugin { it.description = "Extracts proto files/dependencies specified by 'protobuf' configuration" it.destDir.set(getExtractedProtosDir(sourceSetName) as File) it.inputFiles.from(protobufConfig) + it.dummyTaskDependency.from(dummyTask) } protoSourceSet.proto.srcDir(task) return task @@ -448,13 +453,15 @@ class ProtobufPlugin implements Plugin { */ private Provider setupExtractIncludeProtosTask( ProtoSourceSet protoSourceSet, - FileCollection archives + FileCollection archives, + Provider dummyTask ) { String taskName = 'extractInclude' + Utils.getSourceSetSubstringForTaskNames(protoSourceSet.name) + 'Proto' Provider task = project.tasks.register(taskName, ProtobufExtract) { it.description = "Extracts proto files from compile dependencies for includes" it.destDir.set(getExtractedIncludeProtosDir(protoSourceSet.name) as File) it.inputFiles.from(archives) + it.dummyTaskDependency.from(dummyTask) } protoSourceSet.includeProtoDirs.from(task) return task