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
This commit is contained in:
Sergey Igushkin
2018-01-12 17:34:46 +03:00
parent 8ac95b54a2
commit e8cd8b566e
5 changed files with 81 additions and 31 deletions
@@ -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!")
}
}
}
@@ -80,6 +80,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
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<KotlinCompile> {
}
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<File>) {
val project: Project,
val kotlinCompile: KotlinCompile,
val javaCompile: AbstractCompile,
val kaptVariantData: KaptVariantData<*>?,
val sourceSetName: String,
val javaSourceSet: SourceSet?,
val kaptExtension: KaptExtension,
val kaptClasspathConfigurations: List<Configuration>
) {
val sourcesOutputDir = getKaptGeneratedSourcesDir(project, sourceSetName)
val kotlinSourcesOutputDir = getKaptGeneratedKotlinSourcesDir(project, sourceSetName)
val classesOutputDir = getKaptGeneratedClassesDir(project, sourceSetName)
@@ -137,23 +139,13 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
): List<SubpluginOption> {
assert((variantData != null) xor (javaSourceSet != null))
val kaptClasspath = arrayListOf<File>()
val buildDependencies = arrayListOf<TaskDependency>()
val kaptConfigurations = arrayListOf<Configuration>()
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<KotlinCompile> {
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<KotlinCompile> {
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<KotlinCompile> {
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<KotlinCompile> {
registerGeneratedJavaSource(kaptTask, javaCompile)
}
kaptTask.kaptClasspath = kaptClasspath
kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations
buildAndAddOptionsTo(kaptTask, kaptTask.pluginOptions, aptMode = "apt")
@@ -344,7 +340,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
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<KotlinCompile> {
}
}
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
}
@@ -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<File>
val kaptClasspath: FileCollection
get() = project.files(*kaptClasspathConfigurations.toTypedArray())
@get:Internal
internal lateinit var kaptClasspathConfigurations: List<Configuration>
@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
@@ -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<K2JVMComp
}
@get:Classpath @get:InputFiles
lateinit var kaptClasspath: List<File>
val kaptClasspath: FileCollection
get() = project.files(*kaptClasspathConfigurations.toTypedArray())
@get:Internal
internal lateinit var kaptClasspathConfigurations: List<Configuration>
@get:OutputDirectory
internal lateinit var classesDir: File
@@ -58,7 +63,10 @@ open class KaptTask : ConventionTask(), CompilerArgumentAwareWithInput<K2JVMComp
kotlinCompileTask.setupCompilerArgs(args)
args.pluginClasspaths = (pluginClasspath + args.pluginClasspaths!!).toSet().toTypedArray()
args.pluginOptions = (pluginOptions.arguments + args.pluginOptions!!).toTypedArray()
val pluginOptionsWithKapt: CompilerPluginOptions = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath)
args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray()
args.verbose = project.hasProperty("kapt.verbose") && project.property("kapt.verbose").toString().toBoolean() == true
}
@@ -18,7 +18,10 @@ package org.jetbrains.kotlin.gradle.internal
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import org.jetbrains.kotlin.gradle.plugin.CompositeSubpluginOption
import org.jetbrains.kotlin.gradle.plugin.FilesSubpluginOption
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream
import java.util.*
@@ -40,6 +43,25 @@ fun encodePluginOptions(options: Map<String, List<String>>): String {
return Base64.getEncoder().encodeToString(os.toByteArray())
}
internal fun CompilerPluginOptions.withWrappedKaptOptions(withApClasspath: Iterable<File>): CompilerPluginOptions {
val resultOptionsByPluginId: MutableMap<String, List<SubpluginOption>> =
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<SubpluginOption>, newOptionName: String): List<SubpluginOption> {
val groupedOptions = options.groupBy { it.key }.mapValues { opt -> opt.value.map { it.value } }
val encodedOptions = encodePluginOptions(groupedOptions)