[Gradle] Introduce classes to configure KAPT tasks

Avoid storing references to KotlinCompile task and use lazy properties
to configure task. Values are kept in-sync with the
Kotlin compile task (for the stub generation) using this mechanism.
This commit is contained in:
Ivan Gavrilovic
2021-04-26 17:34:43 +01:00
committed by teamcityserver
parent 01dd15cc3e
commit 0882da1788
4 changed files with 149 additions and 124 deletions
@@ -16,65 +16,75 @@
package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.FilteringSourceRootsContainer
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.SourceRoots
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.isParentOf
import org.jetbrains.kotlin.incremental.classpathAsList
import org.jetbrains.kotlin.incremental.destinationAsFile
import java.io.File
import javax.inject.Inject
import java.util.concurrent.Callable
@CacheableTask
open class KaptGenerateStubsTask @Inject constructor(
objectFactory: ObjectFactory
) : KotlinCompile() {
abstract class KaptGenerateStubsTask : KotlinCompile() {
class Configurator(private val kotlinCompileTask: KotlinCompile, kotlinCompilation: KotlinCompilationData<*>) :
AbstractKotlinCompile.Configurator<KaptGenerateStubsTask>(kotlinCompilation) {
override fun configure(task: KaptGenerateStubsTask) {
super.configure(task)
val providerFactory = kotlinCompileTask.project.providers
task.useModuleDetection.value(kotlinCompileTask.useModuleDetection).disallowChanges()
task.moduleName.value(kotlinCompileTask.moduleName).disallowChanges()
task.classpath = task.project.files(Callable { kotlinCompileTask.classpath })
task.kotlinTaskPluginClasspath.from(
providerFactory.provider { kotlinCompileTask.pluginClasspath }
)
task.compileKotlinArgumentsContributor.set(
providerFactory.provider {
kotlinCompileTask.compilerArgumentsContributor
}
)
task.jvmSourceRoots.set(
providerFactory.provider {
kotlinCompileTask.getSourceRoots().let { compileTaskSourceRoots ->
SourceRoots.ForJvm(
compileTaskSourceRoots.kotlinSourceFiles.filterTo(mutableListOf()) { task.isSourceRootAllowed(it) },
javaSourceRootsProvider = { compileTaskSourceRoots.javaSourceRoots.filterTo(mutableSetOf()) { task.isSourceRootAllowed(it) } }
)
}
}
)
task.kotlinOptionsProperty.value(KotlinJvmOptionsImpl()).disallowChanges()
}
}
@field:Transient
override val sourceRootsContainer = FilteringSourceRootsContainer(objectFactory, { isSourceRootAllowed(it) })
override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsImpl()
@get:Internal
@field:Transient // can't serialize task references in Gradle instant execution state
internal lateinit var kotlinCompileTask: KotlinCompile
override val sourceRootsContainer = FilteringSourceRootsContainer(objects, { isSourceRootAllowed(it) })
@get:OutputDirectory
val stubsDir: DirectoryProperty = objectFactory.directoryProperty()
abstract val stubsDir: DirectoryProperty
@get:Internal
lateinit var generatedSourcesDirs: List<File>
@get:Classpath
@get:InputFiles
val kaptClasspath: FileCollection
get() = objects.fileCollection().from(kaptClasspathConfigurations)
@get:Internal
internal lateinit var kaptClasspathConfigurations: List<Configuration>
abstract val kaptClasspath: ConfigurableFileCollection
@get:Classpath
@get:InputFiles
@Suppress("unused")
internal val kotlinTaskPluginClasspath by project.provider {
kotlinCompileTask.pluginClasspath
}
@get:Input
override var useModuleDetection: Boolean
get() = super.useModuleDetection
set(_) {
error("KaptGenerateStubsTask.useModuleDetection setter should not be called!")
}
internal abstract val kotlinTaskPluginClasspath: ConfigurableFileCollection
@get:Input
val verbose = (project.hasProperty("kapt.verbose") && project.property("kapt.verbose").toString().toBoolean() == true)
@@ -92,12 +102,11 @@ open class KaptGenerateStubsTask @Inject constructor(
!stubsDir.asFile.get().isParentOf(source) &&
generatedSourcesDirs.none { it.isParentOf(source) }
private val compileKotlinArgumentsContributor by project.provider {
kotlinCompileTask.compilerArgumentsContributor
}
@get:Internal
internal abstract val compileKotlinArgumentsContributor: Property<CompilerArgumentsContributor<K2JVMCompilerArguments>>
override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) {
compileKotlinArgumentsContributor.contributeArguments(args, compilerArgumentsConfigurationFlags(
compileKotlinArgumentsContributor.get().contributeArguments(args, compilerArgumentsConfigurationFlags(
defaultsOnly,
ignoreClasspathResolutionErrors
))
@@ -106,18 +115,12 @@ open class KaptGenerateStubsTask @Inject constructor(
args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray()
args.verbose = verbose
args.classpathAsList = this.compileClasspath.filter { it.exists() }.toList()
args.classpathAsList = this.classpath.filter { it.exists() }.toList()
args.destinationAsFile = this.destinationDir
}
private val sourceRoots by project.provider {
kotlinCompileTask.getSourceRoots().let { compileTaskSourceRoots ->
SourceRoots.ForJvm(
compileTaskSourceRoots.kotlinSourceFiles.filterTo(mutableListOf()) { isSourceRootAllowed(it) },
javaSourceRootsProvider = { compileTaskSourceRoots.javaSourceRoots.filterTo(mutableSetOf()) { isSourceRootAllowed(it) } }
)
}
}
@get:Internal
internal abstract val jvmSourceRoots: Property<SourceRoots.ForJvm>
override fun getSourceRoots(): SourceRoots.ForJvm = sourceRoots
override fun getSourceRoots(): SourceRoots.ForJvm = jvmSourceRoots.get()
}
@@ -4,8 +4,9 @@ import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.ConventionTask
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
@@ -14,19 +15,47 @@ import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptClasspathChanges
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.UnknownSnapshot
import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.cacheOnlyIfEnabledForKotlin
import org.jetbrains.kotlin.gradle.tasks.clearLocalState
import org.jetbrains.kotlin.gradle.utils.getValue
import java.io.File
import java.util.concurrent.Callable
import java.util.jar.JarFile
import javax.inject.Inject
@CacheableTask
abstract class KaptTask @Inject constructor(
objectFactory: ObjectFactory
@get:Internal
protected val providerFactory: ProviderFactory
): ConventionTask(), TaskWithLocalState {
open class Configurator<T: KaptTask>(protected val kotlinCompileTask: KotlinCompile) : TaskConfigurator<T> {
override fun configure(task: T) {
val objectFactory = task.project.objects
val providerFactory = task.project.providers
task.compilerClasspath.from({ kotlinCompileTask.computedCompilerClasspath })
task.classpath.from(kotlinCompileTask.classpath)
task.kotlinSourceRoots.value(
providerFactory.provider { kotlinCompileTask.sourceRootsContainer.sourceRoots }
).disallowChanges()
task.compiledSources.from(
kotlinCompileTask.destinationDirectory,
Callable { kotlinCompileTask.javaOutputDir.takeIf { it.isPresent } }
).disallowChanges()
task.sourceSetName.value(kotlinCompileTask.sourceSetName).disallowChanges()
task.localStateDirectories.from(Callable { task.incAptCache.orNull }).disallowChanges()
task.source.from(
objectFactory.fileCollection().from(task.kotlinSourceRoots, task.stubsDir).asFileTree
.matching { it.include("**/*.java") }
.filter { f -> task.isRootAllowed(f) }
).disallowChanges()
}
}
init {
cacheOnlyIfEnabledForKotlin()
@@ -34,19 +63,8 @@ abstract class KaptTask @Inject constructor(
outputs.cacheIf(reason) { useBuildCache }
}
override fun localStateDirectories(): FileCollection = objects
.fileCollection()
.from({ incAptCache.orNull })
@get:Internal
@field:Transient
internal lateinit var kotlinCompileTask: KotlinCompile
@get:Internal
internal val stubsDir: DirectoryProperty = objectFactory.directoryProperty()
@get:Internal
internal val objects = project.objects
internal abstract val stubsDir: DirectoryProperty
@get:Classpath
@get:InputFiles
@@ -60,7 +78,7 @@ abstract class KaptTask @Inject constructor(
@get:Classpath
@get:InputFiles
val compilerClasspath: FileCollection = objects.fileCollection().from({ kotlinCompileTask.computedCompilerClasspath })
abstract val compilerClasspath: ConfigurableFileCollection
@get:Internal
internal abstract val kaptClasspathConfigurationNames: ListProperty<String>
@@ -69,15 +87,13 @@ abstract class KaptTask @Inject constructor(
@get:PathSensitive(PathSensitivity.NONE)
@get:Optional
@get:InputFiles
internal var classpathStructure: FileCollection? = null
abstract val classpathStructure: ConfigurableFileCollection
/**
* Output directory that contains caches necessary to support incremental annotation processing.
* [LocalState] should be used here, but in order to be compatible with Gradle 4.2, correct input
* annotations are specified during task configuration.
*/
@get:Internal
val incAptCache: DirectoryProperty = objectFactory.directoryProperty()
@get:LocalState
abstract val incAptCache: DirectoryProperty
@get:OutputDirectory
internal lateinit var classesDir: File
@@ -99,9 +115,7 @@ abstract class KaptTask @Inject constructor(
// @Internal because _abiClasspath and _nonAbiClasspath are used for actual checks
@get:Internal
val classpath: FileCollection by project.provider {
kotlinCompileTask.classpath
}
abstract val classpath: ConfigurableFileCollection
@Suppress("unused", "DeprecatedCallableAddReplaceWith")
@Deprecated(
@@ -111,7 +125,7 @@ abstract class KaptTask @Inject constructor(
@get:CompileClasspath
@get:InputFiles
internal val internalAbiClasspath: FileCollection by project.provider {
if (includeCompileClasspath) project.files() else kotlinCompileTask.classpath
if (includeCompileClasspath) project.files() else classpath
}
@@ -123,29 +137,22 @@ abstract class KaptTask @Inject constructor(
@get:Classpath
@get:InputFiles
internal val internalNonAbiClasspath: FileCollection by project.provider {
if (includeCompileClasspath) kotlinCompileTask.classpath else project.files()
if (includeCompileClasspath) classpath else project.files()
}
@get:Internal
var useBuildCache: Boolean = false
private val sourceRootsFromKotlinTask by project.provider {
kotlinCompileTask.sourceRootsContainer.sourceRoots
}
@get:Internal
abstract val kotlinSourceRoots: ListProperty<File>
/** Needed for the model builder. */
@get:Internal
abstract val sourceSetName: Property<String>
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
val source: FileCollection = objectFactory
.fileCollection()
.from(
{ sourceRootsFromKotlinTask },
stubsDir
)
.asFileTree
.matching {
it.include("**/*.java")
}
.filter(::isRootAllowed)
abstract val source: ConfigurableFileCollection
@get:Internal
override val metrics: BuildMetricsReporter =
@@ -183,10 +190,6 @@ abstract class KaptTask @Inject constructor(
}
}
private fun FileCollection?.orEmpty(): FileCollection =
this ?: project.files()
protected fun checkAnnotationProcessorClasspath() {
if (!includeCompileClasspath) return
@@ -218,9 +221,7 @@ abstract class KaptTask @Inject constructor(
// TODO(gavra): Here we assume that kotlinc and javac output is available for incremental runs. We should insert some checks.
@get:Internal
internal val compiledSources by project.provider {
listOfNotNull(kotlinCompileTask.destinationDir, kotlinCompileTask.javaOutputDir)
}
internal abstract val compiledSources: ConfigurableFileCollection
protected fun getIncrementalChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges {
return if (isIncremental) {
@@ -235,7 +236,7 @@ abstract class KaptTask @Inject constructor(
val incAptCacheDir = incAptCache.asFile.get()
incAptCacheDir.mkdirs()
val allDataFiles = classpathStructure!!.files
val allDataFiles = classpathStructure.files
val changedFiles = if (inputs.isIncremental) {
with(mutableSetOf<File>()) {
inputs.outOfDate { this.add(it.file) }
@@ -5,8 +5,10 @@
package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.file.FileCollection
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
@@ -18,40 +20,52 @@ import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChan
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.report.ReportingSettings
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.optionalProvider
import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray
import java.io.File
import javax.inject.Inject
abstract class KaptWithKotlincTask @Inject constructor(
objectFactory: ObjectFactory
) : KaptTask(objectFactory),
objectFactory: ObjectFactory,
providerFactory: ProviderFactory
) : KaptTask(providerFactory),
CompilerArgumentAwareWithInput<K2JVMCompilerArguments>,
UsesKotlinJavaToolchain {
UsesKotlinJavaToolchain{
class Configurator(kotlinCompileTask: KotlinCompile): KaptTask.Configurator<KaptWithKotlincTask>(kotlinCompileTask) {
override fun configure(task: KaptWithKotlincTask) {
super.configure(task)
task.pluginClasspath.from(kotlinCompileTask.pluginClasspath)
task.compileKotlinArgumentsContributor.set(
task.project.provider { kotlinCompileTask.compilerArgumentsContributor }
)
task.javaPackagePrefix.set(task.project.provider { kotlinCompileTask.javaPackagePrefix })
task.reportingSettings.set(task.project.provider { kotlinCompileTask.reportingSettings })
}
}
@get:Internal
internal val pluginOptions = CompilerPluginOptions()
@get:Classpath
@get:InputFiles
val pluginClasspath: FileCollection get() = kotlinCompileTask.pluginClasspath
abstract val pluginClasspath: ConfigurableFileCollection
@get:Internal
val taskProvider = GradleCompileTaskProvider(this)
val taskProvider by lazy { GradleCompileTaskProvider(this) }
final override val kotlinJavaToolchainProvider: Provider<KotlinJavaToolchainProvider> =
objectFactory.propertyWithNewInstance()
override fun createCompilerArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments()
private val compileKotlinArgumentsContributor by project.provider {
kotlinCompileTask.compilerArgumentsContributor
}
@get:Internal
internal abstract val compileKotlinArgumentsContributor: Property<CompilerArgumentsContributor<K2JVMCompilerArguments>>
override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) {
compileKotlinArgumentsContributor.contributeArguments(
compileKotlinArgumentsContributor.get().contributeArguments(
args, compilerArgumentsConfigurationFlags(
defaultsOnly,
ignoreClasspathResolutionErrors
@@ -63,7 +77,7 @@ abstract class KaptWithKotlincTask @Inject constructor(
withApClasspath = kaptClasspath,
changedFiles = changedFiles,
classpathChanges = classpathChanges,
compiledSourcesDir = compiledSources,
compiledSourcesDir = compiledSources.toList(),
processIncrementally = processIncrementally
)
@@ -80,8 +94,8 @@ abstract class KaptWithKotlincTask @Inject constructor(
private var classpathChanges: List<String> = emptyList()
private var processIncrementally = false
private val javaPackagePrefix by project.optionalProvider { kotlinCompileTask.javaPackagePrefix }
private val reportingSettings by project.provider { kotlinCompileTask.reportingSettings }
private val javaPackagePrefix = objectFactory.property(String::class.java)
private val reportingSettings = objectFactory.property(ReportingSettings::class.java)
@TaskAction
fun compile(inputs: IncrementalTaskInputs) {
@@ -100,8 +114,8 @@ abstract class KaptWithKotlincTask @Inject constructor(
val messageCollector = GradlePrintingMessageCollector(GradleKotlinLogger(logger), args.allWarningsAsErrors)
val outputItemCollector = OutputItemsCollectorImpl()
val environment = GradleCompilerEnvironment(
compilerClasspath, messageCollector, outputItemCollector,
reportingSettings = reportingSettings,
compilerClasspath.files.toList(), messageCollector, outputItemCollector,
reportingSettings = reportingSettings.get(),
outputFiles = allOutputFiles()
)
@@ -114,7 +128,7 @@ abstract class KaptWithKotlincTask @Inject constructor(
sourcesToCompile = emptyList(),
commonSources = emptyList(),
javaSourceRoots = source.files,
javaPackagePrefix = javaPackagePrefix,
javaPackagePrefix = javaPackagePrefix.orNull,
args = args,
environment = environment
)
@@ -6,8 +6,8 @@
package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.gradle.process.CommandLineArgumentProvider
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.rootOrSelf
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.findKotlinStdlibClasspath
import org.jetbrains.kotlin.gradle.tasks.findToolsJar
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
@@ -33,15 +34,24 @@ import java.net.URLClassLoader
import javax.inject.Inject
abstract class KaptWithoutKotlincTask @Inject constructor(
objectFactory: ObjectFactory,
providerFactory: ProviderFactory,
private val workerExecutor: WorkerExecutor
) : KaptTask(objectFactory) {
) : KaptTask(providerFactory) {
class Configurator(kotlinCompileTask: KotlinCompile): KaptTask.Configurator<KaptWithoutKotlincTask>(kotlinCompileTask) {
override fun configure(task: KaptWithoutKotlincTask) {
super.configure(task)
task.addJdkClassesToClasspath.value(
task.project.providers.provider { task.project.plugins.none { it is KotlinAndroidPluginWrapper } }
).disallowChanges()
task.kaptJars.from(task.project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)).disallowChanges()
}
}
@get:InputFiles
@get:Classpath
@Suppress("unused")
val kaptJars: Collection<File> by lazy {
project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).resolve()
}
abstract val kaptJars: ConfigurableFileCollection
@get:Input
var isVerbose: Boolean = false
@@ -65,7 +75,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
lateinit var javacOptions: Map<String, String>
@get:Input
internal val kotlinAndroidPluginWrapperPluginDoesNotExist = project.plugins.none { it is KotlinAndroidPluginWrapper }
internal abstract val addJdkClassesToClasspath: Property<Boolean>
@get:Classpath
internal val kotlinStdlibClasspath = findKotlinStdlibClasspath(project)
@@ -73,9 +83,6 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
@get:Internal
internal val projectDir = project.projectDir
@get:Internal
internal val providers = project.providers
private fun getAnnotationProcessorOptions(): Map<String, String> {
val options = processorOptions.subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID] ?: return emptyMap()
@@ -106,7 +113,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
}
val compileClasspath = classpath.files.toMutableList()
if (kotlinAndroidPluginWrapperPluginDoesNotExist) {
if (addJdkClassesToClasspath.get()) {
compileClasspath.addAll(0, PathUtil.getJdkClassesRootsFromCurrentJre())
}
@@ -123,7 +130,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
source.files.toList(),
changedFiles,
compiledSources,
compiledSources.toList(),
incAptCache.orNull?.asFile,
classpathChanges.toList(),
@@ -149,7 +156,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
return
}
val kaptClasspath = kaptJars + kotlinStdlibClasspath
val kaptClasspath = kaptJars.toList() + kotlinStdlibClasspath
//TODO for gradle < 6.5
val isolationModeStr = getValue("kapt.workers.isolation") ?: "none"
@@ -201,7 +208,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
internal fun getValue(propertyName: String): String? =
if (isGradleVersionAtLeast(6, 5)) {
providers.gradleProperty(propertyName).forUseAtConfigurationTime().orNull
providerFactory.gradleProperty(propertyName).forUseAtConfigurationTime().orNull
} else {
project.findProperty(propertyName) as String?
}