From 3ee089bb4830800cab066231445f6ba247e2de1a Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Thu, 20 Apr 2023 20:31:46 +0200 Subject: [PATCH] Decouple KaptGenerateStubsTask from related KotlinCompile task configuration This should simplify setup and remove task circular dependencies. Generally users should not be affected by it unless they are configuring KotlinCompile task explicetly and expect the same configuration will be present on KaptGenerateStubsTask. ^KT-54468 In Progress --- .../org/jetbrains/kotlin/gradle/Kapt3IT.kt | 2 +- .../org/jetbrains/kotlin/gradle/UpToDateIT.kt | 4 +- .../kotlin/gradle/android/Kapt3AndroidIT.kt | 1 - .../kapt2/generatedSources/build.gradle | 6 +- .../kapt/Kapt3KotlinGradleSubplugin.kt | 34 ++-- .../internal/kapt/KaptGenerateStubsTask.kt | 12 +- .../plugin/Kotlin2JvmSourceSetProcessor.kt | 16 +- .../gradle/plugin/mpp/kotlinCompilations.kt | 14 +- .../targets/android/AndroidProjectHandler.kt | 31 +++- .../configuration/KaptGenerateStubsConfig.kt | 154 +++++++----------- 10 files changed, 142 insertions(+), 132 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt index a074cd8a1f0..f32614005bb 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt @@ -1038,7 +1038,7 @@ open class Kapt3IT : Kapt3BaseIT() { } } - @DisplayName("KT-52761: generated sources attached to compile task are also used by generate stubs task") + @DisplayName("Generated sources attached to KotlinSourceSet are also used by generate stubs task") @GradleTest fun testGeneratedSourcesUsedInGenerateStubsTask(gradleVersion: GradleVersion) { project("generatedSources".withPrefix, gradleVersion) { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/UpToDateIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/UpToDateIT.kt index 69df1732280..d643402f0ec 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/UpToDateIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/UpToDateIT.kt @@ -192,8 +192,8 @@ class UpToDateIT : KGPBaseTest() { } override fun checkAfterRebuild(buildResult: BuildResult) = with(buildResult) { - assertTasksExecuted(":compileKotlin", ":kaptGenerateStubsKotlin") - assertTasksUpToDate(":kaptKotlin") + assertTasksExecuted(":compileKotlin") + assertTasksUpToDate(":kaptGenerateStubsKotlin", ":kaptKotlin") } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIT.kt index 71aae9bd80e..9389bcf8f2b 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/android/Kapt3AndroidIT.kt @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.gradle.testbase.* import org.jetbrains.kotlin.gradle.util.* import org.junit.jupiter.api.DisplayName import kotlin.io.path.appendText -import kotlin.io.path.readText import kotlin.io.path.writeText @DisplayName("android with kapt3 tests") diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/generatedSources/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/generatedSources/build.gradle index 46c87cb98b9..961a26cd926 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/generatedSources/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/generatedSources/build.gradle @@ -8,8 +8,10 @@ repositories { mavenCentral() } -tasks.named("compileKotlin", org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile.class) { - source("src/proto/generated") +sourceSets { + main { + kotlin.srcDir("src/proto/generated") + } } tasks.withType(JavaCompile.class).configureEach { 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 10f2e5373d0..61db08ab165 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 @@ -240,9 +240,10 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To kaptExtension.includeCompileClasspath ?: project.isIncludeCompileClasspath() + @Suppress("UNCHECKED_CAST") val kotlinCompile: TaskProvider // Can't use just kotlinCompilation.compileKotlinTaskProvider, as the latter is not statically-known to be KotlinCompile - get() = checkNotNull(project.locateTask(kotlinCompilation.compileKotlinTaskName)) + get() = kotlinCompilation.compileTaskProvider as TaskProvider } override fun applyToCompilation( @@ -355,7 +356,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To private fun Kapt3SubpluginContext.createKaptKotlinTask( generateStubsTask: TaskProvider ): TaskProvider { - val taskName = getKaptTaskName("kapt") + val taskName = kotlinCompile.kaptTaskName @Suppress("UNCHECKED_CAST") val taskConfigAction = KaptWithoutKotlincConfig( kotlinCompilation.project, @@ -432,10 +433,10 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To } private fun Kapt3SubpluginContext.createKaptGenerateStubsTask(): TaskProvider { - val kaptTaskName = getKaptTaskName("kaptGenerateStubs") + val kaptTaskName = kotlinCompile.kaptGenerateStubsTaskName val kaptTaskProvider = project.registerTask(kaptTaskName) - val taskConfig = KaptGenerateStubsConfig(kotlinCompilation, kotlinCompile, classesOutputDir) + val taskConfig = KaptGenerateStubsConfig(kotlinCompilation) taskConfig.configureTask { it.stubsDir.set(getKaptStubsDir()) it.destinationDirectory.set(getKaptIncrementalDataDir()) @@ -451,13 +452,6 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To return kaptTaskProvider } - private fun Kapt3SubpluginContext.getKaptTaskName(prefix: String): String { - // Replace compile*Kotlin to kapt*Kotlin - val baseName = kotlinCompile.name - assert(baseName.startsWith("compile")) - return baseName.replaceFirst("compile", prefix) - } - private fun Kapt3SubpluginContext.disableAnnotationProcessingInJavaTask() { javaCompile?.configure { javaCompileInstance -> if (javaCompileInstance !is JavaCompile) @@ -491,6 +485,24 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To JetBrainsSubpluginArtifact(artifactId = KAPT_ARTIFACT_NAME) } +internal const val KAPT_GENERATE_STUBS_PREFIX = "kaptGenerateStubs" +internal const val KAPT_PREFIX = "kapt" + +internal val TaskProvider.kaptGenerateStubsTaskName + get() = getKaptTaskName(name, KAPT_GENERATE_STUBS_PREFIX) + +internal val TaskProvider.kaptTaskName + get() = getKaptTaskName(name, KAPT_PREFIX) + +internal fun getKaptTaskName( + kotlinCompileName: String, + prefix: String +): String { + // Replace compile*Kotlin to kapt*Kotlin + assert(kotlinCompileName.startsWith("compile")) + return kotlinCompileName.replaceFirst("compile", prefix) +} + internal fun buildKaptSubpluginOptions( kaptExtension: KaptExtension, project: Project, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt index 03dea277f86..a18bf57a8d6 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt @@ -25,7 +25,6 @@ import org.gradle.work.Incremental import org.gradle.work.NormalizeLineEndings import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsDefault import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsHelper import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext @@ -88,6 +87,9 @@ abstract class KaptGenerateStubsTask @Inject constructor( @get:Internal override val androidLayoutResources: FileCollection = objectFactory.fileCollection() + @get:Internal + abstract val kotlinCompileDestinationDirectory: DirectoryProperty + override val incrementalProps: List get() = listOf( sources, @@ -97,18 +99,10 @@ abstract class KaptGenerateStubsTask @Inject constructor( classpathSnapshotProperties.classpathSnapshot ) - @get:Internal - internal abstract val compileTaskCompilerOptions: Property - override fun createCompilerArguments(context: CreateCompilerArgumentsContext) = context.create { primitive { args -> args.allowNoSourceFiles = true - KotlinJvmCompilerOptionsHelper.fillCompilerArguments(compileTaskCompilerOptions.get(), args) - // Workaround for freeCompiler args duplication when they were configured for both this task - // and linked KotlinCompile task with the same values. For now linked KotlinCompile task - // freeCompilerArgs is used as convention for this task freeCompilerArgs - args.freeArgs = emptyList() KotlinJvmCompilerOptionsHelper.fillCompilerArguments(compilerOptions, args) overrideArgsUsingTaskModuleNameWithWarning(args) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/Kotlin2JvmSourceSetProcessor.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/Kotlin2JvmSourceSetProcessor.kt index 311fc6719a1..38af7d69ba3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/Kotlin2JvmSourceSetProcessor.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/Kotlin2JvmSourceSetProcessor.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider +import org.jetbrains.kotlin.gradle.tasks.configuration.KaptGenerateStubsConfig import org.jetbrains.kotlin.gradle.tasks.configuration.KotlinCompileConfig import org.jetbrains.kotlin.gradle.tasks.withType import org.jetbrains.kotlin.gradle.utils.whenKaptEnabled @@ -34,7 +35,14 @@ internal class Kotlin2JvmSourceSetProcessor( taskName, compilationInfo.compilerOptions.options as KotlinJvmCompilerOptions, configAction - ) + ).also { kotlinTask -> + // Configuring here to not interfere with 'kotlin-android' plugin configuration for 'libraries' input + KaptGenerateStubsConfig.configureLibraries( + project, + kotlinTask, + { compilationInfo.compileDependencyFiles } + ) + } } override fun doTargetSpecificProcessing() { @@ -59,6 +67,12 @@ internal class Kotlin2JvmSourceSetProcessor( kotlinTask.configure { kotlinCompile -> kotlinCompile.javaOutputDir.set(javaTask.flatMap { it.destinationDirectory }) } + + KaptGenerateStubsConfig.wireJavaAndKotlinOutputs( + project, + javaTask, + kotlinTask + ) } if (sourceSetName == SourceSet.MAIN_SOURCE_SET_NAME) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt index 5d826c3c0da..55be88cfad5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt @@ -9,6 +9,8 @@ import org.gradle.api.Project import org.gradle.api.provider.Provider import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions +import org.jetbrains.kotlin.gradle.internal.KAPT_GENERATE_STUBS_PREFIX +import org.jetbrains.kotlin.gradle.internal.getKaptTaskName import org.jetbrains.kotlin.gradle.plugin.HasCompilerOptions import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName @@ -52,16 +54,20 @@ internal fun addSourcesToKotlinCompileTask( // The `commonSourceSet` is passed to the compiler as-is, converted with toList commonSourceSet.from( - Callable { if (addAsCommonSources.value) sources else emptyList() } + { if (addAsCommonSources.value) sources else emptyList() } ) } project.tasks - // To configure a task that may have not yet been created at this point, use 'withType-matching-configureEach`: .withType(AbstractKotlinCompile::class.java) - .matching { it.name == taskName } .configureEach { compileKotlinTask -> - compileKotlinTask.configureAction() + val compileTaskName = compileKotlinTask.name + // We also should configure related Kapt* tasks as they are not pickup configuration from + // related KotlinJvmCompile to avoid circular task dependencies + val kaptGenerateStubsTaskName = getKaptTaskName(compileTaskName, KAPT_GENERATE_STUBS_PREFIX) + if (compileTaskName == taskName || kaptGenerateStubsTaskName == taskName) { + compileKotlinTask.configureAction() + } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt index 7ccb442e17c..55eaef46c89 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/AndroidProjectHandler.kt @@ -26,7 +26,7 @@ import org.gradle.api.tasks.bundling.AbstractArchiveTask import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile import org.jetbrains.kotlin.gradle.dsl.* -import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin +import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.checkAndroidAnnotationProcessorDependencyUsage import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.android.KotlinAndroidSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.android.findKotlinSourceSet import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider +import org.jetbrains.kotlin.gradle.tasks.configuration.KaptGenerateStubsConfig import org.jetbrains.kotlin.gradle.tasks.configuration.KotlinCompileConfig import org.jetbrains.kotlin.gradle.tasks.thisTaskProvider import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry @@ -46,7 +47,6 @@ import java.io.File import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.io.Serializable -import java.util.concurrent.Callable internal class AndroidProjectHandler( private val kotlinTasksProvider: KotlinTasksProvider @@ -186,13 +186,22 @@ internal class AndroidProjectHandler( task.destinationDirectory.set(project.layout.buildDirectory.dir("tmp/kotlin-classes/$variantDataName")) task.description = "Compiles the $variantDataName kotlin." } - tasksProvider.registerKotlinJVMTask( + val kotlinTask = tasksProvider.registerKotlinJVMTask( project, compilation.compileKotlinTaskName, compilation.compilerOptions.options as KotlinJvmCompilerOptions, configAction ) + // Need to move it into afterEvaluate, so it will be executed after KaptGenerateStubsConfig config actions + // Otherwise build will fail within AbstractKotlinCompileConfig trying to modify value with 'disallowChanges()' state + project.afterEvaluate { + KaptGenerateStubsConfig.configureUseModuleDetection( + project, + kotlinTask + ) { value(true).disallowChanges() } + } + // Register the source only after the task is created, because the task is required for that: compilation.source(defaultSourceSet) @@ -250,11 +259,23 @@ internal class AndroidProjectHandler( kotlinTask.configure { kotlinTaskInstance -> kotlinTaskInstance.libraries .from(variantData.getCompileClasspath(preJavaClasspathKey)) - .from(Callable { AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt) }) + .from({ AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt) }) kotlinTaskInstance.javaOutputDir.set(javaTask.flatMap { it.destinationDirectory }) } + KaptGenerateStubsConfig.configureLibraries( + project, + kotlinTask, + variantData.getCompileClasspath(preJavaClasspathKey), + { AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt) } + ) + KaptGenerateStubsConfig.wireJavaAndKotlinOutputs( + project, + javaTask, + kotlinTask + ) + // Find the classpath entries that come from the tested variant and register them as the friend paths, lazily val originalArtifactCollection = variantData.getCompileClasspathArtifacts(preJavaClasspathKey) val testedVariantDataIsNotNull = getTestedVariantData(variantData) != null @@ -306,7 +327,7 @@ internal class AndroidProjectHandler( project.addExtendsFromRelation(name, compilation.runtimeDependencyConfigurationName) } - val buildTypeAttrValue = project.objects.named(BuildTypeAttr::class.java, variant.buildType.name) + val buildTypeAttrValue = project.objects.named(variant.buildType.name) listOf(compilation.compileDependencyConfigurationName, compilation.runtimeDependencyConfigurationName).forEach { project.configurations.findByName(it)?.attributes?.attribute(Attribute.of(BuildTypeAttr::class.java), buildTypeAttrValue) } 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 d151a9657cd..e525891fe89 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 @@ -6,11 +6,12 @@ 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.Property import org.gradle.api.provider.Provider -import org.gradle.api.specs.Spec import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.compile.AbstractCompile +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsHelper import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_SUBPLUGIN_ID @@ -19,66 +20,29 @@ import org.jetbrains.kotlin.gradle.plugin.KaptExtension import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -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 +import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile +import org.jetbrains.kotlin.gradle.tasks.withType +import org.jetbrains.kotlin.gradle.utils.whenKaptEnabled internal class KaptGenerateStubsConfig : BaseKotlinCompileConfig { constructor( - compilation: KotlinCompilation<*>, - kotlinTaskProvider: TaskProvider, - kaptClassesDir: File + compilation: KotlinCompilation<*> ) : super(KotlinCompilationInfo(compilation)) { configureFromExtension(project.extensions.getByType(KaptExtension::class.java)) - configureTask { task -> - val kotlinCompileTask = kotlinTaskProvider.get() - task.useModuleDetection.value(kotlinCompileTask.useModuleDetection).disallowChanges() - @Suppress("DEPRECATION") - task.moduleName.value(kotlinCompileTask.moduleName).disallowChanges() - task.libraries.from({ kotlinCompileTask.libraries - project.files(kaptClassesDir) }) - task.compileTaskCompilerOptions.set(providers.provider { kotlinCompileTask.compilerOptions }) - task.pluginOptions.addAll(kotlinCompileTask.pluginOptions) - task.compilerOptions.moduleName.convention(kotlinCompileTask.compilerOptions.moduleName) - task.compilerOptions.freeCompilerArgs.convention(kotlinCompileTask.compilerOptions.freeCompilerArgs) - // KotlinCompile will also have as input output from KaptGenerateStubTask and KaptTask - // We are filtering them to avoid failed UP-TO-DATE checks - val kaptJavaSourcesDir = Kapt3GradleSubplugin.getKaptGeneratedSourcesDir( - project, - compilation.compilationName - ) - val kaptKotlinSourcesDir = Kapt3GradleSubplugin.getKaptGeneratedKotlinSourcesDir( - project, - compilation.compilationName - ) - val destinationDirectory = task.destinationDirectory - val stubsDir = task.stubsDir - val kaptFilterSpec = KaptFilterSpec(destinationDirectory, stubsDir, kaptJavaSourcesDir, kaptKotlinSourcesDir) - // FileTree filtering approach fails with configuration cache until Gradle 7.5 leading to failed UP-TO-DATE checks - val kaptFilter = if (shouldUseFileTreeKaptFilter) { - FileTreeKaptInputsFilter(kaptFilterSpec) - } else { - FileCollectionKaptInputsFilter(kaptFilterSpec) - } - task.source( - kaptFilter.filtered(kotlinCompileTask.javaSources), - kaptFilter.filtered(kotlinCompileTask.sources), + + configureTask { kaptGenerateStubsTask -> + // Syncing compiler options from related KotlinJvmCompile task + val jvmCompilerOptions = compilation.compilerOptions.options as KotlinJvmCompilerOptions + KotlinJvmCompilerOptionsHelper.syncOptionsAsConvention( + from = jvmCompilerOptions, + into = kaptGenerateStubsTask.compilerOptions ) } } constructor(project: Project, ext: KotlinTopLevelExtension, kaptExtension: KaptExtension) : super(project, ext) { configureFromExtension(kaptExtension) - configureTask { task -> - task.compileTaskCompilerOptions.set( - providers.provider { task.compilerOptions } - ) - } } private fun configureFromExtension(kaptExtension: KaptExtension) { @@ -118,53 +82,51 @@ 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 } + companion object { + internal fun wireJavaAndKotlinOutputs( + project: Project, + javaCompileTask: TaskProvider, + kotlinCompileTask: TaskProvider + ) { + project.whenKaptEnabled { + val kaptGenerateStubsTaskName = getKaptTaskName(kotlinCompileTask.name, KAPT_GENERATE_STUBS_PREFIX) + project.tasks.withType().configureEach { task -> + if (task.name == kaptGenerateStubsTaskName) { + task.javaOutputDir.set(javaCompileTask.flatMap { it.destinationDirectory }) + task.kotlinCompileDestinationDirectory.set(kotlinCompileTask.flatMap { it.destinationDirectory }) + } + } } - } - - private val shouldUseFileTreeKaptFilter - get() = isGradleVersionAtLeast(7, 5) || !isConfigurationCacheAvailable(project.gradle) - - 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) - } + internal fun configureLibraries( + project: Project, + kotlinCompileTask: TaskProvider, + vararg paths: Any + ) { + project.whenKaptEnabled { + val kaptGenerateStubsTaskName = getKaptTaskName(kotlinCompileTask.name, KAPT_GENERATE_STUBS_PREFIX) + project.tasks.withType().configureEach { task -> + if (task.name == kaptGenerateStubsTaskName) { + task.libraries.from(paths) + } + } + } + } - private class KaptFilterSpec( - private val destinationDirectory: DirectoryProperty, - private val stubsDir: DirectoryProperty, - private val kaptJavaSourcesDir: File, - private val kaptKotlinSourcesDir: File, - ) : Spec { - override fun isSatisfiedBy(element: File) = element.isSourceRootAllowed() - - private fun File.isSourceRootAllowed(): Boolean = - !destinationDirectory.get().asFile.isParentOf(this) && - !stubsDir.asFile.get().isParentOf(this) && - !kaptJavaSourcesDir.isParentOf(this) && - !kaptKotlinSourcesDir.isParentOf(this) + internal fun configureUseModuleDetection( + project: Project, + kotlinCompileTask: TaskProvider, + config: Property.() -> Unit + ) { + project.whenKaptEnabled { + val kaptGenerateStubsTaskName = getKaptTaskName(kotlinCompileTask.name, KAPT_GENERATE_STUBS_PREFIX) + project.tasks.withType().configureEach { task -> + if (task.name == kaptGenerateStubsTaskName) { + config(task.useModuleDetection) + } + } + } + } } -} \ No newline at end of file +}