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
This commit is contained in:
Yahor Berdnikau
2023-01-20 15:54:37 +01:00
committed by Space Team
parent e06606aa3f
commit ee1517cd6a
4 changed files with 77 additions and 27 deletions
@@ -27,8 +27,7 @@ class ConfigurationAvoidanceIT : KGPBaseTest() {
@JvmGradlePluginTests @JvmGradlePluginTests
@GradleTestVersions( @GradleTestVersions(
maxVersion = TestVersions.Gradle.G_7_5, additionalVersions = [TestVersions.Gradle.G_7_3]
additionalVersions = [TestVersions.Gradle.G_7_3, TestVersions.Gradle.G_7_4]
) )
@DisplayName("KGP/Jvm does not eagerly configure any tasks") @DisplayName("KGP/Jvm does not eagerly configure any tasks")
@GradleTest @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 @AndroidGradlePluginTests
@DisplayName("Android unrelated tasks are not configured") @DisplayName("Android unrelated tasks are not configured")
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_42) @AndroidTestVersions(minVersion = TestVersions.AGP.AGP_42)
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
plugins { plugins {
id "java" id "java"
id "org.jetbrains.kotlin.jvm" id "org.jetbrains.kotlin.jvm"
@@ -16,4 +18,6 @@ dependencies {
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
} }
compileKotlin.kotlinOptions.allWarningsAsErrors = true tasks.named("compileKotlin", KotlinJvmCompile) {
compilerOptions.allWarningsAsErrors = true
}
@@ -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.model.builder.KaptModelBuilder
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation 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.*
import org.jetbrains.kotlin.gradle.tasks.configuration.* import org.jetbrains.kotlin.gradle.tasks.configuration.*
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
@@ -283,15 +284,12 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
) )
val kaptGenerateStubsTaskProvider: TaskProvider<KaptGenerateStubsTask> = context.createKaptGenerateStubsTask() val kaptGenerateStubsTaskProvider: TaskProvider<KaptGenerateStubsTask> = context.createKaptGenerateStubsTask()
val kaptTaskProvider: TaskProvider<out KaptTask> = context.createKaptKotlinTask() val kaptTaskProvider: TaskProvider<out KaptTask> = context.createKaptKotlinTask(
kaptGenerateStubsTaskProvider
)
kaptGenerateStubsTaskProvider.configure { kaptGenerateStubsTask -> kaptGenerateStubsTaskProvider.configure { kaptGenerateStubsTask ->
kaptGenerateStubsTask.dependsOn(*buildDependencies.toTypedArray()) kaptGenerateStubsTask.dependsOn(*buildDependencies.toTypedArray())
kaptGenerateStubsTask.dependsOn(
project.provider {
kotlinCompilation.compileKotlinTask.dependsOn.filter { it !is TaskProvider<*> || it.name != kaptTaskProvider.name }
}
)
if (androidVariantData != null) { if (androidVariantData != null) {
kaptGenerateStubsTask.additionalSources.from( 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) } context.kotlinCompile.configure { it.dependsOn(kaptTaskProvider) }
/** Plugin options are applied to kapt*Compile inside [createKaptKotlinTask] */ /** Plugin options are applied to kapt*Compile inside [createKaptKotlinTask] */
@@ -357,9 +352,16 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
).get() ).get()
} }
private fun Kapt3SubpluginContext.createKaptKotlinTask(): TaskProvider<out KaptTask> { private fun Kapt3SubpluginContext.createKaptKotlinTask(
generateStubsTask: TaskProvider<KaptGenerateStubsTask>
): TaskProvider<out KaptTask> {
val taskName = getKaptTaskName("kapt") 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") val kaptClasspathConfiguration = project.configurations.create("kaptClasspath_$taskName")
.setExtendsFrom(kaptClasspathConfigurations).also { .setExtendsFrom(kaptClasspathConfigurations).also {
@@ -367,6 +369,8 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
it.isCanBeConsumed = false it.isCanBeConsumed = false
} }
taskConfigAction.configureTaskProvider { taskProvider -> taskConfigAction.configureTaskProvider { taskProvider ->
taskProvider.dependsOn(generateStubsTask)
if (javaCompile != null) { if (javaCompile != null) {
val androidVariantData = KaptWithAndroid.androidVariantData(this) val androidVariantData = KaptWithAndroid.androidVariantData(this)
if (androidVariantData != null) { if (androidVariantData != null) {
@@ -379,7 +383,14 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
disableAnnotationProcessingInJavaTask() 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 -> kotlinCompilation.compileTaskProvider.configure { task ->
with(task as AbstractKotlinCompile<*>) { with(task as AbstractKotlinCompile<*>) {
@@ -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.StructureTransformAction
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction
import org.jetbrains.kotlin.gradle.plugin.* 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.tasks.toCompilerPluginOptions
import org.jetbrains.kotlin.gradle.utils.listProperty import org.jetbrains.kotlin.gradle.utils.listProperty
import org.jetbrains.kotlin.gradle.utils.markResolvable import org.jetbrains.kotlin.gradle.utils.markResolvable
import java.io.File import java.io.File
import java.util.concurrent.Callable
internal open class KaptConfig<TASK : KaptTask>( internal open class KaptConfig<TASK : KaptTask>(
project: Project, project: Project,
@@ -49,7 +47,7 @@ internal open class KaptConfig<TASK : KaptTask>(
task.includeCompileClasspath.set(ext.includeCompileClasspath ?: project.isIncludeCompileClasspath()) task.includeCompileClasspath.set(ext.includeCompileClasspath ?: project.isIncludeCompileClasspath())
task.classpathStructure.from(kaptClasspathSnapshot) task.classpathStructure.from(kaptClasspathSnapshot)
task.localStateDirectories.from(Callable { task.incAptCache.orNull }) task.localStateDirectories.from({ task.incAptCache.orNull })
task.onlyIf { task.onlyIf {
it as KaptTask it as KaptTask
it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty
@@ -58,18 +56,26 @@ internal open class KaptConfig<TASK : KaptTask>(
} }
} }
internal constructor(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : this(kotlinCompileTask.project, ext) { internal constructor(
project: Project,
kaptGenerateStubsTask: TaskProvider<KaptGenerateStubsTask>,
ext: KaptExtension
) : this(project, ext) {
configureTask { task -> configureTask { task ->
task.classpath.from(kotlinCompileTask.libraries - project.files(task.classesDir)) task.classpath.from(
task.compiledSources.from( kaptGenerateStubsTask.map { it.libraries }
kotlinCompileTask.destinationDirectory, )
Callable { kotlinCompileTask.javaOutputDir.takeIf { it.isPresent } }) task.compiledSources
.from(
kaptGenerateStubsTask.flatMap { it.kotlinCompileDestinationDirectory },
{ kaptGenerateStubsTask.get().javaOutputDir.takeIf { it.isPresent } }
)
.disallowChanges() .disallowChanges()
task.sourceSetName.value(kotlinCompileTask.sourceSetName).disallowChanges() task.sourceSetName.value(kaptGenerateStubsTask.flatMap { it.sourceSetName }).disallowChanges()
val kaptSources = objectFactory.fileCollection() val kaptSources = objectFactory.fileCollection()
.from(kotlinCompileTask.javaSources, task.stubsDir) .from(kaptGenerateStubsTask.map { it.javaSources }, task.stubsDir)
.asFileTree .asFileTree
.matching { it.include("**/*.java") } .matching { it.include("**/*.java") }
.filter { .filter {
@@ -175,14 +181,21 @@ internal class KaptWithoutKotlincConfig : KaptConfig<KaptWithoutKotlincTask> {
) )
task.kaptJars.from(project.configurations.getByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)) task.kaptJars.from(project.configurations.getByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME))
task.mapDiagnosticLocations = ext.mapDiagnosticLocations 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.disableClassloaderCacheForProcessors = project.disableClassloaderCacheForProcessors()
task.classLoadersCacheSize = project.classLoadersCacheSize() task.classLoadersCacheSize = project.classLoadersCacheSize()
task.javacOptions.set(getJavaOptions(task.defaultJavaSourceCompatibility)) task.javacOptions.set(getJavaOptions(task.defaultJavaSourceCompatibility))
} }
} }
constructor(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : super(kotlinCompileTask, ext) { constructor(
project: Project,
kaptGenerateStubsTask: TaskProvider<KaptGenerateStubsTask>,
ext: KaptExtension
) : super(project, kaptGenerateStubsTask, ext) {
project.configurations.findByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME) project.configurations.findByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)
?: project.configurations.create(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply { ?: project.configurations.create(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply {
dependencies.addAllLater(project.listProperty { dependencies.addAllLater(project.listProperty {