From e8cd8b566e6d67304603c9d5bc0d8daec05270ec Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Fri, 12 Jan 2018 17:34:46 +0300 Subject: [PATCH] Delay kapt dependencies resolution from configuration phase Store kapt configurations instead of classpath files in the tasks Delay wrapping kapt subplugin options to task execution (when the classpath can be safely resovled) Issue #KT-18821 Fixed --- .../org/jetbrains/kotlin/gradle/Kapt3IT.kt | 13 +++++ .../internal/Kapt3KotlinGradleSubplugin.kt | 50 +++++++++---------- .../gradle/internal/KaptGenerateStubsTask.kt | 15 +++++- .../kotlin/gradle/internal/KaptTask.kt | 12 ++++- .../kotlin/gradle/internal/subpluginUtils.kt | 22 ++++++++ 5 files changed, 81 insertions(+), 31 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 e24abb3680f..626e462b5ce 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 @@ -324,4 +324,17 @@ open class Kapt3IT : Kapt3BaseIT() { assertContains("Additional warning message from AP") } } + + @Test + fun testKaptConfigurationLazyResolution() = with(Project("simple", GRADLE_VERSION, directoryPrefix = "kapt2")) { + setupWorkingDir() + File(projectDir, "build.gradle").appendText( + "\ndependencies { kapt project.files { throw new GradleException(\"Resolved!\") } }" + ) + // Check that the kapt configuration does not get resolved during the project evaluation: + build("tasks") { + assertSuccessful() + assertNotContains("Resolved!") + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt index c0e5223ac85..3c4df43c4a2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt @@ -80,6 +80,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { val KAPT_GROUP_NAME = "org.jetbrains.kotlin" val KAPT_ARTIFACT_NAME = "kotlin-annotation-processing-gradle" + val KAPT_SUBPLUGIN_ID = "org.jetbrains.kotlin.kapt3" fun getKaptConfigurationName(sourceSetName: String): String { return if (sourceSetName != "main") @@ -110,14 +111,15 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { } private inner class Kapt3SubpluginContext( - val project: Project, - val kotlinCompile: KotlinCompile, - val javaCompile: AbstractCompile, - val kaptVariantData: KaptVariantData<*>?, - val sourceSetName: String, - val javaSourceSet: SourceSet?, - val kaptExtension: KaptExtension, - val kaptClasspath: MutableList) { + val project: Project, + val kotlinCompile: KotlinCompile, + val javaCompile: AbstractCompile, + val kaptVariantData: KaptVariantData<*>?, + val sourceSetName: String, + val javaSourceSet: SourceSet?, + val kaptExtension: KaptExtension, + val kaptClasspathConfigurations: List + ) { val sourcesOutputDir = getKaptGeneratedSourcesDir(project, sourceSetName) val kotlinSourcesOutputDir = getKaptGeneratedKotlinSourcesDir(project, sourceSetName) val classesOutputDir = getKaptGeneratedClassesDir(project, sourceSetName) @@ -137,23 +139,13 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { ): List { assert((variantData != null) xor (javaSourceSet != null)) - val kaptClasspath = arrayListOf() val buildDependencies = arrayListOf() val kaptConfigurations = arrayListOf() fun handleSourceSet(sourceSetName: String) { - val kaptConfiguration = project.findKaptConfiguration(sourceSetName) - val filteredDependencies = kaptConfiguration?.dependencies?.filter { - it.group != getGroupName() || it.name != getArtifactName() - } ?: emptyList() - - if (kaptConfiguration != null) { + project.findKaptConfiguration(sourceSetName)?.let { kaptConfiguration -> kaptConfigurations += kaptConfiguration buildDependencies += kaptConfiguration.buildDependencies - - if (filteredDependencies.isNotEmpty()) { - kaptClasspath.addAll(kaptConfiguration.resolve()) - } } } @@ -175,8 +167,14 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { val kaptExtension = project.extensions.getByType(KaptExtension::class.java) - val context = Kapt3SubpluginContext(project, kotlinCompile, javaCompile, - kaptVariantData, sourceSetName, javaSourceSet, kaptExtension, kaptClasspath) + val nonEmptyKaptConfigurations = kaptConfigurations.filter { configuration -> + configuration.dependencies.any { it.group != getGroupName() || it.name != getArtifactName() } + } + + val context = Kapt3SubpluginContext( + project, kotlinCompile, javaCompile, + kaptVariantData, sourceSetName, javaSourceSet, kaptExtension, nonEmptyKaptConfigurations + ) val kaptGenerateStubsTask = context.createKaptGenerateStubsTask() val kaptTask = context.createKaptKotlinTask() @@ -208,8 +206,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { pluginOptions += SubpluginOption("aptMode", aptMode) disableAnnotationProcessingInJavaTask() - kaptClasspath.forEach { pluginOptions += FilesSubpluginOption("apclasspath", listOf(it)) } - javaCompile.source(generatedFilesDir) pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir)) @@ -246,7 +242,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { private fun Kapt3SubpluginContext.buildAndAddOptionsTo(task: Task, container: CompilerPluginOptions, aptMode: String) { val compilerPluginId = getCompilerPluginId() - val kaptSubpluginOptions = wrapPluginOptions(buildOptions(aptMode), "configuration") + val kaptSubpluginOptions = buildOptions(aptMode) task.registerSubpluginOptionsAsInputs(compilerPluginId, kaptSubpluginOptions) for (option in kaptSubpluginOptions) { @@ -320,7 +316,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { registerGeneratedJavaSource(kaptTask, javaCompile) } - kaptTask.kaptClasspath = kaptClasspath + kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations buildAndAddOptionsTo(kaptTask, kaptTask.pluginOptions, aptMode = "apt") @@ -344,7 +340,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { kaptTask.generatedSourcesDir = sourcesOutputDir mapKotlinTaskProperties(project, kaptTask) - kaptTask.kaptClasspath = kaptClasspath + kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations buildAndAddOptionsTo(kaptTask, kaptTask.pluginOptions, aptMode = "stubs") return kaptTask @@ -372,7 +368,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { } } - override fun getCompilerPluginId() = "org.jetbrains.kotlin.kapt3" + override fun getCompilerPluginId() = KAPT_SUBPLUGIN_ID override fun getGroupName() = KAPT_GROUP_NAME override fun getArtifactName() = KAPT_ARTIFACT_NAME } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptGenerateStubsTask.kt index f7d2b20cdc7..65be5eb088e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptGenerateStubsTask.kt @@ -17,11 +17,14 @@ package org.jetbrains.kotlin.gradle.internal import com.intellij.openapi.util.io.FileUtil +import org.gradle.api.artifacts.Configuration +import org.gradle.api.file.FileCollection import org.gradle.api.tasks.* import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.gradle.plugin.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.kotlinWarn +import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions import org.jetbrains.kotlin.gradle.tasks.FilteringSourceRootsContainer import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.incremental.ChangedFiles @@ -44,7 +47,11 @@ open class KaptGenerateStubsTask : KotlinCompile() { lateinit var generatedSourcesDir: File @get:Classpath @get:InputFiles - lateinit var kaptClasspath: List + val kaptClasspath: FileCollection + get() = project.files(*kaptClasspathConfigurations.toTypedArray()) + + @get:Internal + internal lateinit var kaptClasspathConfigurations: List @get:Classpath @get:InputFiles @Suppress("unused") internal val kotlinTaskPluginClasspath get() = kotlinCompileTask.pluginClasspath @@ -66,8 +73,12 @@ open class KaptGenerateStubsTask : KotlinCompile() { override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean) { kotlinCompileTask.setupCompilerArgs(args) + args.pluginClasspaths = (pluginClasspath + args.pluginClasspaths!!).toSet().toTypedArray() - args.pluginOptions = (pluginOptions.arguments + args.pluginOptions!!).toTypedArray() + + val pluginOptionsWithKapt = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath) + args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray() + args.verbose = project.hasProperty("kapt.verbose") && project.property("kapt.verbose").toString().toBoolean() == true args.classpathAsList = this.compileClasspath.toList() args.destinationAsFile = this.destinationDir diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt index cff75932ddb..2c9787808c9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.gradle.internal import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtil.compareVersionNumbers import org.gradle.api.GradleException +import org.gradle.api.artifacts.Configuration import org.gradle.api.file.FileCollection import org.gradle.api.internal.ConventionTask import org.gradle.api.tasks.* @@ -41,7 +42,11 @@ open class KaptTask : ConventionTask(), CompilerArgumentAwareWithInput + val kaptClasspath: FileCollection + get() = project.files(*kaptClasspathConfigurations.toTypedArray()) + + @get:Internal + internal lateinit var kaptClasspathConfigurations: List @get:OutputDirectory internal lateinit var classesDir: File @@ -58,7 +63,10 @@ open class KaptTask : ConventionTask(), CompilerArgumentAwareWithInput>): String { return Base64.getEncoder().encodeToString(os.toByteArray()) } +internal fun CompilerPluginOptions.withWrappedKaptOptions(withApClasspath: Iterable): CompilerPluginOptions { + val resultOptionsByPluginId: MutableMap> = + subpluginOptionsByPluginId.toMutableMap() + + resultOptionsByPluginId.compute(Kapt3KotlinGradleSubplugin.KAPT_SUBPLUGIN_ID) { _, kaptOptions -> + val kaptOptionsWithClasspath = + kaptOptions.orEmpty() + withApClasspath.map { FilesSubpluginOption("apclasspath", listOf(it)) } + + wrapPluginOptions(kaptOptionsWithClasspath, "configuration") + } + + val result = CompilerPluginOptions() + classpath.forEach { result.addClasspathEntry(File(it)) } + resultOptionsByPluginId.forEach { pluginId, options -> + options.forEach { option -> result.addPluginArgument(pluginId, option) } + } + return result +} + fun wrapPluginOptions(options: List, newOptionName: String): List { val groupedOptions = options.groupBy { it.key }.mapValues { opt -> opt.value.map { it.value } } val encodedOptions = encodePluginOptions(groupedOptions)