From ee1517cd6a1cd5bbe5ffea41459fc7dfddf208ef Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Fri, 20 Jan 2023 15:54:37 +0100 Subject: [PATCH] Decouple Kapt task from KotlinCompile task configuration This fixes KotlinCompile task instantiation on configuring Kapt tasks as well Kapt tasks itself eager realization. Additionally this change removes circular dependency between kapt and compilation tasks. ^KT-54468 In Progress --- .../kotlin/gradle/ConfigurationAvoidanceIT.kt | 26 ++++++++++++- .../testProject/kapt2/simple/build.gradle | 6 ++- .../kapt/Kapt3KotlinGradleSubplugin.kt | 35 ++++++++++++------ .../gradle/tasks/configuration/KaptConfig.kt | 37 +++++++++++++------ 4 files changed, 77 insertions(+), 27 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ConfigurationAvoidanceIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ConfigurationAvoidanceIT.kt index 607c7578a4e..eed0fdcbbbb 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ConfigurationAvoidanceIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ConfigurationAvoidanceIT.kt @@ -27,8 +27,7 @@ class ConfigurationAvoidanceIT : KGPBaseTest() { @JvmGradlePluginTests @GradleTestVersions( - maxVersion = TestVersions.Gradle.G_7_5, - additionalVersions = [TestVersions.Gradle.G_7_3, TestVersions.Gradle.G_7_4] + additionalVersions = [TestVersions.Gradle.G_7_3] ) @DisplayName("KGP/Jvm does not eagerly configure any tasks") @GradleTest @@ -49,6 +48,29 @@ class ConfigurationAvoidanceIT : KGPBaseTest() { } } + @OtherGradlePluginTests + @GradleTestVersions( + additionalVersions = [TestVersions.Gradle.G_7_3] + ) + @DisplayName("KGP/Kapt does not eagerly configure any tasks") + @GradleTest + fun testKaptConfigurationAvoidance(gradleVersion: GradleVersion) { + project("kapt2/simple", gradleVersion) { + buildGradle.appendText( + """ + | + |tasks.configureEach { + | if (name != "help" && name != "clean") { + | throw new GradleException("Configuration avoidance failure for ${'$'}name!") + | } + |} + """.trimMargin() + ) + + build("--dry-run") + } + } + @AndroidGradlePluginTests @DisplayName("Android unrelated tasks are not configured") @AndroidTestVersions(minVersion = TestVersions.AGP.AGP_42) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/simple/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/simple/build.gradle index 84961752565..c940dd01607 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/simple/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/simple/build.gradle @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile + plugins { id "java" id "org.jetbrains.kotlin.jvm" @@ -16,4 +18,6 @@ dependencies { testImplementation 'junit:junit:4.13.2' } -compileKotlin.kotlinOptions.allWarningsAsErrors = true +tasks.named("compileKotlin", KotlinJvmCompile) { + compilerOptions.allWarningsAsErrors = true +} 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 98f68086e94..10f2e5373d0 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 @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isUse import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.configuration.* import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild @@ -283,15 +284,12 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To ) val kaptGenerateStubsTaskProvider: TaskProvider = context.createKaptGenerateStubsTask() - val kaptTaskProvider: TaskProvider = context.createKaptKotlinTask() + val kaptTaskProvider: TaskProvider = context.createKaptKotlinTask( + kaptGenerateStubsTaskProvider + ) kaptGenerateStubsTaskProvider.configure { kaptGenerateStubsTask -> kaptGenerateStubsTask.dependsOn(*buildDependencies.toTypedArray()) - kaptGenerateStubsTask.dependsOn( - project.provider { - kotlinCompilation.compileKotlinTask.dependsOn.filter { it !is TaskProvider<*> || it.name != kaptTaskProvider.name } - } - ) if (androidVariantData != null) { kaptGenerateStubsTask.additionalSources.from( @@ -305,9 +303,6 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To } } - kaptTaskProvider.configure { kaptTask -> - kaptTask.dependsOn(kaptGenerateStubsTaskProvider) - } context.kotlinCompile.configure { it.dependsOn(kaptTaskProvider) } /** Plugin options are applied to kapt*Compile inside [createKaptKotlinTask] */ @@ -357,9 +352,16 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To ).get() } - private fun Kapt3SubpluginContext.createKaptKotlinTask(): TaskProvider { + private fun Kapt3SubpluginContext.createKaptKotlinTask( + generateStubsTask: TaskProvider + ): TaskProvider { val taskName = getKaptTaskName("kapt") - val taskConfigAction = KaptWithoutKotlincConfig(kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile, kaptExtension) + @Suppress("UNCHECKED_CAST") + val taskConfigAction = KaptWithoutKotlincConfig( + kotlinCompilation.project, + generateStubsTask, + kaptExtension + ) val kaptClasspathConfiguration = project.configurations.create("kaptClasspath_$taskName") .setExtendsFrom(kaptClasspathConfigurations).also { @@ -367,6 +369,8 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To it.isCanBeConsumed = false } taskConfigAction.configureTaskProvider { taskProvider -> + taskProvider.dependsOn(generateStubsTask) + if (javaCompile != null) { val androidVariantData = KaptWithAndroid.androidVariantData(this) if (androidVariantData != null) { @@ -379,7 +383,14 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To disableAnnotationProcessingInJavaTask() } - kotlinCompilation.output.classesDirs.from(taskProvider.flatMap { it.classesDir }) + // Workaround for changes in Gradle 7.3 causing eager task realization + // For details check `KotlinSourceSetProcessor.prepareKotlinCompileTask()` + if (kotlinCompilation is KotlinWithJavaCompilation<*, *>) { + val kotlinSourceDirectorySet = kotlinCompilation.defaultSourceSet.kotlin + kotlinSourceDirectorySet.compiledBy(taskProvider, KaptTask::classesDir) + } else { + kotlinCompilation.output.classesDirs.from(taskProvider.flatMap { it.classesDir }) + } kotlinCompilation.compileTaskProvider.configure { task -> with(task as AbstractKotlinCompile<*>) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt index 2873a22e677..1d179f87fb8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt @@ -24,12 +24,10 @@ import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ART import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformAction import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction import org.jetbrains.kotlin.gradle.plugin.* -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.toCompilerPluginOptions import org.jetbrains.kotlin.gradle.utils.listProperty import org.jetbrains.kotlin.gradle.utils.markResolvable import java.io.File -import java.util.concurrent.Callable internal open class KaptConfig( project: Project, @@ -49,7 +47,7 @@ internal open class KaptConfig( task.includeCompileClasspath.set(ext.includeCompileClasspath ?: project.isIncludeCompileClasspath()) task.classpathStructure.from(kaptClasspathSnapshot) - task.localStateDirectories.from(Callable { task.incAptCache.orNull }) + task.localStateDirectories.from({ task.incAptCache.orNull }) task.onlyIf { it as KaptTask it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty @@ -58,18 +56,26 @@ internal open class KaptConfig( } } - internal constructor(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : this(kotlinCompileTask.project, ext) { + internal constructor( + project: Project, + kaptGenerateStubsTask: TaskProvider, + ext: KaptExtension + ) : this(project, ext) { configureTask { task -> - task.classpath.from(kotlinCompileTask.libraries - project.files(task.classesDir)) - task.compiledSources.from( - kotlinCompileTask.destinationDirectory, - Callable { kotlinCompileTask.javaOutputDir.takeIf { it.isPresent } }) + task.classpath.from( + kaptGenerateStubsTask.map { it.libraries } + ) + task.compiledSources + .from( + kaptGenerateStubsTask.flatMap { it.kotlinCompileDestinationDirectory }, + { kaptGenerateStubsTask.get().javaOutputDir.takeIf { it.isPresent } } + ) .disallowChanges() - task.sourceSetName.value(kotlinCompileTask.sourceSetName).disallowChanges() + task.sourceSetName.value(kaptGenerateStubsTask.flatMap { it.sourceSetName }).disallowChanges() val kaptSources = objectFactory.fileCollection() - .from(kotlinCompileTask.javaSources, task.stubsDir) + .from(kaptGenerateStubsTask.map { it.javaSources }, task.stubsDir) .asFileTree .matching { it.include("**/*.java") } .filter { @@ -175,14 +181,21 @@ internal class KaptWithoutKotlincConfig : KaptConfig { ) task.kaptJars.from(project.configurations.getByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)) task.mapDiagnosticLocations = ext.mapDiagnosticLocations - task.annotationProcessorFqNames.set(providers.provider { ext.processors.split(',').filter { it.isNotEmpty() } }) + task.annotationProcessorFqNames.set(providers.provider { + @Suppress("DEPRECATION") + ext.processors.split(',').filter { it.isNotEmpty() } + }) task.disableClassloaderCacheForProcessors = project.disableClassloaderCacheForProcessors() task.classLoadersCacheSize = project.classLoadersCacheSize() task.javacOptions.set(getJavaOptions(task.defaultJavaSourceCompatibility)) } } - constructor(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : super(kotlinCompileTask, ext) { + constructor( + project: Project, + kaptGenerateStubsTask: TaskProvider, + ext: KaptExtension + ) : super(project, kaptGenerateStubsTask, ext) { project.configurations.findByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME) ?: project.configurations.create(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply { dependencies.addAllLater(project.listProperty {