From effa12e9a406bad0a63dfc0b238b593c7dda503f Mon Sep 17 00:00:00 2001 From: Alexander Likhachev Date: Tue, 9 Aug 2022 16:20:30 +0200 Subject: [PATCH] [Gradle] Optimize KaptGenerateStubs inputs filtering ^KT-53118 Fixed --- .../kapt/Kapt3KotlinGradleSubplugin.kt | 2 - .../configuration/KaptGenerateStubsConfig.kt | 67 ++++++++++++++----- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 0a1c4ee9048..8fe03415a9b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -482,8 +482,6 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To taskConfig.configureTask { it.stubsDir.set(getKaptStubsDir()) it.destinationDirectory.set(getKaptIncrementalDataDir()) - val generatedSourcesDirs = listOf(sourcesOutputDir, kotlinSourcesOutputDir) - it.exclude { fileElement -> generatedSourcesDirs.any { dir -> dir.isParentOf(fileElement.file) } } it.kaptClasspath.from(kaptClasspathConfigurations) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt index 8a8d0c31908..d10ddf2afac 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.tasks.configuration import org.gradle.api.Project import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.FileCollection import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec import org.gradle.api.tasks.TaskProvider @@ -21,9 +22,12 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompilerArgumentsProvider +import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable +import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast import org.jetbrains.kotlin.gradle.utils.isParentOf import java.io.File import java.nio.file.Files +import java.util.concurrent.ConcurrentHashMap internal class KaptGenerateStubsConfig : BaseKotlinCompileConfig { @@ -48,13 +52,16 @@ internal class KaptGenerateStubsConfig : BaseKotlinCompileConfig() + abstract fun filtered(fileCollection: FileCollection): FileCollection + + protected fun isSatisfiedBy(file: File) = filterCache[file] ?: predicate(file).also { filterCache[file] = it } + + abstract fun predicate(file: File): Boolean + } + // Drop `isEmptyDirectory` check after min supported Gradle version will be bumped to 6.8 // It will be covered by '@IgnoreEmptyDirectories' input annotation + private class FileCollectionKaptInputsFilter(val spec: KaptFilterSpec) : CachingKaptInputsFilter() { + override fun filtered(fileCollection: FileCollection): FileCollection { + return fileCollection.filter(::isSatisfiedBy) + } + + override fun predicate(file: File) = !file.isEmptyDirectory && spec.isSatisfiedBy(file) + + private val File.isEmptyDirectory: Boolean + get() = with(toPath()) { + Files.isDirectory(this) && !Files.list(this).use { it.findFirst().isPresent } + } + } + + private val shouldUseFileTreeKaptFilter + get() = isGradleVersionAtLeast(7, 5) || !isConfigurationCacheAvailable(project.gradle) && isGradleVersionAtLeast(6, 8) + + // Filtering through FileTree and PatternFilterable works faster, but adds empty directories which is the problem for Gradle 6.7 + private class FileTreeKaptInputsFilter(val spec: KaptFilterSpec) : CachingKaptInputsFilter() { + override fun filtered(fileCollection: FileCollection): FileCollection { + return fileCollection.asFileTree.matching { it.include { elem -> isSatisfiedBy(elem.file) } } + } + + override fun predicate(file: File) = spec.isSatisfiedBy(file) + } + private class KaptFilterSpec( private val destinationDirectory: DirectoryProperty, private val stubsDir: DirectoryProperty, - private val additionalParentToCheck: File + private val kaptJavaSourcesDir: File, + private val kaptKotlinSourcesDir: File, ) : Spec { - override fun isSatisfiedBy(element: File): Boolean { - return !element.isEmptyDirectory && - element.isSourceRootAllowed() - } - - private val File.isEmptyDirectory: Boolean - get() = with(toPath()) { Files.isDirectory(this) && !Files.list(this).use { it.findFirst().isPresent } } + override fun isSatisfiedBy(element: File) = element.isSourceRootAllowed() private fun File.isSourceRootAllowed(): Boolean = !destinationDirectory.get().asFile.isParentOf(this) && !stubsDir.asFile.get().isParentOf(this) && - !additionalParentToCheck.isParentOf(this) + !kaptJavaSourcesDir.isParentOf(this) && + !kaptKotlinSourcesDir.isParentOf(this) } } \ No newline at end of file