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") 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_GROUP_NAME = "org.jetbrains.kotlin"
val KAPT_ARTIFACT_NAME = "kotlin-annotation-processing-gradle" val KAPT_ARTIFACT_NAME = "kotlin-annotation-processing-gradle"
val KAPT_SUBPLUGIN_ID = "org.jetbrains.kotlin.kapt3"
fun getKaptConfigurationName(sourceSetName: String): String { fun getKaptConfigurationName(sourceSetName: String): String {
return if (sourceSetName != "main") return if (sourceSetName != "main")
@@ -110,14 +111,15 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
} }
private inner class Kapt3SubpluginContext( private inner class Kapt3SubpluginContext(
val project: Project, val project: Project,
val kotlinCompile: KotlinCompile, val kotlinCompile: KotlinCompile,
val javaCompile: AbstractCompile, val javaCompile: AbstractCompile,
val kaptVariantData: KaptVariantData<*>?, val kaptVariantData: KaptVariantData<*>?,
val sourceSetName: String, val sourceSetName: String,
val javaSourceSet: SourceSet?, val javaSourceSet: SourceSet?,
val kaptExtension: KaptExtension, val kaptExtension: KaptExtension,
val kaptClasspath: MutableList<File>) { val kaptClasspathConfigurations: List<Configuration>
) {
val sourcesOutputDir = getKaptGeneratedSourcesDir(project, sourceSetName) val sourcesOutputDir = getKaptGeneratedSourcesDir(project, sourceSetName)
val kotlinSourcesOutputDir = getKaptGeneratedKotlinSourcesDir(project, sourceSetName) val kotlinSourcesOutputDir = getKaptGeneratedKotlinSourcesDir(project, sourceSetName)
val classesOutputDir = getKaptGeneratedClassesDir(project, sourceSetName) val classesOutputDir = getKaptGeneratedClassesDir(project, sourceSetName)
@@ -137,23 +139,13 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
): List<SubpluginOption> { ): List<SubpluginOption> {
assert((variantData != null) xor (javaSourceSet != null)) assert((variantData != null) xor (javaSourceSet != null))
val kaptClasspath = arrayListOf<File>()
val buildDependencies = arrayListOf<TaskDependency>() val buildDependencies = arrayListOf<TaskDependency>()
val kaptConfigurations = arrayListOf<Configuration>() val kaptConfigurations = arrayListOf<Configuration>()
fun handleSourceSet(sourceSetName: String) { fun handleSourceSet(sourceSetName: String) {
val kaptConfiguration = project.findKaptConfiguration(sourceSetName) project.findKaptConfiguration(sourceSetName)?.let { kaptConfiguration ->
val filteredDependencies = kaptConfiguration?.dependencies?.filter {
it.group != getGroupName() || it.name != getArtifactName()
} ?: emptyList()
if (kaptConfiguration != null) {
kaptConfigurations += kaptConfiguration kaptConfigurations += kaptConfiguration
buildDependencies += kaptConfiguration.buildDependencies 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 kaptExtension = project.extensions.getByType(KaptExtension::class.java)
val context = Kapt3SubpluginContext(project, kotlinCompile, javaCompile, val nonEmptyKaptConfigurations = kaptConfigurations.filter { configuration ->
kaptVariantData, sourceSetName, javaSourceSet, kaptExtension, kaptClasspath) 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 kaptGenerateStubsTask = context.createKaptGenerateStubsTask()
val kaptTask = context.createKaptKotlinTask() val kaptTask = context.createKaptKotlinTask()
@@ -208,8 +206,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
pluginOptions += SubpluginOption("aptMode", aptMode) pluginOptions += SubpluginOption("aptMode", aptMode)
disableAnnotationProcessingInJavaTask() disableAnnotationProcessingInJavaTask()
kaptClasspath.forEach { pluginOptions += FilesSubpluginOption("apclasspath", listOf(it)) }
javaCompile.source(generatedFilesDir) javaCompile.source(generatedFilesDir)
pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir)) pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir))
@@ -246,7 +242,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
private fun Kapt3SubpluginContext.buildAndAddOptionsTo(task: Task, container: CompilerPluginOptions, aptMode: String) { private fun Kapt3SubpluginContext.buildAndAddOptionsTo(task: Task, container: CompilerPluginOptions, aptMode: String) {
val compilerPluginId = getCompilerPluginId() val compilerPluginId = getCompilerPluginId()
val kaptSubpluginOptions = wrapPluginOptions(buildOptions(aptMode), "configuration") val kaptSubpluginOptions = buildOptions(aptMode)
task.registerSubpluginOptionsAsInputs(compilerPluginId, kaptSubpluginOptions) task.registerSubpluginOptionsAsInputs(compilerPluginId, kaptSubpluginOptions)
for (option in kaptSubpluginOptions) { for (option in kaptSubpluginOptions) {
@@ -320,7 +316,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
registerGeneratedJavaSource(kaptTask, javaCompile) registerGeneratedJavaSource(kaptTask, javaCompile)
} }
kaptTask.kaptClasspath = kaptClasspath kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations
buildAndAddOptionsTo(kaptTask, kaptTask.pluginOptions, aptMode = "apt") buildAndAddOptionsTo(kaptTask, kaptTask.pluginOptions, aptMode = "apt")
@@ -344,7 +340,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
kaptTask.generatedSourcesDir = sourcesOutputDir kaptTask.generatedSourcesDir = sourcesOutputDir
mapKotlinTaskProperties(project, kaptTask) mapKotlinTaskProperties(project, kaptTask)
kaptTask.kaptClasspath = kaptClasspath kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations
buildAndAddOptionsTo(kaptTask, kaptTask.pluginOptions, aptMode = "stubs") buildAndAddOptionsTo(kaptTask, kaptTask.pluginOptions, aptMode = "stubs")
return kaptTask 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 getGroupName() = KAPT_GROUP_NAME
override fun getArtifactName() = KAPT_ARTIFACT_NAME override fun getArtifactName() = KAPT_ARTIFACT_NAME
} }
@@ -17,11 +17,14 @@
package org.jetbrains.kotlin.gradle.internal package org.jetbrains.kotlin.gradle.internal
import com.intellij.openapi.util.io.FileUtil 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.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.kotlinWarn 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.FilteringSourceRootsContainer
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.incremental.ChangedFiles import org.jetbrains.kotlin.incremental.ChangedFiles
@@ -44,7 +47,11 @@ open class KaptGenerateStubsTask : KotlinCompile() {
lateinit var generatedSourcesDir: File lateinit var generatedSourcesDir: File
@get:Classpath @get:InputFiles @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") @get:Classpath @get:InputFiles @Suppress("unused")
internal val kotlinTaskPluginClasspath get() = kotlinCompileTask.pluginClasspath internal val kotlinTaskPluginClasspath get() = kotlinCompileTask.pluginClasspath
@@ -66,8 +73,12 @@ open class KaptGenerateStubsTask : KotlinCompile() {
override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean) { override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean) {
kotlinCompileTask.setupCompilerArgs(args) kotlinCompileTask.setupCompilerArgs(args)
args.pluginClasspaths = (pluginClasspath + args.pluginClasspaths!!).toSet().toTypedArray() 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.verbose = project.hasProperty("kapt.verbose") && project.property("kapt.verbose").toString().toBoolean() == true
args.classpathAsList = this.compileClasspath.toList() args.classpathAsList = this.compileClasspath.toList()
args.destinationAsFile = this.destinationDir 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.io.FileUtil
import com.intellij.openapi.util.text.StringUtil.compareVersionNumbers import com.intellij.openapi.util.text.StringUtil.compareVersionNumbers
import org.gradle.api.GradleException import org.gradle.api.GradleException
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.internal.ConventionTask import org.gradle.api.internal.ConventionTask
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
@@ -41,7 +42,11 @@ open class KaptTask : ConventionTask(), CompilerArgumentAwareWithInput<K2JVMComp
} }
@get:Classpath @get:InputFiles @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 @get:OutputDirectory
internal lateinit var classesDir: File internal lateinit var classesDir: File
@@ -58,7 +63,10 @@ open class KaptTask : ConventionTask(), CompilerArgumentAwareWithInput<K2JVMComp
kotlinCompileTask.setupCompilerArgs(args) kotlinCompileTask.setupCompilerArgs(args)
args.pluginClasspaths = (pluginClasspath + args.pluginClasspaths!!).toSet().toTypedArray() 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 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.SubpluginOption
import org.jetbrains.kotlin.gradle.plugin.CompositeSubpluginOption 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.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream import java.io.ObjectOutputStream
import java.util.* import java.util.*
@@ -40,6 +43,25 @@ fun encodePluginOptions(options: Map<String, List<String>>): String {
return Base64.getEncoder().encodeToString(os.toByteArray()) 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> { fun wrapPluginOptions(options: List<SubpluginOption>, newOptionName: String): List<SubpluginOption> {
val groupedOptions = options.groupBy { it.key }.mapValues { opt -> opt.value.map { it.value } } val groupedOptions = options.groupBy { it.key }.mapValues { opt -> opt.value.map { it.value } }
val encodedOptions = encodePluginOptions(groupedOptions) val encodedOptions = encodePluginOptions(groupedOptions)