[Gradle] Move more task inputs to properties

... move more configuration logic to TaskConfigAction classes. This is
to avoid directly accessing tasks to configure them. The TaskConfigAction
objects should eventually have access to all information that is required
to configure the task, and they should compute the final values of
all properties.

This will also allow 3P plugins to configure Kotlin tasks, without
the need to create KGP internal objects.

^KT-50869 In Progress
This commit is contained in:
Ivan Gavrilovic
2022-02-21 11:47:35 +00:00
committed by Space
parent d908eb6e84
commit 46cb4902e1
26 changed files with 1060 additions and 957 deletions
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Internal
import java.io.File import java.io.File
open class SubpluginOption(val key: String, private val lazyValue: Lazy<String>) { open class SubpluginOption(val key: String, private val lazyValue: Lazy<String>) {
@@ -64,6 +65,7 @@ open class InternalSubpluginOption(key: String, value: String) : SubpluginOption
/** Keeps one or more compiler options for one of more compiler plugins. */ /** Keeps one or more compiler options for one of more compiler plugins. */
open class CompilerPluginConfig { open class CompilerPluginConfig {
@get:Internal
protected val optionsByPluginId = mutableMapOf<String, MutableList<SubpluginOption>>() protected val optionsByPluginId = mutableMapOf<String, MutableList<SubpluginOption>>()
fun allOptions(): Map<String, List<SubpluginOption>> = optionsByPluginId fun allOptions(): Map<String, List<SubpluginOption>> = optionsByPluginId
@@ -9,13 +9,10 @@ import com.android.build.gradle.BaseExtension
import com.android.build.gradle.api.AndroidSourceSet import com.android.build.gradle.api.AndroidSourceSet
import com.android.build.gradle.api.BaseVariant import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.SourceKind import com.android.build.gradle.api.SourceKind
import com.intellij.openapi.util.SystemInfo
import com.intellij.util.lang.JavaVersion
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ExternalDependency import org.gradle.api.artifacts.ExternalDependency
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.Usage import org.gradle.api.attributes.Usage
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
@@ -24,21 +21,20 @@ import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.process.CommandLineArgumentProvider import org.gradle.process.CommandLineArgumentProvider
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isInfoAsWarnings
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKaptKeepKdocCommentsInStubs
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKaptVerbose
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformAction
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction
import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.configuration.*
import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
import java.io.ObjectOutputStream import java.io.ObjectOutputStream
@@ -53,17 +49,6 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
override fun apply(target: Project) { override fun apply(target: Project) {
target.extensions.create("kapt", KaptExtension::class.java) target.extensions.create("kapt", KaptExtension::class.java)
target.configurations.create(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply {
val kaptDependency = getPluginArtifact().run { "$groupId:$artifactId:${target.getKotlinPluginVersion()}" }
dependencies.add(target.dependencies.create(kaptDependency))
dependencies.add(
target.kotlinDependency(
"kotlin-stdlib",
target.kotlinExtension.coreLibrariesVersion
)
)
}
registry.register(KaptModelBuilder()) registry.register(KaptModelBuilder())
} }
@@ -82,7 +67,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
const val KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME = "kotlinKaptWorkerDependencies" const val KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME = "kotlinKaptWorkerDependencies"
private val KAPT_KOTLIN_GENERATED = "kapt.kotlin.generated" val KAPT_KOTLIN_GENERATED = "kapt.kotlin.generated"
private val CLASSLOADERS_CACHE_SIZE = "kapt.classloaders.cache.size" private val CLASSLOADERS_CACHE_SIZE = "kapt.classloaders.cache.size"
private val CLASSLOADERS_CACHE_DISABLE_FOR_PROCESSORS = "kapt.classloaders.cache.disableForProcessors" private val CLASSLOADERS_CACHE_DISABLE_FOR_PROCESSORS = "kapt.classloaders.cache.disableForProcessors"
@@ -245,6 +230,8 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
private fun Kapt3SubpluginContext.getKaptIncrementalDataDir() = temporaryKaptDirectory("incrementalData") private fun Kapt3SubpluginContext.getKaptIncrementalDataDir() = temporaryKaptDirectory("incrementalData")
private fun Kapt3SubpluginContext.getKaptClasspathSnapshotDir() = temporaryKaptDirectory("classpath-snapshot")
private fun Kapt3SubpluginContext.getKaptIncrementalAnnotationProcessingCache() = temporaryKaptDirectory("incApCache") private fun Kapt3SubpluginContext.getKaptIncrementalAnnotationProcessingCache() = temporaryKaptDirectory("incApCache")
private fun Kapt3SubpluginContext.temporaryKaptDirectory( private fun Kapt3SubpluginContext.temporaryKaptDirectory(
@@ -326,7 +313,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
Callable { Callable {
// Avoid circular dependency: the stubs task need the Java sources, but the Java sources generated by Kapt should be // Avoid circular dependency: the stubs task need the Java sources, but the Java sources generated by Kapt should be
// excluded, as the Kapt tasks depend on the stubs ones, and having them in the input would lead to a cycle // excluded, as the Kapt tasks depend on the stubs ones, and having them in the input would lead to a cycle
val kaptJavaOutput = kaptTaskProvider.get().destinationDir val kaptJavaOutput = kaptTaskProvider.get().destinationDir.get().asFile
androidVariantData.getSourceFolders(SourceKind.JAVA).filter { it.dir != kaptJavaOutput } androidVariantData.getSourceFolders(SourceKind.JAVA).filter { it.dir != kaptJavaOutput }
} }
) )
@@ -343,42 +330,21 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
} }
// This method should be called no more than once for each Kapt3SubpluginContext // This method should be called no more than once for each Kapt3SubpluginContext
private fun Kapt3SubpluginContext.buildOptions( private fun Kapt3SubpluginContext.buildOptionsForAptMode(
aptMode: String,
javacOptions: Provider<Map<String, String>> javacOptions: Provider<Map<String, String>>
): Provider<List<SubpluginOption>> { ): Provider<List<SubpluginOption>> {
disableAnnotationProcessingInJavaTask()
return project.provider { return project.provider {
val pluginOptions = mutableListOf<SubpluginOption>() buildKaptSubpluginOptions(
kaptExtension,
val generatedFilesDir = getKaptGeneratedSourcesDir(project, sourceSetName) project,
KaptWithAndroid.androidVariantData(this)?.addJavaSourceFoldersToModel(generatedFilesDir) javacOptions.get(),
"apt",
pluginOptions += SubpluginOption("aptMode", aptMode) generatedSourcesDir = listOf(sourcesOutputDir),
generatedClassesDir = listOf(getKaptGeneratedClassesDir(project, sourceSetName)),
pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir)) incrementalDataDir = listOf(getKaptIncrementalDataDir()),
pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName))) includeCompileClasspath = includeCompileClasspath,
kaptStubsDir = listOf(getKaptStubsDir())
pluginOptions += FilesSubpluginOption("incrementalData", listOf(getKaptIncrementalDataDir())) ) + getAPOptions().get() // apOptions are needed only for "apt" mode
val annotationProcessors = kaptExtension.processors
if (annotationProcessors.isNotEmpty()) {
pluginOptions += SubpluginOption("processors", annotationProcessors)
}
if (aptMode == "apt") {
// apOptions are needed only for "apt" mode
pluginOptions += getAPOptions().get()
}
pluginOptions += SubpluginOption("javacArguments", encodeList(javacOptions.get()))
pluginOptions += SubpluginOption("includeCompileClasspath", includeCompileClasspath.toString())
addMiscOptions(pluginOptions)
pluginOptions
} }
} }
@@ -425,96 +391,14 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
FilesSubpluginOption(KAPT_KOTLIN_GENERATED, listOf(kotlinSourcesOutputDir)) FilesSubpluginOption(KAPT_KOTLIN_GENERATED, listOf(kotlinSourcesOutputDir))
} }
private fun Kapt3SubpluginContext.registerSubpluginOptions(
taskProvider: TaskProvider<*>,
optionsProvider: Provider<List<SubpluginOption>>
) {
taskProvider.configure { taskInstance ->
val container = when (taskInstance) {
is KaptGenerateStubsTask -> taskInstance.pluginOptions
is KaptWithKotlincTask -> taskInstance.pluginOptions
is KaptWithoutKotlincTask -> taskInstance.processorOptions
else -> error("Unexpected task ${taskInstance.name} (${taskInstance.javaClass})")
}
val compilerPluginId = getCompilerPluginId()
val options = optionsProvider.get()
taskInstance.registerSubpluginOptionsAsInputs(compilerPluginId, options)
for (option in options) {
container.addPluginArgument(compilerPluginId, option)
}
}
// Also register all the subplugin options from the Kotlin task:
project.whenEvaluated {
taskProvider.configure { taskInstance ->
kotlinCompile.get().pluginOptions.subpluginOptionsByPluginId.forEach { (pluginId, options) ->
taskInstance.registerSubpluginOptionsAsInputs("kotlinCompile.$pluginId", options)
}
}
}
}
private fun encodeList(options: Map<String, String>): String {
val os = ByteArrayOutputStream()
val oos = ObjectOutputStream(os)
oos.writeInt(options.size)
for ((key, value) in options.entries) {
oos.writeUTF(key)
oos.writeUTF(value)
}
oos.flush()
return Base64.getEncoder().encodeToString(os.toByteArray())
}
private fun Kapt3SubpluginContext.addMiscOptions(pluginOptions: MutableList<SubpluginOption>) {
if (kaptExtension.generateStubs) {
project.logger.warn("'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin")
}
// These option names must match those defined in org.jetbrains.kotlin.kapt.cli.KaptCliOption.
pluginOptions += SubpluginOption("useLightAnalysis", "${kaptExtension.useLightAnalysis}")
pluginOptions += SubpluginOption("correctErrorTypes", "${kaptExtension.correctErrorTypes}")
pluginOptions += SubpluginOption("dumpDefaultParameterValues", "${kaptExtension.dumpDefaultParameterValues}")
pluginOptions += SubpluginOption("mapDiagnosticLocations", "${kaptExtension.mapDiagnosticLocations}")
pluginOptions += SubpluginOption(
"strictMode", // Currently doesn't match KaptCliOption.STRICT_MODE_OPTION, is it a typo introduced in https://github.com/JetBrains/kotlin/commit/c83581e6b8155c6d89da977be6e3cd4af30562e5?
"${kaptExtension.strictMode}"
)
pluginOptions += SubpluginOption("stripMetadata", "${kaptExtension.stripMetadata}")
pluginOptions += SubpluginOption("keepKdocCommentsInStubs", "${project.isKaptKeepKdocCommentsInStubs()}")
pluginOptions += SubpluginOption("showProcessorStats", "${kaptExtension.showProcessorStats}")
pluginOptions += SubpluginOption("detectMemoryLeaks", kaptExtension.detectMemoryLeaks)
pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}")
pluginOptions += FilesSubpluginOption("stubs", listOf(getKaptStubsDir()))
if (project.isKaptVerbose()) {
pluginOptions += SubpluginOption("verbose", "true")
}
}
private fun Kapt3SubpluginContext.createKaptKotlinTask(useWorkerApi: Boolean): TaskProvider<out KaptTask> { private fun Kapt3SubpluginContext.createKaptKotlinTask(useWorkerApi: Boolean): TaskProvider<out KaptTask> {
val taskClass = if (useWorkerApi) KaptWithoutKotlincTask::class.java else KaptWithKotlincTask::class.java val taskClass = if (useWorkerApi) KaptWithoutKotlincTask::class.java else KaptWithKotlincTask::class.java
val taskName = getKaptTaskName("kapt") val taskName = getKaptTaskName("kapt")
var classStructureIfIncremental: Configuration? = null val taskConfigAction = if (taskClass == KaptWithoutKotlincTask::class.java ) {
KaptWithoutKotlincConfigAction(kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile, kaptExtension)
if (project.isIncrementalKapt()) { } else {
maybeRegisterTransform(project) KaptWithKotlincConfigAction(kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile, kaptExtension)
classStructureIfIncremental = project.configurations.create("_classStructure${taskName}")
// Wrap the `kotlinCompile.classpath` into a file collection, so that, if the classpath is represented by a configuration,
// the configuration is not extended (via extendsFrom, which normally happens when one configuration is _added_ into another)
// but is instead included as the (lazily) resolved files. This is needed because the class structure configuration doesn't have
// the attributes that are potentially needed to resolve dependencies on MPP modules, and the classpath configuration does.
project.dependencies.add(classStructureIfIncremental.name, project.files(project.provider { kotlinCompile.get().libraries }))
} }
val kaptClasspathConfiguration = project.configurations.create("kaptClasspath_$taskName") val kaptClasspathConfiguration = project.configurations.create("kaptClasspath_$taskName")
@@ -522,182 +406,97 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
it.isVisible = false it.isVisible = false
it.isCanBeConsumed = false it.isCanBeConsumed = false
} }
taskConfigAction.configureTaskProvider { taskProvider ->
val kaptTaskProvider = project.registerTask(taskName, taskClass, emptyList()) { kaptTask -> if (javaCompile != null) {
kaptTask.useBuildCache = kaptExtension.useBuildCache val androidVariantData = KaptWithAndroid.androidVariantData(this)
if (androidVariantData != null) {
val kotlinCompileTask = kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile KaptWithAndroid.registerGeneratedJavaSourceForAndroid(this, project, androidVariantData, taskProvider)
if (kaptTask is KaptWithoutKotlincTask) { androidVariantData.addJavaSourceFoldersToModel(sourcesOutputDir)
KaptWithoutKotlincTask.Configurator(kotlinCompileTask).configure(kaptTask) } else {
} else { registerGeneratedJavaSource(taskProvider, javaCompile)
KaptWithKotlincTask.Configurator(kotlinCompileTask).configure(kaptTask as KaptWithKotlincTask)
PropertiesProvider(project).mapKotlinDaemonProperties(kaptTask)
}
kaptTask.stubsDir.set(getKaptStubsDir())
kaptTask.destinationDir = sourcesOutputDir
kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir
kaptTask.classesDir = classesOutputDir
kaptTask.includeCompileClasspath.set(includeCompileClasspath)
kaptTask.isIncremental = project.isIncrementalKapt()
if (kaptTask.isIncremental) {
kaptTask.incAptCache.fileValue(getKaptIncrementalAnnotationProcessingCache()).disallowChanges()
kaptTask.classpathStructure.from(
classStructureIfIncremental!!.incoming.artifactView { viewConfig ->
viewConfig.attributes.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}.files
).disallowChanges()
if (kaptTask is KaptWithKotlincTask) {
kaptTask.pluginOptions.addPluginArgument(
getCompilerPluginId(),
SubpluginOption(
"incrementalCache",
lazy { kaptTask.incAptCache.asFile.get().absolutePath }
)
)
} }
disableAnnotationProcessingInJavaTask()
} }
kaptTask.kaptClasspath.from(kaptClasspathConfiguration).disallowChanges() kotlinCompilation.output.classesDirs.from(taskProvider.flatMap { it.classesDir })
kaptTask.kaptExternalClasspath.from(kaptClasspathConfiguration.fileCollection { it is ExternalDependency })
kaptTask.kaptClasspathConfigurationNames.value(kaptClasspathConfigurations.map { it.name }).disallowChanges() kotlinCompilation.compileKotlinTaskProvider.configure {
(it as AbstractKotlinCompileTool<*>).setSource(sourcesOutputDir, kotlinSourcesOutputDir)
}
}
taskConfigAction.configureTask { task ->
task.stubsDir.set(getKaptStubsDir())
task.destinationDir.set(sourcesOutputDir)
task.kotlinSourcesDestinationDir.set(kotlinSourcesOutputDir)
task.classesDir.set(classesOutputDir)
if (javaCompile != null) {
task.defaultJavaSourceCompatibility.set(javaCompile.map { it.sourceCompatibility })
}
if (project.isIncrementalKapt()) {
task.incAptCache.fileValue(getKaptIncrementalAnnotationProcessingCache()).disallowChanges()
}
task.kaptClasspath.from(kaptClasspathConfiguration).disallowChanges()
task.kaptExternalClasspath.from(kaptClasspathConfiguration.fileCollection { it is ExternalDependency })
task.kaptClasspathConfigurationNames.value(kaptClasspathConfigurations.map { it.name }).disallowChanges()
KaptWithAndroid.androidVariantData(this)?.annotationProcessorOptionProviders?.let { KaptWithAndroid.androidVariantData(this)?.annotationProcessorOptionProviders?.let {
kaptTask.annotationProcessorOptionProviders.add(it) task.annotationProcessorOptionProviders.add(it)
} }
}
kotlinCompilation.output.classesDirs.from(kaptTaskProvider.map { it.classesDir }) val pluginOptions: Provider<CompilerPluginOptions> = if (taskClass == KaptWithKotlincTask::class.java) {
buildOptionsForAptMode(taskConfigAction.getJavaOptions(task.defaultJavaSourceCompatibility))
kotlinCompilation.compileKotlinTaskProvider.configure {
(it as AbstractKotlinCompileTool<*>).setSource(sourcesOutputDir, kotlinSourcesOutputDir)
}
if (javaCompile != null) {
val androidVariantData = KaptWithAndroid.androidVariantData(this)
if (androidVariantData != null) {
KaptWithAndroid.registerGeneratedJavaSourceForAndroid(this, project, androidVariantData, kaptTaskProvider)
} else { } else {
registerGeneratedJavaSource(kaptTaskProvider, javaCompile) check(taskClass == KaptWithoutKotlincTask::class.java)
getDslKaptApOptions()
}.map {
val res = CompilerPluginOptions()
it.forEach { res.addPluginArgument(KAPT_SUBPLUGIN_ID, it) }
return@map res
} }
task.kaptPluginOptions.add(pluginOptions)
} }
val dslJavacOptions: Provider<Map<String, String>> = project.provider { return if (taskClass == KaptWithoutKotlincTask::class.java) {
kaptExtension.getJavacOptions().toMutableMap().also { result -> taskConfigAction as KaptWithoutKotlincConfigAction
if (javaCompile != null && "-source" !in result && "--source" !in result && "--release" !in result) { project.registerTask(taskName, KaptWithoutKotlincTask::class.java, emptyList()).also {
val atLeast12Java = taskConfigAction.execute(it)
if (isConfigurationCacheAvailable(project.gradle)) {
val currentJavaVersion =
JavaVersion.parse(project.providers.systemProperty("java.version").forUseAtConfigurationTime().get())
currentJavaVersion.feature >= 12
} else {
SystemInfo.isJavaVersionAtLeast(12, 0, 0)
}
val sourceOptionKey = if (atLeast12Java) {
"--source"
} else {
"-source"
}
result[sourceOptionKey] = javaCompile.get().sourceCompatibility
}
} }
} } else {
taskConfigAction as KaptWithKotlincConfigAction
if (KaptWithKotlincTask::class.java.isAssignableFrom(taskClass)) { project.registerTask(taskName, KaptWithKotlincTask::class.java, emptyList()).also {
val subpluginOptions = buildOptions("apt", dslJavacOptions) taskConfigAction.execute(it)
registerSubpluginOptions(kaptTaskProvider, subpluginOptions)
}
if (taskClass == KaptWithoutKotlincTask::class.java) {
kaptTaskProvider.configure {
it as KaptWithoutKotlincTask
it.mapDiagnosticLocations = kaptExtension.mapDiagnosticLocations
it.annotationProcessorFqNames = kaptExtension.processors.split(',').filter { it.isNotEmpty() }
it.javacOptions = dslJavacOptions.get()
if (includeCompileClasspath && project.classLoadersCacheSize() > 0) {
project.logger.warn(
"ClassLoaders cache can't be enabled together with AP discovery in compilation classpath."
+ "\nSet 'kapt.include.compile.classpath=false' to disable discovery"
)
} else {
it.classLoadersCacheSize = project.classLoadersCacheSize()
}
it.disableClassloaderCacheForProcessors = project.disableClassloaderCacheForProcessors()
} }
val subpluginOptions = getDslKaptApOptions()
registerSubpluginOptions(kaptTaskProvider, subpluginOptions)
}
kaptTaskProvider.configure { task ->
task.onlyIf {
it as KaptTask
it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty
}
}
return kaptTaskProvider
}
private fun maybeRegisterTransform(project: Project) {
if (!project.extensions.extraProperties.has("KaptStructureTransformAdded")) {
val transformActionClass =
if (GradleVersion.current() >= GradleVersion.version("5.4"))
StructureTransformAction::class.java
else
StructureTransformLegacyAction::class.java
project.dependencies.registerTransform(transformActionClass) { transformSpec ->
transformSpec.from.attribute(artifactType, "jar")
transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}
project.dependencies.registerTransform(transformActionClass) { transformSpec ->
transformSpec.from.attribute(artifactType, "directory")
transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}
project.extensions.extraProperties["KaptStructureTransformAdded"] = true
} }
} }
private fun Kapt3SubpluginContext.createKaptGenerateStubsTask(): TaskProvider<KaptGenerateStubsTask> { private fun Kapt3SubpluginContext.createKaptGenerateStubsTask(): TaskProvider<KaptGenerateStubsTask> {
val properties = PropertiesProvider(project)
val kaptTaskName = getKaptTaskName("kaptGenerateStubs") val kaptTaskName = getKaptTaskName("kaptGenerateStubs")
val kaptTaskProvider = project.registerTask<KaptGenerateStubsTask>(kaptTaskName) val kaptTaskProvider = project.registerTask<KaptGenerateStubsTask>(kaptTaskName)
val projectDir = project.projectDir
val configurator = KaptGenerateStubsTask.Configurator(kotlinCompile, kotlinCompilation, properties) val taskConfig = KaptGenerateStubsConfig(kotlinCompilation, kotlinCompile)
configurator.runAtConfigurationTime(kaptTaskProvider, project) taskConfig.configureTask {
it.stubsDir.set(getKaptStubsDir())
kaptTaskProvider.configure { kaptTask -> it.destinationDirectory.set(getKaptIncrementalDataDir())
configurator.configure(kaptTask) it.exclude(
"${sourcesOutputDir.relativeTo(projectDir).path}/**",
kaptTask.stubsDir.set(getKaptStubsDir()) "${kotlinSourcesOutputDir.relativeTo(projectDir).path}/**"
kaptTask.destinationDirectory.set(getKaptIncrementalDataDir()) )
kaptTask.generatedSourcesDirs = listOf(sourcesOutputDir, kotlinSourcesOutputDir) it.kaptClasspath.from(kaptClasspathConfigurations)
it.classpathSnapshotProperties.classpathSnapshotDir.fileValue(getKaptClasspathSnapshotDir())
kaptTask.kaptClasspath.from(kaptClasspathConfigurations)
properties.mapKotlinTaskProperties(kaptTask)
if (!includeCompileClasspath) {
kaptTask.onlyIf {
!(it as KaptGenerateStubsTask).kaptClasspath.isEmpty
}
}
} }
taskConfig.execute(kaptTaskProvider)
project.whenEvaluated { project.whenEvaluated {
addCompilationSourcesToExternalCompileTask(kotlinCompilation, kaptTaskProvider) addCompilationSourcesToExternalCompileTask(kotlinCompilation, kaptTaskProvider)
} }
val subpluginOptions = buildOptions("stubs", project.provider { kaptExtension.getJavacOptions() })
registerSubpluginOptions(kaptTaskProvider, subpluginOptions)
return kaptTaskProvider return kaptTaskProvider
} }
@@ -741,7 +540,72 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
JetBrainsSubpluginArtifact(artifactId = KAPT_ARTIFACT_NAME) JetBrainsSubpluginArtifact(artifactId = KAPT_ARTIFACT_NAME)
} }
private val artifactType = Attribute.of("artifactType", String::class.java) internal fun buildKaptSubpluginOptions(
kaptExtension: KaptExtension,
project: Project,
javacOptions: Map<String, String>,
aptMode: String,
generatedSourcesDir: Iterable<File>,
generatedClassesDir: Iterable<File>,
incrementalDataDir: Iterable<File>,
includeCompileClasspath: Boolean,
kaptStubsDir: Iterable<File>,
): List<SubpluginOption> {
if (kaptExtension.generateStubs) {
project.logger.warn("'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin")
}
val pluginOptions = mutableListOf<SubpluginOption>()
pluginOptions += SubpluginOption("aptMode", aptMode)
pluginOptions += FilesSubpluginOption("sources", generatedSourcesDir)
pluginOptions += FilesSubpluginOption("classes", generatedClassesDir)
pluginOptions += FilesSubpluginOption("incrementalData", incrementalDataDir)
val annotationProcessors = kaptExtension.processors
if (annotationProcessors.isNotEmpty()) {
pluginOptions += SubpluginOption("processors", annotationProcessors)
}
pluginOptions += SubpluginOption("javacArguments", encodeList(javacOptions))
pluginOptions += SubpluginOption("includeCompileClasspath", includeCompileClasspath.toString())
// These option names must match those defined in org.jetbrains.kotlin.kapt.cli.KaptCliOption.
pluginOptions += SubpluginOption("useLightAnalysis", "${kaptExtension.useLightAnalysis}")
pluginOptions += SubpluginOption("correctErrorTypes", "${kaptExtension.correctErrorTypes}")
pluginOptions += SubpluginOption("dumpDefaultParameterValues", "${kaptExtension.dumpDefaultParameterValues}")
pluginOptions += SubpluginOption("mapDiagnosticLocations", "${kaptExtension.mapDiagnosticLocations}")
pluginOptions += SubpluginOption(
"strictMode", // Currently doesn't match KaptCliOption.STRICT_MODE_OPTION, is it a typo introduced in https://github.com/JetBrains/kotlin/commit/c83581e6b8155c6d89da977be6e3cd4af30562e5?
"${kaptExtension.strictMode}"
)
pluginOptions += SubpluginOption("stripMetadata", "${kaptExtension.stripMetadata}")
pluginOptions += SubpluginOption("keepKdocCommentsInStubs", "${project.isKaptKeepKdocCommentsInStubs()}")
pluginOptions += SubpluginOption("showProcessorTimings", "${kaptExtension.showProcessorStats}")
pluginOptions += SubpluginOption("detectMemoryLeaks", kaptExtension.detectMemoryLeaks)
pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}")
pluginOptions += FilesSubpluginOption("stubs", kaptStubsDir)
if (project.isKaptVerbose()) {
pluginOptions += SubpluginOption("verbose", "true")
}
return pluginOptions
}
private fun encodeList(options: Map<String, String>): String {
val os = ByteArrayOutputStream()
val oos = ObjectOutputStream(os)
oos.writeInt(options.size)
for ((key, value) in options.entries) {
oos.writeUTF(key)
oos.writeUTF(value)
}
oos.flush()
return Base64.getEncoder().encodeToString(os.toByteArray())
}
// Don't reference the BaseVariant type in the Kapt plugin signatures, as those type references will fail to link when there's no Android // Don't reference the BaseVariant type in the Kapt plugin signatures, as those type references will fail to link when there's no Android
// Gradle plugin on the project's plugin classpath // Gradle plugin on the project's plugin classpath
@@ -771,7 +635,7 @@ private object KaptWithAndroid {
internal fun registerGeneratedJavaSource(kaptTask: TaskProvider<out KaptTask>, javaTaskProvider: TaskProvider<out AbstractCompile>) { internal fun registerGeneratedJavaSource(kaptTask: TaskProvider<out KaptTask>, javaTaskProvider: TaskProvider<out AbstractCompile>) {
javaTaskProvider.configure { javaTask -> javaTaskProvider.configure { javaTask ->
val generatedJavaSources = javaTask.project.fileTree(kaptTask.map { it.destinationDir }) val generatedJavaSources = javaTask.project.fileTree(kaptTask.flatMap { it.destinationDir })
generatedJavaSources.include("**/*.java") generatedJavaSources.include("**/*.java")
javaTask.source(generatedJavaSources) javaTask.source(generatedJavaSources)
} }
@@ -18,18 +18,18 @@ package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.file.* import org.gradle.api.file.*
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.work.Incremental import org.gradle.work.Incremental
import org.gradle.work.NormalizeLineEndings import org.gradle.work.NormalizeLineEndings
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.isParentOf import org.jetbrains.kotlin.gradle.utils.isParentOf
import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions
import org.jetbrains.kotlin.incremental.classpathAsList import org.jetbrains.kotlin.incremental.classpathAsList
import org.jetbrains.kotlin.incremental.destinationAsFile import org.jetbrains.kotlin.incremental.destinationAsFile
import java.io.File import java.io.File
@@ -45,38 +45,9 @@ abstract class KaptGenerateStubsTask @Inject constructor(
objectFactory objectFactory
) { ) {
internal class Configurator(
private val kotlinCompileTaskProvider: TaskProvider<KotlinCompile>,
kotlinCompilation: KotlinCompilationData<*>,
properties: PropertiesProvider
) : KotlinCompile.Configurator<KaptGenerateStubsTask>(kotlinCompilation, properties) {
override fun configure(task: KaptGenerateStubsTask) {
super.configure(task)
val kotlinCompileTask = kotlinCompileTaskProvider.get()
val providerFactory = kotlinCompileTask.project.providers
task.useModuleDetection.value(kotlinCompileTask.useModuleDetection).disallowChanges()
task.moduleName.value(kotlinCompileTask.moduleName).disallowChanges()
task.libraries.from(kotlinCompileTask.libraries)
task.kotlinTaskPluginClasspath.from(
providerFactory.provider { kotlinCompileTask.pluginClasspath }
)
task.compileKotlinArgumentsContributor.set(
providerFactory.provider {
kotlinCompileTask.compilerArgumentsContributor
}
)
task.verbose.set(KaptTask.queryKaptVerboseProperty(task.project))
}
}
@get:OutputDirectory @get:OutputDirectory
abstract val stubsDir: DirectoryProperty abstract val stubsDir: DirectoryProperty
@get:Internal
lateinit var generatedSourcesDirs: List<File>
@get:Internal("Not an input, just passed as kapt args. ") @get:Internal("Not an input, just passed as kapt args. ")
abstract val kaptClasspath: ConfigurableFileCollection abstract val kaptClasspath: ConfigurableFileCollection
@@ -84,11 +55,6 @@ abstract class KaptGenerateStubsTask @Inject constructor(
@Input @Input
fun getIfKaptClasspathIsPresent() = !kaptClasspath.isEmpty fun getIfKaptClasspathIsPresent() = !kaptClasspath.isEmpty
@get:NormalizeLineEndings
@get:Classpath
@Suppress("unused")
internal abstract val kotlinTaskPluginClasspath: ConfigurableFileCollection
@get:Input @get:Input
abstract val verbose: Property<Boolean> abstract val verbose: Property<Boolean>
@@ -105,8 +71,7 @@ abstract class KaptGenerateStubsTask @Inject constructor(
private fun File.isSourceRootAllowed(): Boolean = private fun File.isSourceRootAllowed(): Boolean =
!destinationDirectory.get().asFile.isParentOf(this) && !destinationDirectory.get().asFile.isParentOf(this) &&
!stubsDir.asFile.get().isParentOf(this) && !stubsDir.asFile.get().isParentOf(this)
generatedSourcesDirs.none { it.isParentOf(this) }
override fun skipCondition(): Boolean = sources.isEmpty && javaSources.isEmpty override fun skipCondition(): Boolean = sources.isEmpty && javaSources.isEmpty
@@ -123,10 +88,10 @@ abstract class KaptGenerateStubsTask @Inject constructor(
} }
@get:Internal @get:Internal
override val scriptSources: FileCollection = objectFactory.fileCollection() abstract override val scriptSources: FileCollection
@get:Internal @get:Internal
override val androidLayoutResources: FileCollection = objectFactory.fileCollection() abstract override val androidLayoutResources: FileCollection
override val incrementalProps: List<FileCollection> override val incrementalProps: List<FileCollection>
get() = listOf( get() = listOf(
@@ -159,11 +124,11 @@ abstract class KaptGenerateStubsTask @Inject constructor(
) )
) )
val pluginOptionsWithKapt = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath) val pluginOptionsWithKapt = pluginOptions.toSingleCompilerPluginOptions().withWrappedKaptOptions(withApClasspath = kaptClasspath)
args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray() args.pluginOptions = (pluginOptionsWithKapt.arguments).toTypedArray()
args.verbose = verbose.get() args.verbose = verbose.get()
args.classpathAsList = this.libraries.filter { it.exists() }.toList() args.classpathAsList = this.libraries.filter { it.exists() }.toList()
args.destinationAsFile = this.destinationDirectory.get().asFile args.destinationAsFile = this.destinationDirectory.get().asFile
} }
} }
@@ -19,13 +19,11 @@ 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.KaptClasspathChanges
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.UnknownSnapshot 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.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import java.io.File import java.io.File
import java.util.concurrent.Callable
import java.util.jar.JarFile import java.util.jar.JarFile
import javax.inject.Inject import javax.inject.Inject
@@ -36,30 +34,6 @@ abstract class KaptTask @Inject constructor(
TaskWithLocalState, TaskWithLocalState,
UsesKotlinJavaToolchain { UsesKotlinJavaToolchain {
open class Configurator<T: KaptTask>(protected val kotlinCompileTask: KotlinCompile) : TaskConfigurator<T> {
override fun configure(task: T) {
val objectFactory = task.project.objects
task.compilerClasspath.from({ kotlinCompileTask.defaultCompilerClasspath })
task.classpath.from(kotlinCompileTask.libraries)
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(
kotlinCompileTask.javaSources,
task.stubsDir
).asFileTree
.matching { it.include("**/*.java") }
.filter { f -> task.isRootAllowed(f) }
).disallowChanges()
task.verbose.set(queryKaptVerboseProperty(task.project))
}
}
init { init {
cacheOnlyIfEnabledForKotlin() cacheOnlyIfEnabledForKotlin()
@@ -95,6 +69,9 @@ abstract class KaptTask @Inject constructor(
@get:InputFiles @get:InputFiles
abstract val classpathStructure: ConfigurableFileCollection abstract val classpathStructure: ConfigurableFileCollection
@get:Internal
abstract val kaptPluginOptions: ListProperty<CompilerPluginOptions>
/** /**
* Output directory that contains caches necessary to support incremental annotation processing. * Output directory that contains caches necessary to support incremental annotation processing.
*/ */
@@ -102,13 +79,14 @@ abstract class KaptTask @Inject constructor(
abstract val incAptCache: DirectoryProperty abstract val incAptCache: DirectoryProperty
@get:OutputDirectory @get:OutputDirectory
internal lateinit var classesDir: File internal abstract val classesDir: DirectoryProperty
@get:OutputDirectory @get:OutputDirectory
lateinit var destinationDir: File abstract val destinationDir: DirectoryProperty
/** Used in the model builder only. */
@get:OutputDirectory @get:OutputDirectory
lateinit var kotlinSourcesDestinationDir: File abstract val kotlinSourcesDestinationDir: DirectoryProperty
@get:Nested @get:Nested
internal val annotationProcessorOptionProviders: MutableList<Any> = mutableListOf() internal val annotationProcessorOptionProviders: MutableList<Any> = mutableListOf()
@@ -176,37 +154,8 @@ abstract class KaptTask @Inject constructor(
@get:Input @get:Input
abstract val verbose: Property<Boolean> abstract val verbose: Property<Boolean>
private fun isRootAllowed(file: File): Boolean = @get:Internal
file.exists() && abstract val defaultJavaSourceCompatibility: Property<String>
!isAncestor(destinationDir, file) &&
!isAncestor(classesDir, file)
//Have to avoid using FileUtil because it is required system property reading that is not allowed for configuration cache
private fun isAncestor(dir: File, file: File): Boolean {
val path = file.canonicalPath
val prefix = dir.canonicalPath
val pathLength = path.length
val prefixLength = prefix.length
//TODO
val caseSensitive = true
return if (prefixLength == 0) {
true
} else if (prefixLength > pathLength) {
false
} else if (!path.regionMatches(0, prefix, 0, prefixLength, ignoreCase = !caseSensitive)) {
return false
} else if (pathLength == prefixLength) {
return true
} else {
val lastPrefixChar: Char = prefix.get(prefixLength - 1)
var slashOrSeparatorIdx = prefixLength
if (lastPrefixChar == '/' || lastPrefixChar == File.separatorChar) {
slashOrSeparatorIdx = prefixLength - 1
}
val next1 = path[slashOrSeparatorIdx]
return !(next1 != '/' && next1 != File.separatorChar)
}
}
protected fun checkAnnotationProcessorClasspath() { protected fun checkAnnotationProcessorClasspath() {
if (!includeCompileClasspath.get()) return if (!includeCompileClasspath.get()) return
@@ -35,21 +35,6 @@ abstract class KaptWithKotlincTask @Inject constructor(
CompilerArgumentAwareWithInput<K2JVMCompilerArguments>, CompilerArgumentAwareWithInput<K2JVMCompilerArguments>,
CompileUsingKotlinDaemonWithNormalization { CompileUsingKotlinDaemonWithNormalization {
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:NormalizeLineEndings @get:NormalizeLineEndings
@get:Classpath @get:Classpath
abstract val pluginClasspath: ConfigurableFileCollection abstract val pluginClasspath: ConfigurableFileCollection
@@ -59,6 +44,10 @@ abstract class KaptWithKotlincTask @Inject constructor(
objectFactory.newInstance<GradleCompileTaskProvider>(project.gradle, this, project) objectFactory.newInstance<GradleCompileTaskProvider>(project.gradle, this, project)
) )
/** Used only as task input, actual values come from [compileKotlinArgumentsContributor]. */
@get:Nested
internal abstract val additionalPluginOptionsAsInputs: ListProperty<CompilerPluginOptions>
override fun createCompilerArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments() override fun createCompilerArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments()
abstract override val kotlinDaemonJvmArguments: ListProperty<String> abstract override val kotlinDaemonJvmArguments: ListProperty<String>
@@ -74,8 +63,7 @@ abstract class KaptWithKotlincTask @Inject constructor(
)) ))
args.pluginClasspaths = pluginClasspath.toPathsArray() args.pluginClasspaths = pluginClasspath.toPathsArray()
val pluginOptionsWithKapt: CompilerPluginOptions = kaptPluginOptions.toSingleCompilerPluginOptions().withWrappedKaptOptions(
val pluginOptionsWithKapt: CompilerPluginOptions = pluginOptions.withWrappedKaptOptions(
withApClasspath = kaptClasspath, withApClasspath = kaptClasspath,
changedFiles = changedFiles, changedFiles = changedFiles,
classpathChanges = classpathChanges, classpathChanges = classpathChanges,
@@ -95,8 +83,11 @@ abstract class KaptWithKotlincTask @Inject constructor(
private var classpathChanges: List<String> = emptyList() private var classpathChanges: List<String> = emptyList()
private var processIncrementally = false private var processIncrementally = false
private val javaPackagePrefix = objectFactory.property(String::class.java) @get:Internal
private val reportingSettings = objectFactory.property(ReportingSettings::class.java) internal abstract val javaPackagePrefix: Property<String>
@get:Internal
internal abstract val reportingSettings: Property<ReportingSettings>
@TaskAction @TaskAction
fun compile(inputChanges: InputChanges) { fun compile(inputChanges: InputChanges) {
@@ -9,6 +9,7 @@ import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
@@ -20,13 +21,12 @@ import org.gradle.workers.IsolationMode
import org.gradle.workers.WorkAction import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.ClassLoadersCache import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.ClassLoadersCache
import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.rootOrSelf import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.rootOrSelf
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinAndroidPluginWrapper import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinAndroidPluginWrapper
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -42,16 +42,6 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
private val workerExecutor: WorkerExecutor private val workerExecutor: WorkerExecutor
) : KaptTask(objectFactory) { ) : KaptTask(objectFactory) {
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 AbstractKotlinAndroidPluginWrapper } }
).disallowChanges()
task.kaptJars.from(task.project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)).disallowChanges()
}
}
@get:NormalizeLineEndings @get:NormalizeLineEndings
@get:Classpath @get:Classpath
abstract val kaptJars: ConfigurableFileCollection abstract val kaptJars: ConfigurableFileCollection
@@ -66,16 +56,13 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
var mapDiagnosticLocations: Boolean = false var mapDiagnosticLocations: Boolean = false
@get:Input @get:Input
lateinit var annotationProcessorFqNames: List<String> abstract val annotationProcessorFqNames: ListProperty<String>
@get:Internal
internal val processorOptions = CompilerPluginOptions()
@get:Input @get:Input
lateinit var javacOptions: Map<String, String> abstract val javacOptions: MapProperty<String, String>
@get:Input @get:Input
internal abstract val addJdkClassesToClasspath: Property<Boolean> abstract val addJdkClassesToClasspath: Property<Boolean>
@get:Internal @get:Internal
internal val projectDir = project.projectDir internal val projectDir = project.projectDir
@@ -84,11 +71,9 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
val kaptProcessJvmArgs: ListProperty<String> = objectFactory.listProperty<String>().convention(emptyList()) val kaptProcessJvmArgs: ListProperty<String> = objectFactory.listProperty<String>().convention(emptyList())
private fun getAnnotationProcessorOptions(): Map<String, String> { private fun getAnnotationProcessorOptions(): Map<String, String> {
val options = processorOptions.subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID] ?: return emptyMap()
val result = mutableMapOf<String, String>() val result = mutableMapOf<String, String>()
for (option in options) { kaptPluginOptions.toSingleCompilerPluginOptions().subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID]?.forEach {
result[option.key] = option.value result[it.key] = it.value
} }
annotationProcessorOptionProviders.forEach { providers -> annotationProcessorOptionProviders.forEach { providers ->
(providers as List<*>).forEach { provider -> (providers as List<*>).forEach { provider ->
@@ -104,6 +89,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
@TaskAction @TaskAction
fun compile(inputChanges: InputChanges) { fun compile(inputChanges: InputChanges) {
logger.info("Running kapt annotation processing using the Gradle Worker API") logger.info("Running kapt annotation processing using the Gradle Worker API")
checkProcessorCachingSetup()
checkAnnotationProcessorClasspath() checkAnnotationProcessorClasspath()
val incrementalChanges = getIncrementalChanges(inputChanges) val incrementalChanges = getIncrementalChanges(inputChanges)
@@ -137,16 +123,16 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
incAptCache.orNull?.asFile, incAptCache.orNull?.asFile,
classpathChanges.toList(), classpathChanges.toList(),
destinationDir, destinationDir.get().asFile,
classesDir, classesDir.get().asFile,
stubsDir.asFile.get(), stubsDir.asFile.get(),
kaptClasspath.files.toList(), kaptClasspath.files.toList(),
kaptExternalClasspath.files.toList(), kaptExternalClasspath.files.toList(),
annotationProcessorFqNames, annotationProcessorFqNames.get(),
getAnnotationProcessorOptions(), getAnnotationProcessorOptions(),
javacOptions, javacOptions.get(),
kaptFlagsForWorker, kaptFlagsForWorker,
@@ -154,7 +140,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
) )
// Skip annotation processing if no annotation processors were provided. // Skip annotation processing if no annotation processors were provided.
if (annotationProcessorFqNames.isEmpty() && kaptClasspath.isEmpty()) { if (annotationProcessorFqNames.get().isEmpty() && kaptClasspath.isEmpty()) {
logger.info("No annotation processors provided. Skip KAPT processing.") logger.info("No annotation processors provided. Skip KAPT processing.")
return return
} }
@@ -259,6 +245,15 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
).run() ).run()
} }
} }
private fun checkProcessorCachingSetup() {
if (includeCompileClasspath.get() && classLoadersCacheSize > 0) {
logger.warn(
"ClassLoaders cache can't be enabled together with AP discovery in compilation classpath."
+ "\nSet 'kapt.include.compile.classpath=false' to disable discovery"
)
}
}
} }
@@ -1,13 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.internal.tasks
import org.gradle.api.Task
/** Classes that participate in task configuration should implement this interface. */
interface TaskConfigurator<T : Task> {
fun configure(task: T)
}
@@ -39,9 +39,9 @@ class KaptModelBuilder : ToolingModelBuilder {
true true
) )
) KaptSourceSet.KaptSourceSetType.TEST else KaptSourceSet.KaptSourceSetType.PRODUCTION, ) KaptSourceSet.KaptSourceSetType.TEST else KaptSourceSet.KaptSourceSetType.PRODUCTION,
destinationDir, destinationDir.get().asFile,
kotlinSourcesDestinationDir, kotlinSourcesDestinationDir.get().asFile,
classesDir classesDir.get().asFile
) )
} }
} }
@@ -36,11 +36,11 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
import org.jetbrains.kotlin.gradle.targets.js.ir.* import org.jetbrains.kotlin.gradle.targets.js.ir.*
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.configuration.*
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.tooling.includeKotlinToolingMetadataInApk import org.jetbrains.kotlin.gradle.tooling.includeKotlinToolingMetadataInApk
import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.*
@@ -67,7 +67,7 @@ abstract class KotlinCompilationProcessor<out T : AbstractKotlinCompileTool<*>>(
protected val project: Project protected val project: Project
get() = kotlinCompilation.project get() = kotlinCompilation.project
protected val defaultKotlinDestinationDir: File protected val defaultKotlinDestinationDir: Provider<Directory>
get() { get() {
val kotlinExt = project.topLevelExtension val kotlinExt = project.topLevelExtension
val targetSubDirectory = val targetSubDirectory =
@@ -75,7 +75,7 @@ abstract class KotlinCompilationProcessor<out T : AbstractKotlinCompileTool<*>>(
"" // In single-target projects, don't add the target name part to this path "" // In single-target projects, don't add the target name part to this path
else else
kotlinCompilation.compilationClassifier?.let { "$it/" }.orEmpty() kotlinCompilation.compilationClassifier?.let { "$it/" }.orEmpty()
return File(project.buildDir, "classes/kotlin/$targetSubDirectory${kotlinCompilation.compilationPurpose}") return project.layout.buildDirectory.dir("classes/kotlin/$targetSubDirectory${kotlinCompilation.compilationPurpose}")
} }
} }
@@ -103,23 +103,10 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
} }
private fun prepareKotlinCompileTask(): TaskProvider<out T> = private fun prepareKotlinCompileTask(): TaskProvider<out T> =
registerKotlinCompileTask(register = ::doRegisterTask).also { task -> doRegisterTask(project, kotlinCompilation.compileKotlinTaskName).also { task ->
kotlinCompilation.output.classesDirs.from(task.flatMap { it.destinationDirectory }) kotlinCompilation.output.classesDirs.from(task.flatMap { it.destinationDirectory })
} }
protected fun registerKotlinCompileTask(
name: String = kotlinCompilation.compileKotlinTaskName,
register: (Project, String, (T) -> Unit) -> TaskProvider<out T>
): TaskProvider<out T> {
logger.kotlinDebug("Creating kotlin compile task $name")
return register(project, name) {
it.description = taskDescription
it.destinationDirectory.set(defaultKotlinDestinationDir)
it.libraries.from({ kotlinCompilation.compileDependencyFiles })
}
}
override fun run() { override fun run() {
addKotlinDirectoriesToJavaSourceSet() addKotlinDirectoriesToJavaSourceSet()
doTargetSpecificProcessing() doTargetSpecificProcessing()
@@ -165,7 +152,15 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
} }
} }
protected abstract fun doRegisterTask(project: Project, taskName: String, configureAction: (T) -> (Unit)): TaskProvider<out T> protected fun applyStandardTaskConfiguration(taskConfiguration: AbstractKotlinCompileConfig<*>) {
taskConfiguration.configureTask {
it.description = taskDescription
it.destinationDirectory.convention(defaultKotlinDestinationDir)
it.libraries.from({ kotlinCompilation.compileDependencyFiles })
}
}
protected abstract fun doRegisterTask(project: Project, taskName: String): TaskProvider<out T>
} }
internal class Kotlin2JvmSourceSetProcessor( internal class Kotlin2JvmSourceSetProcessor(
@@ -174,12 +169,11 @@ internal class Kotlin2JvmSourceSetProcessor(
) : KotlinSourceSetProcessor<KotlinCompile>( ) : KotlinSourceSetProcessor<KotlinCompile>(
tasksProvider, "Compiles the $kotlinCompilation.", kotlinCompilation tasksProvider, "Compiles the $kotlinCompilation.", kotlinCompilation
) { ) {
override fun doRegisterTask( override fun doRegisterTask(project: Project, taskName: String): TaskProvider<out KotlinCompile> {
project: Project, val configAction = KotlinCompileConfig(kotlinCompilation)
taskName: String, applyStandardTaskConfiguration(configAction)
configureAction: (KotlinCompile) -> (Unit) return tasksProvider.registerKotlinJVMTask(project, taskName, kotlinCompilation.kotlinOptions, configAction)
): TaskProvider<out KotlinCompile> = }
tasksProvider.registerKotlinJVMTask(project, taskName, kotlinCompilation, configureAction)
override fun doTargetSpecificProcessing() { override fun doTargetSpecificProcessing() {
ifKaptEnabled(project) { ifKaptEnabled(project) {
@@ -232,12 +226,11 @@ internal class Kotlin2JsSourceSetProcessor(
taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.", taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.",
kotlinCompilation = kotlinCompilation kotlinCompilation = kotlinCompilation
) { ) {
override fun doRegisterTask( override fun doRegisterTask(project: Project, taskName: String): TaskProvider<out Kotlin2JsCompile> {
project: Project, val configAction = Kotlin2JsCompileConfig(kotlinCompilation)
taskName: String, applyStandardTaskConfiguration(configAction)
configureAction: (Kotlin2JsCompile) -> (Unit) return tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation.kotlinOptions, configAction)
): TaskProvider<out Kotlin2JsCompile> = }
tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation, configureAction)
override fun doTargetSpecificProcessing() { override fun doTargetSpecificProcessing() {
project.tasks.named(kotlinCompilation.compileAllTaskName).configure { project.tasks.named(kotlinCompilation.compileAllTaskName).configure {
@@ -298,27 +291,10 @@ internal class KotlinJsIrSourceSetProcessor(
tasksProvider, taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.", tasksProvider, taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.",
kotlinCompilation = kotlinCompilation kotlinCompilation = kotlinCompilation
) { ) {
override fun doRegisterTask( override fun doRegisterTask(project: Project, taskName: String): TaskProvider<out Kotlin2JsCompile> {
project: Project, val configAction = Kotlin2JsCompileConfig(kotlinCompilation)
taskName: String, applyStandardTaskConfiguration(configAction)
configureAction: (Kotlin2JsCompile) -> (Unit) return tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation.kotlinOptions, configAction)
): TaskProvider<out Kotlin2JsCompile> =
tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation, configureAction)
private fun registerJsLink(
project: Project,
taskName: String,
mode: KotlinJsBinaryMode,
configureAction: (Kotlin2JsCompile) -> Unit
): TaskProvider<out KotlinJsIrLink> {
return tasksProvider.registerKotlinJsIrTask(
project,
taskName,
kotlinCompilation
) { task ->
task.mode = mode
configureAction(task)
}
} }
override fun doTargetSpecificProcessing() { override fun doTargetSpecificProcessing() {
@@ -331,14 +307,14 @@ internal class KotlinJsIrSourceSetProcessor(
compilation.binaries compilation.binaries
.withType(JsIrBinary::class.java) .withType(JsIrBinary::class.java)
.all { binary -> .all { binary ->
registerKotlinCompileTask( val configAction = KotlinJsIrLinkConfig(compilation)
binary.linkTaskName applyStandardTaskConfiguration(configAction)
) { project, name, action -> configAction.configureTask { task ->
registerJsLink(project, name, binary.mode) { compileTask -> task.modeProperty.set(binary.mode)
action(compileTask) task.dependsOn(kotlinTask)
compileTask.dependsOn(kotlinTask)
}
} }
tasksProvider.registerKotlinJsIrTask(project, binary.linkTaskName, configAction)
} }
project.whenEvaluated { project.whenEvaluated {
@@ -369,13 +345,11 @@ internal class KotlinCommonSourceSetProcessor(
} }
} }
// protected abstract fun doRegisterTask(project: Project, taskName: String, configureAction: (T) -> (Unit)): TaskHolder<out T> override fun doRegisterTask(project: Project, taskName: String): TaskProvider<out KotlinCompileCommon> {
override fun doRegisterTask( val configAction = KotlinCompileCommonConfig(kotlinCompilation)
project: Project, applyStandardTaskConfiguration(configAction)
taskName: String, return tasksProvider.registerKotlinCommonTask(project, taskName, kotlinCompilation.kotlinOptions, configAction)
configureAction: (KotlinCompileCommon) -> (Unit) }
): TaskProvider<out KotlinCompileCommon> =
tasksProvider.registerKotlinCommonTask(project, taskName, kotlinCompilation, configureAction)
} }
internal abstract class AbstractKotlinPlugin( internal abstract class AbstractKotlinPlugin(
@@ -683,7 +657,7 @@ internal open class KotlinAndroidPlugin(
companion object { companion object {
const val MINIMAL_SUPPORTED_AGP_VERSION = "3.6.4" const val MINIMAL_SUPPORTED_AGP_VERSION = "3.6.4"
fun androidTargetHandler(): AbstractAndroidProjectHandler { fun androidTargetHandler(): AbstractAndroidProjectHandler {
val tasksProvider = AndroidTasksProvider() val tasksProvider = KotlinTasksProvider()
if (androidPluginVersion != null) { if (androidPluginVersion != null) {
if (compareVersionNumbers(androidPluginVersion, MINIMAL_SUPPORTED_AGP_VERSION) < 0) { if (compareVersionNumbers(androidPluginVersion, MINIMAL_SUPPORTED_AGP_VERSION) < 0) {
@@ -957,15 +931,15 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationTool
val defaultSourceSet = project.kotlinExtension.sourceSets.maybeCreate(compilation.defaultSourceSetName) val defaultSourceSet = project.kotlinExtension.sourceSets.maybeCreate(compilation.defaultSourceSetName)
val kotlinTaskName = compilation.compileKotlinTaskName val configAction = KotlinCompileConfig(compilation)
configAction.configureTask { task ->
tasksProvider.registerKotlinJVMTask(project, kotlinTaskName, compilation) { task.parentKotlinOptionsImpl.value(rootKotlinOptions).disallowChanges()
it.parentKotlinOptionsImpl.set(rootKotlinOptions) task.useModuleDetection.value(true).disallowChanges()
// store kotlin classes in separate directory. They will serve as class-path to java compiler // store kotlin classes in separate directory. They will serve as class-path to java compiler
it.destinationDirectory.set(project.layout.buildDirectory.dir("tmp/kotlin-classes/$variantDataName")) task.destinationDirectory.set(project.layout.buildDirectory.dir("tmp/kotlin-classes/$variantDataName"))
it.description = "Compiles the $variantDataName kotlin." task.description = "Compiles the $variantDataName kotlin."
} }
tasksProvider.registerKotlinJVMTask(project, compilation.compileKotlinTaskName, compilation.kotlinOptions, configAction)
// Register the source only after the task is created, because the task is required for that: // Register the source only after the task is created, because the task is required for that:
compilation.source(defaultSourceSet) compilation.source(defaultSourceSet)
@@ -1026,33 +1000,6 @@ private fun SourceSet.clearJavaSrcDirs() {
java.setSrcDirs(emptyList<File>()) java.setSrcDirs(emptyList<File>())
} }
internal fun Task.registerSubpluginOptionsAsInputs(subpluginId: String, subpluginOptions: List<SubpluginOption>) {
// There might be several options with the same key. We group them together
// and add an index to the Gradle input property name to resolve possible duplication:
val pluginOptionsGrouped = subpluginOptions.groupBy { it.key }
for ((optionKey, optionsGroup) in pluginOptionsGrouped) {
optionsGroup.forEachIndexed { index, option ->
val indexSuffix = if (optionsGroup.size > 1) ".$index" else ""
when (option) {
is InternalSubpluginOption -> Unit
is CompositeSubpluginOption -> {
val subpluginIdWithWrapperKey = "$subpluginId.$optionKey$indexSuffix"
registerSubpluginOptionsAsInputs(subpluginIdWithWrapperKey, option.originalOptions)
}
is FilesSubpluginOption -> when (option.kind) {
FilesOptionKind.INTERNAL -> Unit
}.run { /* exhaustive when */ }
else -> {
inputs.property("$subpluginId." + option.key + indexSuffix, Callable { option.value })
}
}
}
}
}
//copied from BasePlugin.getLocalVersion //copied from BasePlugin.getLocalVersion
internal val androidPluginVersion by lazy { internal val androidPluginVersion by lazy {
try { try {
@@ -100,19 +100,13 @@ abstract class KotlinBasePluginWrapper : Plugin<Project> {
KotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion) KotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
val buildMetricReporter = BuildMetricsReporterService.registerIfAbsent(project) BuildMetricsReporterService.registerIfAbsent(project)?.also {
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it)
buildMetricReporter?.also { BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it) } }
HttpReportService.registerIfAbsent(project, kotlinPluginVersion) HttpReportService.registerIfAbsent(project, kotlinPluginVersion)
?.also { BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it) } ?.also { BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it) }
project.tasks.withType(AbstractKotlinCompile::class.java).configureEach {
if (buildMetricReporter != null) {
it.buildMetricsReporterService.set(buildMetricReporter)
}
}
project.createKotlinExtension(projectExtensionClass).apply { project.createKotlinExtension(projectExtensionClass).apply {
coreLibrariesVersion = kotlinPluginVersion coreLibrariesVersion = kotlinPluginVersion
@@ -36,37 +36,6 @@ import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import java.io.File import java.io.File
import java.util.* import java.util.*
internal fun PropertiesProvider.mapKotlinTaskProperties(task: AbstractKotlinCompile<*>) {
if (task is KotlinCompile) {
incrementalJvm?.let { task.incremental = it }
usePreciseJavaTracking?.let {
task.usePreciseJavaTracking = it
}
task.classpathSnapshotProperties.useClasspathSnapshot.value(useClasspathSnapshot).disallowChanges()
useFir?.let {
if (it == true) {
task.kotlinOptions.useFir = true
}
}
task.jvmTargetValidationMode.set(jvmTargetValidationMode)
task.useKotlinAbiSnapshot.value(useKotlinAbiSnapshot).disallowChanges()
}
if (task is Kotlin2JsCompile) {
incrementalJs?.let { task.incremental = it }
incrementalJsKlib?.let { task.incrementalJsKlib = it }
}
}
internal fun PropertiesProvider.mapKotlinDaemonProperties(task: CompileUsingKotlinDaemon) {
kotlinDaemonJvmArgs?.let {
task.kotlinDaemonJvmArguments.set(it.split("\\s+".toRegex()))
}
if (!task.compilerExecutionStrategy.isPresent) {
task.compilerExecutionStrategy.set(kotlinCompilerExecutionStrategy)
}
}
internal class PropertiesProvider private constructor(private val project: Project) { internal class PropertiesProvider private constructor(private val project: Project) {
private val localProperties: Properties by lazy { private val localProperties: Properties by lazy {
Properties().apply { Properties().apply {
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.logging.Logging import org.gradle.api.logging.Logging
import org.gradle.api.tasks.TaskProvider
/** /**
* This class encapsulated logic which should be invoked during not before the script evaluation is ready and * This class encapsulated logic which should be invoked during not before the script evaluation is ready and
@@ -45,14 +44,8 @@ internal class RunOnceAfterEvaluated(private val name: String, private val actio
} }
} }
internal fun Project.runOnceAfterEvaluated(name: String, task: TaskProvider<*>, action: () -> (Unit)) { internal fun Project.runOnceAfterEvaluated(name: String, action: () -> (Unit)) {
val runOnce = RunOnceAfterEvaluated(name, action) val runOnce = RunOnceAfterEvaluated(name, action)
runOnceAfterEvaluated(runOnce, task)
}
internal fun Project.runOnceAfterEvaluated(runOnce: RunOnceAfterEvaluated, task: TaskProvider<*>) {
whenEvaluated { runOnce.onEvaluated() } whenEvaluated { runOnce.onEvaluated() }
task.configure { runOnce.onConfigure()
runOnce.onConfigure()
}
} }
@@ -49,14 +49,20 @@ class SubpluginEnvironment(
val subpluginOptionsProvider = subplugin.applyToCompilation(kotlinCompilation) val subpluginOptionsProvider = subplugin.applyToCompilation(kotlinCompilation)
val subpluginId = subplugin.getCompilerPluginId() val subpluginId = subplugin.getCompilerPluginId()
val compilerOptions = subpluginOptionsProvider.map { subpluginOptions ->
val options = CompilerPluginOptions()
subpluginOptions.forEach { opt ->
options.addPluginArgument(subpluginId, opt)
}
options
}
val configureKotlinTask: (KotlinCompile<*>) -> Unit = { val configureKotlinTask: (KotlinCompile<*>) -> Unit = {
val pluginOptions = it.getPluginOptions() when (it) {
val subpluginOptions = subpluginOptionsProvider.get() is AbstractKotlinCompile<*> -> it.pluginOptions.add(compilerOptions)
for (option in subpluginOptions) { is KotlinNativeCompile -> it.compilerPluginOptions.addPluginArgument(compilerOptions.get())
pluginOptions.addPluginArgument(subpluginId, option) else -> error("Unexpected task ${it.name}, class: ${it.javaClass}")
} }
it.registerSubpluginOptionsAsInputs(subpluginId, subpluginOptions)
} }
kotlinCompilation.compileKotlinTaskProvider.configure(configureKotlinTask) kotlinCompilation.compileKotlinTaskProvider.configure(configureKotlinTask)
@@ -75,12 +81,6 @@ class SubpluginEnvironment(
return appliedSubplugins return appliedSubplugins
} }
private fun KotlinCompile<*>.getPluginOptions(): CompilerPluginOptions = when (this) {
is AbstractKotlinCompile<*> -> pluginOptions
is KotlinNativeCompile -> compilerPluginOptions
else -> error("Unexpected task ${this.name}, class: ${this.javaClass}")
}
private fun Project.addMavenDependency(configuration: String, artifact: SubpluginArtifact) { private fun Project.addMavenDependency(configuration: String, artifact: SubpluginArtifact) {
val artifactVersion = artifact.version ?: kotlinPluginVersion val artifactVersion = artifact.version ?: kotlinPluginVersion
val mavenCoordinate = "${artifact.groupId}:${artifact.artifactId}:$artifactVersion" val mavenCoordinate = "${artifact.groupId}:${artifact.artifactId}:$artifactVersion"
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile
import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions
import org.jetbrains.kotlin.project.model.LanguageSettings import org.jetbrains.kotlin.project.model.LanguageSettings
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics
@@ -76,7 +77,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
get() { get() {
val pluginOptionsTask = compilerPluginOptionsTask.value ?: return null val pluginOptionsTask = compilerPluginOptionsTask.value ?: return null
return when (pluginOptionsTask) { return when (pluginOptionsTask) {
is AbstractKotlinCompile<*> -> pluginOptionsTask.pluginOptions is AbstractKotlinCompile<*> -> pluginOptionsTask.pluginOptions.toSingleCompilerPluginOptions()
is AbstractKotlinNativeCompile<*, *, *> -> pluginOptionsTask.compilerPluginOptions is AbstractKotlinNativeCompile<*, *, *> -> pluginOptionsTask.compilerPluginOptions
else -> error("Unexpected task: $pluginOptionsTask") else -> error("Unexpected task: $pluginOptionsTask")
}.arguments }.arguments
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.gradle.targets.js.ir package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.file.ProjectLayout import org.gradle.api.file.ProjectLayout
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.work.NormalizeLineEndings import org.gradle.work.NormalizeLineEndings
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
@@ -46,18 +46,6 @@ abstract class KotlinJsIrLink @Inject constructor(
workerExecutor workerExecutor
) { ) {
class Configurator(compilation: KotlinCompilationData<*>) : Kotlin2JsCompile.Configurator<KotlinJsIrLink>(compilation) {
override fun configure(task: KotlinJsIrLink) {
super.configure(task)
task.entryModule.fileProvider(
(compilation as KotlinJsIrCompilation).output.classesDirs.elements.map { it.single().asFile }
).disallowChanges()
task.destinationDirectory.fileProvider(task.outputFileProperty.map { it.parentFile }).disallowChanges()
}
}
init { init {
// Not check sources, only klib module // Not check sources, only klib module
disallowSourceChanges() disallowSourceChanges()
@@ -88,11 +76,16 @@ abstract class KotlinJsIrLink @Inject constructor(
@get:Input @get:Input
val outputGranularity: KotlinJsIrOutputGranularity = propertiesProvider.jsIrOutputGranularity val outputGranularity: KotlinJsIrOutputGranularity = propertiesProvider.jsIrOutputGranularity
// Link tasks are not affected by compiler plugin @get:Internal
override val pluginClasspath: ConfigurableFileCollection = project.objects.fileCollection() @get:Deprecated("Please use modeProperty instead.")
var mode: KotlinJsBinaryMode
get() = modeProperty.get()
set(value) {
modeProperty.set(value)
}
@Input @get:Input
lateinit var mode: KotlinJsBinaryMode internal abstract val modeProperty: Property<KotlinJsBinaryMode>
private val buildDir = project.buildDir private val buildDir = project.buildDir
@@ -16,7 +16,10 @@
package org.jetbrains.kotlin.gradle.tasks package org.jetbrains.kotlin.gradle.tasks
import org.jetbrains.kotlin.gradle.plugin.CompilerPluginConfig import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.jetbrains.kotlin.gradle.plugin.*
class CompilerPluginOptions() : CompilerPluginConfig() { class CompilerPluginOptions() : CompilerPluginConfig() {
@@ -24,8 +27,10 @@ class CompilerPluginOptions() : CompilerPluginConfig() {
copyOptionsFrom(options) copyOptionsFrom(options)
} }
val subpluginOptionsByPluginId = optionsByPluginId @get:Internal
internal val subpluginOptionsByPluginId = optionsByPluginId
@get:Internal
val arguments: List<String> val arguments: List<String>
get() = optionsByPluginId.flatMap { (pluginId, subplubinOptions) -> get() = optionsByPluginId.flatMap { (pluginId, subplubinOptions) ->
subplubinOptions.map { option -> subplubinOptions.map { option ->
@@ -33,6 +38,10 @@ class CompilerPluginOptions() : CompilerPluginConfig() {
} }
} }
fun addPluginArgument(options: CompilerPluginOptions) {
copyOptionsFrom(options)
}
operator fun plus(options: CompilerPluginConfig?): CompilerPluginOptions { operator fun plus(options: CompilerPluginConfig?): CompilerPluginOptions {
if (options == null) return this if (options == null) return this
val newOptions = CompilerPluginOptions() val newOptions = CompilerPluginOptions()
@@ -42,9 +51,52 @@ class CompilerPluginOptions() : CompilerPluginConfig() {
return newOptions return newOptions
} }
@Input
fun getAsTaskInputArgs(): Map<String, String> {
val result = mutableMapOf<String, String>()
subpluginOptionsByPluginId.forEach { (id, subpluginOptions) ->
result += computeForSubpluginId(id, subpluginOptions)
}
return result
}
private fun computeForSubpluginId(subpluginId: String, subpluginOptions: List<SubpluginOption>): Map<String, String> {
// There might be several options with the same key. We group them together
// and add an index to the Gradle input property name to resolve possible duplication:
val result = mutableMapOf<String, String>()
val pluginOptionsGrouped = subpluginOptions.groupBy { it.key }
for ((optionKey, optionsGroup) in pluginOptionsGrouped) {
optionsGroup.forEachIndexed { index, option ->
val indexSuffix = if (optionsGroup.size > 1) ".$index" else ""
when (option) {
is InternalSubpluginOption -> return@forEachIndexed
is CompositeSubpluginOption -> {
val subpluginIdWithWrapperKey = "$subpluginId.$optionKey$indexSuffix"
result += computeForSubpluginId(subpluginIdWithWrapperKey, option.originalOptions)
}
is FilesSubpluginOption -> when (option.kind) {
FilesOptionKind.INTERNAL -> Unit
}.run { /* exhaustive when */ }
else -> {
result["$subpluginId." + option.key + indexSuffix] = option.value
}
}
}
}
return result
}
private fun copyOptionsFrom(options: CompilerPluginConfig) { private fun copyOptionsFrom(options: CompilerPluginConfig) {
options.allOptions().forEach { entry -> options.allOptions().forEach { entry ->
optionsByPluginId[entry.key] = entry.value.toMutableList() optionsByPluginId[entry.key] = entry.value.toMutableList()
} }
} }
}
internal fun ListProperty<CompilerPluginOptions>.toSingleCompilerPluginOptions(): CompilerPluginOptions {
val values = this.orNull ?: return CompilerPluginOptions()
return values.reduceOrNull(CompilerPluginOptions::plus) ?: CompilerPluginOptions()
} }
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.gradle.tasks package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
@@ -32,13 +31,6 @@ import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.AbstractKotlinFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.dependsOnClosure
import org.jetbrains.kotlin.gradle.utils.propertyWithConvention import org.jetbrains.kotlin.gradle.utils.propertyWithConvention
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
@@ -51,41 +43,6 @@ abstract class KotlinCompileCommon @Inject constructor(
) : AbstractKotlinCompile<K2MetadataCompilerArguments>(objectFactory), ) : AbstractKotlinCompile<K2MetadataCompilerArguments>(objectFactory),
KotlinCommonCompile { KotlinCommonCompile {
class Configurator(compilation: KotlinCompilationData<*>) : AbstractKotlinCompile.Configurator<KotlinCompileCommon>(compilation) {
override fun configure(task: KotlinCompileCommon) {
super.configure(task)
task.refinesMetadataPaths.from(getRefinesMetadataPaths(task.project)).disallowChanges()
task.expectActualLinker
.value(task.project.provider { (compilation as? KotlinCommonCompilation)?.isKlibCompilation == true || compilation is KotlinMetadataCompilationData })
.disallowChanges()
}
private fun getRefinesMetadataPaths(project: Project): Provider<Iterable<File>> {
return project.provider {
when (compilation) {
is KotlinCompilation<*> -> {
val defaultKotlinSourceSet: KotlinSourceSet = compilation.defaultSourceSet
val metadataTarget = compilation.owner as KotlinTarget
defaultKotlinSourceSet.dependsOnClosure
.mapNotNull { sourceSet -> metadataTarget.compilations.findByName(sourceSet.name)?.output?.classesDirs }
.flatten()
}
is AbstractKotlinFragmentMetadataCompilationData -> {
val fragment = compilation.fragment
project.files(
fragment.refinesClosure.map {
val compilation = compilation.metadataCompilationRegistry.getForFragmentOrNull(it)
?: return@map project.files()
compilation.output.classesDirs
}
)
}
else -> error("unexpected compilation type")
}
}
}
}
override val compilerRunner: Provider<GradleCompilerRunner> = override val compilerRunner: Provider<GradleCompilerRunner> =
objectFactory.propertyWithConvention( objectFactory.propertyWithConvention(
gradleCompileTaskProvider.map { gradleCompileTaskProvider.map {
@@ -10,7 +10,6 @@ import org.gradle.api.DefaultTask
import org.gradle.api.GradleException import org.gradle.api.GradleException
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.attributes.Attribute
import org.gradle.api.file.* import org.gradle.api.file.*
import org.gradle.api.invocation.Gradle import org.gradle.api.invocation.Gradle
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
@@ -46,21 +45,17 @@ import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings
import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.incremental.* import org.jetbrains.kotlin.gradle.incremental.*
import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.*
import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.internal.transforms.ClasspathEntrySnapshotTransform
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.report.BuildMetricsReporterService import org.jetbrains.kotlin.gradle.report.BuildMetricsReporterService
import org.jetbrains.kotlin.gradle.report.BuildReportMode import org.jetbrains.kotlin.gradle.report.BuildReportMode
import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.report.ReportingSettings
import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib
import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled
@@ -261,42 +256,6 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
) : AbstractKotlinCompileTool<T>(objectFactory), ) : AbstractKotlinCompileTool<T>(objectFactory),
CompileUsingKotlinDaemonWithNormalization { CompileUsingKotlinDaemonWithNormalization {
open class Configurator<T : AbstractKotlinCompile<*>>(protected val compilation: KotlinCompilationData<*>) : TaskConfigurator<T> {
override fun configure(task: T) {
val project = task.project
task.friendPaths.from(project.provider { compilation.friendPaths })
if (compilation is KotlinCompilation<*>) {
task.friendSourceSets.set(project.provider { compilation.associateWithClosure.map { it.name } })
// FIXME support compiler plugins with PM20
task.pluginClasspath.from(project.configurations.getByName(compilation.pluginConfigurationName))
}
task.moduleName.set(project.provider { compilation.moduleName })
task.sourceSetName.set(project.provider { compilation.compilationPurpose })
task.multiPlatformEnabled.value(
project.provider {
project.plugins.any {
it is KotlinPlatformPluginBase ||
it is AbstractKotlinMultiplatformPluginWrapper ||
it is AbstractKotlinPm20PluginWrapper
}
}
).disallowChanges()
task.taskBuildCacheableOutputDirectory.value(getKotlinBuildDir(task).map { it.dir("cacheable") }).disallowChanges()
task.taskBuildLocalStateDirectory.value(getKotlinBuildDir(task).map { it.dir("local-state") }).disallowChanges()
task.localStateDirectories.from(task.taskBuildLocalStateDirectory).disallowChanges()
PropertiesProvider(task.project).mapKotlinDaemonProperties(task)
}
private fun getKotlinBuildDir(task: T): Provider<Directory> =
task.project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/${task.name}")
protected fun getClasspathSnapshotDir(task: T): Provider<Directory> =
getKotlinBuildDir(task).map { it.dir("classpath-snapshot") }
}
init { init {
cacheOnlyIfEnabledForKotlin() cacheOnlyIfEnabledForKotlin()
} }
@@ -312,7 +271,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
// avoid creating directory in getter: this can lead to failure in parallel build // avoid creating directory in getter: this can lead to failure in parallel build
@get:LocalState @get:LocalState
internal val taskBuildLocalStateDirectory: DirectoryProperty = objectFactory.directoryProperty() internal abstract val taskBuildLocalStateDirectory: DirectoryProperty
@get:Internal @get:Internal
internal val buildHistoryFile internal val buildHistoryFile
@@ -342,7 +301,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
internal fun reportingSettings() = buildMetricsReporterService.orNull?.parameters?.reportingSettings ?: ReportingSettings() internal fun reportingSettings() = buildMetricsReporterService.orNull?.parameters?.reportingSettings ?: ReportingSettings()
@get:Input @get:Input
internal val useModuleDetection: Property<Boolean> = objectFactory.property(Boolean::class.java).value(false) internal abstract val useModuleDetection: Property<Boolean>
@get:Internal @get:Internal
protected val multiModuleICSettings: MultiModuleICSettings protected val multiModuleICSettings: MultiModuleICSettings
@@ -350,10 +309,10 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
@get:NormalizeLineEndings @get:NormalizeLineEndings
@get:Classpath @get:Classpath
open val pluginClasspath: ConfigurableFileCollection = objectFactory.fileCollection() abstract val pluginClasspath: ConfigurableFileCollection
@get:Internal @get:Nested
internal val pluginOptions = CompilerPluginOptions() internal abstract val pluginOptions: ListProperty<CompilerPluginOptions>
/** /**
@@ -368,7 +327,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
internal val javaOutputDir: DirectoryProperty = objectFactory.directoryProperty() internal val javaOutputDir: DirectoryProperty = objectFactory.directoryProperty()
@get:Internal @get:Internal
internal val sourceSetName: Property<String> = objectFactory.property(String::class.java) internal abstract val sourceSetName: Property<String>
@get:InputFiles @get:InputFiles
@get:IgnoreEmptyDirectories @get:IgnoreEmptyDirectories
@@ -378,7 +337,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
internal val commonSourceSet: ConfigurableFileCollection = objectFactory.fileCollection() internal val commonSourceSet: ConfigurableFileCollection = objectFactory.fileCollection()
@get:Input @get:Input
internal val moduleName: Property<String> = objectFactory.property(String::class.java) internal abstract val moduleName: Property<String>
@get:Internal @get:Internal
val abiSnapshotFile val abiSnapshotFile
@@ -394,12 +353,10 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
internal val friendSourceSets = objectFactory.listProperty(String::class.java) internal val friendSourceSets = objectFactory.listProperty(String::class.java)
@get:Internal // takes part in the compiler arguments @get:Internal // takes part in the compiler arguments
val friendPaths: ConfigurableFileCollection = objectFactory.fileCollection() abstract val friendPaths: ConfigurableFileCollection
private val kotlinLogger by lazy { GradleKotlinLogger(logger) } private val kotlinLogger by lazy { GradleKotlinLogger(logger) }
abstract override val kotlinDaemonJvmArguments: ListProperty<String>
@get:Internal @get:Internal
protected val gradleCompileTaskProvider: Provider<GradleCompileTaskProvider> = objectFactory protected val gradleCompileTaskProvider: Provider<GradleCompileTaskProvider> = objectFactory
.property( .property(
@@ -473,8 +430,6 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
protected open fun skipCondition(): Boolean = sources.isEmpty protected open fun skipCondition(): Boolean = sources.isEmpty
private val projectDir = project.rootProject.projectDir
@get:Internal @get:Internal
protected open val incrementalProps: List<FileCollection> protected open val incrementalProps: List<FileCollection>
get() = listOfNotNull( get() = listOfNotNull(
@@ -489,7 +444,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
) { ) {
val allKotlinSources = sources.asFileTree.files val allKotlinSources = sources.asFileTree.files
logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(projectDir)}" } logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(gradleCompileTaskProvider.get().projectDir.get())}" }
if (!inputChanges.isIncremental && skipCondition()) { if (!inputChanges.isIncremental && skipCondition()) {
// Skip running only if non-incremental run. Otherwise, we may need to do some cleanup. // Skip running only if non-incremental run. Otherwise, we may need to do some cleanup.
@@ -542,7 +497,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
) )
@get:Input @get:Input
internal val multiPlatformEnabled: Property<Boolean> = objectFactory.property(Boolean::class.java) internal abstract val multiPlatformEnabled: Property<Boolean>
@get:Internal @get:Internal
internal val abstractKotlinCompileArgumentsContributor by lazy { internal val abstractKotlinCompileArgumentsContributor by lazy {
@@ -568,8 +523,7 @@ open class KotlinCompileArgumentsProvider<T : AbstractKotlinCompile<out CommonCo
val isMultiplatform: Boolean = taskProvider.multiPlatformEnabled.get() val isMultiplatform: Boolean = taskProvider.multiPlatformEnabled.get()
private val pluginData = taskProvider.kotlinPluginData?.orNull private val pluginData = taskProvider.kotlinPluginData?.orNull
val pluginClasspath: FileCollection = listOfNotNull(taskProvider.pluginClasspath, pluginData?.classpath).reduce(FileCollection::plus) val pluginClasspath: FileCollection = listOfNotNull(taskProvider.pluginClasspath, pluginData?.classpath).reduce(FileCollection::plus)
val pluginOptions: CompilerPluginOptions = val pluginOptions: CompilerPluginOptions = taskProvider.pluginOptions.toSingleCompilerPluginOptions() + pluginData?.options
listOfNotNull(taskProvider.pluginOptions, pluginData?.options).reduce(CompilerPluginOptions::plus)
} }
class KotlinJvmCompilerArgumentsProvider class KotlinJvmCompilerArgumentsProvider
@@ -596,101 +550,8 @@ abstract class KotlinCompile @Inject constructor(
KotlinJvmCompile, KotlinJvmCompile,
UsesKotlinJavaToolchain { UsesKotlinJavaToolchain {
internal open class Configurator<T : KotlinCompile>( @get:Internal("Takes part in compiler args.")
kotlinCompilation: KotlinCompilationData<*>, internal abstract val parentKotlinOptionsImpl: Property<KotlinJvmOptions>
private val properties: PropertiesProvider
) : AbstractKotlinCompile.Configurator<T>(kotlinCompilation) {
companion object {
private const val TRANSFORMS_REGISTERED = "_kgp_internal_kotlin_compile_transforms_registered"
val ARTIFACT_TYPE_ATTRIBUTE: Attribute<String> = Attribute.of("artifactType", String::class.java)
private const val DIRECTORY_ARTIFACT_TYPE = "directory"
private const val JAR_ARTIFACT_TYPE = "jar"
const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot"
}
/**
* Prepares for configuration of the task. This method must be called during build configuration, not during task configuration
* (which typically happens after build configuration). The reason is that some actions must be performed early (e.g., creating
* configurations should be done early to avoid issues with composite builds (https://issuetracker.google.com/183952598)).
*/
fun runAtConfigurationTime(taskProvider: TaskProvider<T>, project: Project) {
if (properties.useClasspathSnapshot) {
registerTransformsOnce(project)
project.configurations.create(classpathSnapshotConfigurationName(taskProvider.name)).apply {
project.dependencies.add(name, project.files(project.provider { taskProvider.get().libraries }))
}
}
}
private fun registerTransformsOnce(project: Project) {
if (project.extensions.extraProperties.has(TRANSFORMS_REGISTERED)) {
return
}
project.extensions.extraProperties[TRANSFORMS_REGISTERED] = true
val buildMetricsReporterService = BuildMetricsReporterService.registerIfAbsent(project)
project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) {
it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, JAR_ARTIFACT_TYPE)
it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
it.parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir)
buildMetricsReporterService?.apply { it.parameters.buildMetricsReporterService.set(this) }
}
project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) {
it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DIRECTORY_ARTIFACT_TYPE)
it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
it.parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir)
buildMetricsReporterService?.apply { it.parameters.buildMetricsReporterService.set(this) }
}
}
private fun classpathSnapshotConfigurationName(taskName: String) = "_kgp_internal_${taskName}_classpath_snapshot"
override fun configure(task: T) {
super.configure(task)
val compileJavaTaskProvider = when (compilation) {
is KotlinJvmCompilation -> compilation.compileJavaTaskProvider
is KotlinJvmAndroidCompilation -> compilation.compileJavaTaskProvider
is KotlinWithJavaCompilation -> compilation.compileJavaTaskProvider
else -> null
}
if (compileJavaTaskProvider != null) {
task.associatedJavaCompileTaskTargetCompatibility.set(
compileJavaTaskProvider.map { it.targetCompatibility }
)
task.associatedJavaCompileTaskSources.from(
compileJavaTaskProvider.map { javaTask ->
javaTask.source
}
)
task.associatedJavaCompileTaskName.set(
compileJavaTaskProvider.map { it.name }
)
}
task.moduleName.set(task.project.provider {
task.kotlinOptions.moduleName ?: task.parentKotlinOptionsImpl.orNull?.moduleName ?: compilation.moduleName
})
if (properties.useClasspathSnapshot) {
val classpathSnapshot = task.project.configurations.getByName(classpathSnapshotConfigurationName(task.name))
task.classpathSnapshotProperties.classpathSnapshot.from(
classpathSnapshot.incoming.artifactView {
it.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
}.files
)
val classpathSnapshotDir = getClasspathSnapshotDir(task)
task.classpathSnapshotProperties.classpathSnapshotDir.value(classpathSnapshotDir).disallowChanges()
} else {
task.classpathSnapshotProperties.classpath.from(task.project.provider { task.libraries })
}
}
}
@get:Internal
internal val parentKotlinOptionsImpl: Property<KotlinJvmOptions> = objectFactory.property(KotlinJvmOptions::class.java)
/** A package prefix that is used for locating Java sources in a directory structure with non-full-depth packages. /** A package prefix that is used for locating Java sources in a directory structure with non-full-depth packages.
* *
@@ -1070,33 +931,6 @@ abstract class Kotlin2JsCompile @Inject constructor(
incremental = true incremental = true
} }
open class Configurator<T : Kotlin2JsCompile>(compilation: KotlinCompilationData<*>) :
AbstractKotlinCompile.Configurator<T>(compilation) {
override fun configure(task: T) {
super.configure(task)
task.outputFileProperty.value(
task.project.provider {
task.kotlinOptions.outputFile?.let(::File)
?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}.js")
}
).disallowChanges()
task.optionalOutputFile.fileProvider(
task.outputFileProperty.flatMap { outputFile ->
task.project.provider {
outputFile.takeUnless { task.kotlinOptions.isProduceUnzippedKlib() }
}
}
).disallowChanges()
val libraryCacheService = task.project.rootProject.gradle.sharedServices.registerIfAbsent(
"${LibraryFilterCachingService::class.java.canonicalName}_${LibraryFilterCachingService::class.java.classLoader.hashCode()}",
LibraryFilterCachingService::class.java
) {}
task.libraryCache.set(libraryCacheService).also { task.libraryCache.disallowChanges() }
}
}
internal abstract class LibraryFilterCachingService : BuildService<BuildServiceParameters.None>, AutoCloseable { internal abstract class LibraryFilterCachingService : BuildService<BuildServiceParameters.None>, AutoCloseable {
internal data class LibraryFilterCacheKey(val dependency: File, val irEnabled: Boolean, val preIrDisabled: Boolean) internal data class LibraryFilterCacheKey(val dependency: File, val irEnabled: Boolean, val preIrDisabled: Boolean)
@@ -21,12 +21,9 @@ import org.gradle.api.Task
import org.gradle.api.UnknownTaskException import org.gradle.api.UnknownTaskException
import org.gradle.api.tasks.TaskCollection import org.gradle.api.tasks.TaskCollection
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.runOnceAfterEvaluated
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink
import org.jetbrains.kotlin.gradle.tasks.configuration.*
/** /**
* Registers the task with [name] and [type] and initialization script [body] * Registers the task with [name] and [type] and initialization script [body]
@@ -92,114 +89,42 @@ internal inline fun <reified T : Task> Project.locateOrRegisterTask(
internal open class KotlinTasksProvider { internal open class KotlinTasksProvider {
open fun registerKotlinJVMTask( open fun registerKotlinJVMTask(
project: Project, project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: KotlinCompileConfig
name: String,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinCompile) -> (Unit)
): TaskProvider<out KotlinCompile> { ): TaskProvider<out KotlinCompile> {
val properties = PropertiesProvider(project) return project.registerTask(taskName, KotlinCompile::class.java, constructorArgs = listOf(kotlinOptions)).also {
val kotlinCompile = project.registerTask( configuration.execute(it)
name,
KotlinCompile::class.java,
constructorArgs = listOf(compilation.kotlinOptions)
)
val configurator = KotlinCompile.Configurator<KotlinCompile>(compilation, properties)
configurator.runAtConfigurationTime(kotlinCompile, project)
kotlinCompile.configure {
configureAction(it)
configurator.configure(it)
} }
configure(kotlinCompile, project, properties, compilation)
return kotlinCompile
} }
fun registerKotlinJSTask( fun registerKotlinJSTask(
project: Project, project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: Kotlin2JsCompileConfig
name: String,
compilation: KotlinCompilationData<*>,
configureAction: (Kotlin2JsCompile) -> Unit
): TaskProvider<out Kotlin2JsCompile> { ): TaskProvider<out Kotlin2JsCompile> {
val properties = PropertiesProvider(project) return project.registerTask(
val result = project.registerTask( taskName,
name,
Kotlin2JsCompile::class.java, Kotlin2JsCompile::class.java,
constructorArgs = listOf(compilation.kotlinOptions) constructorArgs = listOf(kotlinOptions)
) { ).also {
configureAction(it) configuration.execute(it)
Kotlin2JsCompile.Configurator<Kotlin2JsCompile>(compilation).configure(it)
} }
configure(result, project, properties, compilation)
return result
} }
fun registerKotlinJsIrTask( fun registerKotlinJsIrTask(
project: Project, project: Project, taskName: String, configuration: KotlinJsIrLinkConfig
name: String,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinJsIrLink) -> Unit
): TaskProvider<out KotlinJsIrLink> { ): TaskProvider<out KotlinJsIrLink> {
val properties = PropertiesProvider(project) return project.registerTask(taskName, KotlinJsIrLink::class.java).also {
val result = project.registerTask( configuration.execute(it)
name,
KotlinJsIrLink::class.java
) {
it.compilation = compilation
configureAction(it)
KotlinJsIrLink.Configurator(compilation).configure(it)
} }
configure(result, project, properties, compilation)
return result
} }
fun registerKotlinCommonTask( fun registerKotlinCommonTask(
project: Project, project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: KotlinCompileCommonConfig
name: String,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinCompileCommon) -> (Unit)
): TaskProvider<out KotlinCompileCommon> { ): TaskProvider<out KotlinCompileCommon> {
val properties = PropertiesProvider(project) return project.registerTask(
val result = project.registerTask( taskName,
name,
KotlinCompileCommon::class.java, KotlinCompileCommon::class.java,
constructorArgs = listOf(compilation.kotlinOptions) constructorArgs = listOf(kotlinOptions)
) { ).also {
configureAction(it) configuration.execute(it)
KotlinCompileCommon.Configurator(compilation).configure(it)
}
configure(result, project, properties, compilation)
return result
}
open fun configure(
kotlinTaskHolder: TaskProvider<out AbstractKotlinCompile<*>>,
project: Project,
propertiesProvider: PropertiesProvider,
compilation: KotlinCompilationData<*>
) {
project.runOnceAfterEvaluated("apply properties and language settings to ${kotlinTaskHolder.name}", kotlinTaskHolder) {
propertiesProvider.mapKotlinTaskProperties(kotlinTaskHolder.get())
applyLanguageSettingsToKotlinOptions(
compilation.languageSettings,
(kotlinTaskHolder.get() as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>).kotlinOptions
)
}
}
}
internal class AndroidTasksProvider : KotlinTasksProvider() {
override fun configure(
kotlinTaskHolder: TaskProvider<out AbstractKotlinCompile<*>>,
project: Project,
propertiesProvider: PropertiesProvider,
compilation: KotlinCompilationData<*>
) {
super.configure(kotlinTaskHolder, project, propertiesProvider, compilation)
kotlinTaskHolder.configure {
it.useModuleDetection.set(true)
} }
} }
} }
@@ -0,0 +1,131 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.Directory
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithClosure
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions
import org.jetbrains.kotlin.gradle.report.BuildMetricsReporterService
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME
import java.util.concurrent.Callable
/**
* Configuration for the base compile task, [org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile].
*
* This contains all data necessary to configure the tasks, and should avoid exposing global state (project, extensions, other tasks)
* to the task instance as much as possible.
*/
internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile<*>>(
project: Project,
) : TaskConfigAction<TASK>(project) {
constructor(compilation: KotlinCompilationData<*>) : this(compilation.project) {
val ext = compilation.project.topLevelExtension
configureTaskProvider { taskProvider ->
project.runOnceAfterEvaluated("apply properties and language settings to ${taskProvider.name}") {
taskProvider.configure {
applyLanguageSettingsToKotlinOptions(
compilation.languageSettings, (it as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>).kotlinOptions
)
}
}
}
configureTask { task ->
task.friendPaths.from({ compilation.friendPaths })
if (compilation is KotlinCompilation<*>) {
task.friendSourceSets.value(providers.provider { compilation.associateWithClosure.map { it.name } })
.disallowChanges()
task.pluginClasspath.from(compilation.project.configurations.getByName(compilation.pluginConfigurationName))
}
task.moduleName.set(providers.provider { compilation.moduleName })
task.sourceSetName.value(providers.provider { compilation.compilationPurpose })
task.multiPlatformEnabled.value(
providers.provider {
compilation.project.plugins.any {
it is KotlinPlatformPluginBase ||
it is AbstractKotlinMultiplatformPluginWrapper ||
it is AbstractKotlinPm20PluginWrapper
}
}
)
val propertiesProvider = project.kotlinPropertiesProvider
task.taskBuildCacheableOutputDirectory
.value(getKotlinBuildDir(task).map { it.dir("cacheable") })
.disallowChanges()
task.taskBuildLocalStateDirectory
.value(getKotlinBuildDir(task).map { it.dir("local-state") })
.disallowChanges()
task.localStateDirectories.from(task.taskBuildLocalStateDirectory).disallowChanges()
BuildMetricsReporterService.registerIfAbsent(project)?.let {
task.buildMetricsReporterService.value(it)
}
propertiesProvider.kotlinDaemonJvmArgs?.let { kotlinDaemonJvmArgs ->
task.kotlinDaemonJvmArguments.set(providers.provider {
kotlinDaemonJvmArgs.split("\\s+".toRegex())
})
}
task.compilerExecutionStrategy.value(propertiesProvider.kotlinCompilerExecutionStrategy)
// Default values
task.incremental = false
task.useModuleDetection.convention(false)
}
}
private fun getKotlinBuildDir(task: TASK): Provider<Directory> =
task.project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/${task.name}")
protected fun getClasspathSnapshotDir(task: TASK): Provider<Directory> =
getKotlinBuildDir(task).map { it.dir("classpath-snapshot") }
}
internal abstract class TaskConfigAction<TASK : Task>(protected val project: Project) {
protected val objectFactory: ObjectFactory = project.objects
protected val providers: ProviderFactory = project.providers
protected val propertiesProvider = project.kotlinPropertiesProvider
private var executed = false
// Collect all task configurations, and run them later (in order they were added).
private val taskConfigActions = ArrayDeque<(TaskProvider<TASK>) -> Unit>()
fun configureTaskProvider(configAction: (TaskProvider<TASK>) -> Unit) {
check(!executed) {
"Task has already been configured. Configuration actions should be added to this object before `this.execute` method runs."
}
taskConfigActions.addLast(configAction)
}
fun configureTask(configAction: (TASK) -> Unit) {
configureTaskProvider { taskProvider ->
taskProvider.configure(configAction)
}
}
fun execute(taskProvider: TaskProvider<TASK>) {
executed = true
taskConfigActions.forEach {
it(taskProvider)
}
}
}
@@ -0,0 +1,243 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
package org.jetbrains.kotlin.gradle.tasks.configuration
import com.intellij.openapi.util.SystemInfo
import com.intellij.util.lang.JavaVersion
import org.gradle.api.Project
import org.gradle.api.attributes.Attribute
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
import org.jetbrains.kotlin.gradle.internal.*
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_SUBPLUGIN_ID
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.classLoadersCacheSize
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.disableClassloaderCacheForProcessors
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isIncludeCompileClasspath
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isIncrementalKapt
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformAction
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction
import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinAndroidPluginWrapper
import org.jetbrains.kotlin.gradle.plugin.KaptExtension
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
import org.jetbrains.kotlin.gradle.utils.listProperty
import java.io.File
import java.util.concurrent.Callable
internal open class KaptConfigAction<TASK : KaptTask>(
project: Project,
protected val ext: KaptExtension,
) : TaskConfigAction<TASK>(project) {
internal constructor(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : this(kotlinCompileTask.project, ext) {
configureTaskProvider { taskProvider ->
val kaptClasspathSnapshot = getKaptClasspathSnapshot(taskProvider)
taskProvider.configure { task ->
task.classpath.from(kotlinCompileTask.libraries)
task.compiledSources.from(
kotlinCompileTask.destinationDirectory,
Callable { kotlinCompileTask.javaOutputDir.takeIf { it.isPresent } })
.disallowChanges()
task.sourceSetName.value(kotlinCompileTask.sourceSetName).disallowChanges()
val kaptSources = objectFactory
.fileCollection()
.from(kotlinCompileTask.javaSources, task.stubsDir)
.asFileTree
.matching { it.include("**/*.java") }
.filter {
it.exists() &&
!isAncestor(task.destinationDir.get().asFile, it) &&
!isAncestor(task.classesDir.get().asFile, it)
}
task.source.from(kaptSources).disallowChanges()
task.verbose.set(KaptTask.queryKaptVerboseProperty(project))
task.compilerClasspath.from(providers.provider { kotlinCompileTask.defaultCompilerClasspath })
task.isIncremental = project.isIncrementalKapt()
task.useBuildCache = ext.useBuildCache
task.includeCompileClasspath.set(ext.includeCompileClasspath ?: project.isIncludeCompileClasspath())
task.classpathStructure.from(kaptClasspathSnapshot)
task.localStateDirectories.from(Callable { task.incAptCache.orNull })
task.onlyIf {
it as KaptTask
it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty
}
}
}
}
private fun getKaptClasspathSnapshot(taskProvider: TaskProvider<TASK>): FileCollection? {
return if (project.isIncrementalKapt()) {
maybeRegisterTransform(project)
val classStructureConfiguration = project.configurations.detachedConfiguration()
// Wrap the `kotlinCompile.classpath` into a file collection, so that, if the classpath is represented by a configuration,
// the configuration is not extended (via extendsFrom, which normally happens when one configuration is _added_ into another)
// but is instead included as the (lazily) resolved files. This is needed because the class structure configuration doesn't have
// the attributes that are potentially needed to resolve dependencies on MPP modules, and the classpath configuration does.
classStructureConfiguration.dependencies.add(project.dependencies.create(project.files(project.provider { taskProvider.get().classpath })))
classStructureConfiguration.incoming.artifactView { viewConfig ->
viewConfig.attributes.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}.files
} else null
}
private fun maybeRegisterTransform(project: Project) {
if (!project.extensions.extraProperties.has("KaptStructureTransformAdded")) {
val transformActionClass =
if (GradleVersion.current() >= GradleVersion.version("5.4"))
StructureTransformAction::class.java
else
StructureTransformLegacyAction::class.java
project.dependencies.registerTransform(transformActionClass) { transformSpec ->
transformSpec.from.attribute(artifactType, "jar")
transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}
project.dependencies.registerTransform(transformActionClass) { transformSpec ->
transformSpec.from.attribute(artifactType, "directory")
transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}
project.extensions.extraProperties["KaptStructureTransformAdded"] = true
}
}
internal fun getJavaOptions(defaultJavaSourceCompatibility: Provider<String>): Provider<Map<String, String>> {
return providers.provider {
ext.getJavacOptions().toMutableMap().also { result ->
if ("-source" in result || "--source" in result || "--release" in result) return@also
if (defaultJavaSourceCompatibility.isPresent) {
val atLeast12Java =
if (isConfigurationCacheAvailable(project.gradle)) {
val currentJavaVersion =
JavaVersion.parse(project.providers.systemProperty("java.version").forUseAtConfigurationTime().get())
currentJavaVersion.feature >= 12
} else {
SystemInfo.isJavaVersionAtLeast(12, 0, 0)
}
val sourceOptionKey = if (atLeast12Java) {
"--source"
} else {
"-source"
}
result[sourceOptionKey] = defaultJavaSourceCompatibility.get()
}
}
}
}
}
//Have to avoid using FileUtil because it is required system property reading that is not allowed for configuration cache
private fun isAncestor(dir: File, file: File): Boolean {
val path = file.canonicalPath
val prefix = dir.canonicalPath
val pathLength = path.length
val prefixLength = prefix.length
val caseSensitive = true
return if (prefixLength == 0) {
true
} else if (prefixLength > pathLength) {
false
} else if (!path.regionMatches(0, prefix, 0, prefixLength, ignoreCase = !caseSensitive)) {
return false
} else if (pathLength == prefixLength) {
return true
} else {
val lastPrefixChar: Char = prefix.get(prefixLength - 1)
var slashOrSeparatorIdx = prefixLength
if (lastPrefixChar == '/' || lastPrefixChar == File.separatorChar) {
slashOrSeparatorIdx = prefixLength - 1
}
val next1 = path[slashOrSeparatorIdx]
return !(next1 != '/' && next1 != File.separatorChar)
}
}
internal class KaptWithoutKotlincConfigAction(kotlinCompileTask: KotlinCompile, ext: KaptExtension) :
KaptConfigAction<KaptWithoutKotlincTask>(kotlinCompileTask, ext) {
init {
initKaptWorkersConfiguration(project.topLevelExtension)
configureTask { task ->
task.addJdkClassesToClasspath.set(
project.providers.provider {
project.plugins.none { it is AbstractKotlinAndroidPluginWrapper }
}
)
task.kaptJars.from(project.configurations.getByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME))
task.mapDiagnosticLocations = ext.mapDiagnosticLocations
task.annotationProcessorFqNames.set(providers.provider { ext.processors.split(',').filter { it.isNotEmpty() } })
task.disableClassloaderCacheForProcessors = project.disableClassloaderCacheForProcessors()
task.classLoadersCacheSize = project.classLoadersCacheSize()
task.javacOptions.set(getJavaOptions(task.defaultJavaSourceCompatibility))
}
}
private fun initKaptWorkersConfiguration(kotlinExt: KotlinTopLevelExtension) {
project.configurations.findByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)
?: project.configurations.create(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply {
dependencies.addAllLater(project.listProperty {
val kaptDependency = "org.jetbrains.kotlin:kotlin-annotation-processing-gradle:${project.getKotlinPluginVersion()}"
listOf(
project.dependencies.create(kaptDependency),
project.kotlinDependency(
"kotlin-stdlib",
kotlinExt.coreLibrariesVersion
)
)
})
}
}
}
internal class KaptWithKotlincConfigAction(kotlinCompileTask: KotlinCompile, ext: KaptExtension) :
KaptConfigAction<KaptWithKotlincTask>(kotlinCompileTask, ext) {
init {
configureTask { task ->
if (project.isIncrementalKapt()) {
val incAptCacheOption = task.incAptCache.locationOnly.map { incAptCacheDir ->
CompilerPluginOptions().also {
it.addPluginArgument(
KAPT_SUBPLUGIN_ID, SubpluginOption("incrementalCache", lazy { incAptCacheDir.asFile.absolutePath })
)
}
}
task.kaptPluginOptions.add(incAptCacheOption)
}
task.pluginClasspath.from(kotlinCompileTask.pluginClasspath)
task.additionalPluginOptionsAsInputs.value(kotlinCompileTask.pluginOptions).disallowChanges()
task.compileKotlinArgumentsContributor.set(providers.provider { kotlinCompileTask.compilerArgumentsContributor })
task.javaPackagePrefix.set(providers.provider { kotlinCompileTask.javaPackagePrefix })
task.reportingSettings.set(providers.provider { kotlinCompileTask.reportingSettings() })
propertiesProvider.kotlinDaemonJvmArgs?.let {
task.kotlinDaemonJvmArguments.value(it.split("\\s+".toRegex())).disallowChanges()
}
task.compilerExecutionStrategy.value(propertiesProvider.kotlinCompilerExecutionStrategy).disallowChanges()
}
}
}
private val artifactType = Attribute.of("artifactType", String::class.java)
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_SUBPLUGIN_ID
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isIncludeCompileClasspath
import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask
import org.jetbrains.kotlin.gradle.internal.KaptTask
import org.jetbrains.kotlin.gradle.internal.buildKaptSubpluginOptions
import org.jetbrains.kotlin.gradle.plugin.KaptExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.util.concurrent.Callable
internal class KaptGenerateStubsConfig(compilation: KotlinCompilationData<*>, kotlinTaskProvider: TaskProvider<KotlinCompile>) :
BaseKotlinCompileConfig<KaptGenerateStubsTask>(compilation) {
private val kaptExtension: KaptExtension = project.extensions.getByType(KaptExtension::class.java)
init {
configureTask { task ->
val kotlinCompileTask = kotlinTaskProvider.get()
task.useModuleDetection.value(kotlinCompileTask.useModuleDetection).disallowChanges()
task.moduleName.value(kotlinCompileTask.moduleName).disallowChanges()
task.libraries.from({ kotlinCompileTask.libraries })
task.compileKotlinArgumentsContributor.set(providers.provider { kotlinCompileTask.compilerArgumentsContributor })
task.verbose.set(KaptTask.queryKaptVerboseProperty(project))
task.pluginOptions.add(buildOptions(task))
if (!isIncludeCompileClasspath()) {
task.onlyIf {
!(it as KaptGenerateStubsTask).kaptClasspath.isEmpty
}
}
}
}
private fun isIncludeCompileClasspath() = kaptExtension.includeCompileClasspath ?: project.isIncludeCompileClasspath()
private fun buildOptions(task: KaptGenerateStubsTask): Provider<CompilerPluginOptions> {
val javacOptions = project.provider { kaptExtension.getJavacOptions() }
return project.provider {
val compilerPluginOptions = CompilerPluginOptions()
buildKaptSubpluginOptions(
kaptExtension,
project,
javacOptions.get(),
aptMode = "stubs",
generatedSourcesDir = objectFactory.fileCollection().from(task.destinationDirectory.asFile),
generatedClassesDir = objectFactory.fileCollection().from(task.destinationDirectory.asFile),
incrementalDataDir = objectFactory.fileCollection().from(task.destinationDirectory.asFile),
includeCompileClasspath = isIncludeCompileClasspath(),
kaptStubsDir = objectFactory.fileCollection().from(task.stubsDir.asFile)
).forEach {
compilerPluginOptions.addPluginArgument(KAPT_SUBPLUGIN_ID, it)
}
return@provider compilerPluginOptions
}
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import java.io.File
internal typealias Kotlin2JsCompileConfig = BaseKotlin2JsCompileConfig<Kotlin2JsCompile>
internal open class BaseKotlin2JsCompileConfig<TASK : Kotlin2JsCompile>(
compilation: KotlinCompilationData<*>
) : AbstractKotlinCompileConfig<TASK>(compilation) {
init {
val libraryCacheService = project.rootProject.gradle.sharedServices.registerIfAbsent(
"${Kotlin2JsCompile.LibraryFilterCachingService::class.java.canonicalName}_${Kotlin2JsCompile.LibraryFilterCachingService::class.java.classLoader.hashCode()}",
Kotlin2JsCompile.LibraryFilterCachingService::class.java
) {}
configureTask { task ->
task.incremental = propertiesProvider.incrementalJs ?: true
task.incrementalJsKlib = propertiesProvider.incrementalJsKlib ?: true
task.outputFileProperty.value(task.project.provider {
task.kotlinOptions.outputFile?.let(::File)
?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}.js")
}).disallowChanges()
task.optionalOutputFile.fileProvider(task.outputFileProperty.flatMap { outputFile ->
task.project.provider {
outputFile.takeUnless { task.kotlinOptions.isProduceUnzippedKlib() }
}
}).disallowChanges()
task.libraryCache.set(libraryCacheService).also { task.libraryCache.disallowChanges() }
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.AbstractKotlinFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.refinesClosure
import org.jetbrains.kotlin.gradle.plugin.sources.dependsOnClosure
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon
import java.io.File
internal class KotlinCompileCommonConfig(
private val compilation: KotlinCompilationData<*>,
) : AbstractKotlinCompileConfig<KotlinCompileCommon>(compilation) {
init {
configureTask { task ->
task.expectActualLinker.value(
providers.provider {
(compilation as? KotlinCommonCompilation)?.isKlibCompilation == true || compilation is KotlinMetadataCompilationData
}
).disallowChanges()
task.refinesMetadataPaths.from(getRefinesMetadataPaths(project)).disallowChanges()
}
}
private fun getRefinesMetadataPaths(project: Project): Provider<Iterable<File>> {
return project.provider {
when (compilation) {
is KotlinCompilation<*> -> {
val defaultKotlinSourceSet: KotlinSourceSet = compilation.defaultSourceSet
val metadataTarget = compilation.owner as KotlinTarget
defaultKotlinSourceSet.dependsOnClosure
.mapNotNull { sourceSet -> metadataTarget.compilations.findByName(sourceSet.name)?.output?.classesDirs }
.flatten()
}
is AbstractKotlinFragmentMetadataCompilationData -> {
val fragment = compilation.fragment
project.files(
fragment.refinesClosure.minus(fragment).map {
val compilation = compilation.metadataCompilationRegistry.getForFragmentOrNull(it)
?: return@map project.files()
compilation.output.classesDirs
}
)
}
else -> error("unexpected compilation type")
}
}
}
}
@@ -0,0 +1,117 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.Attribute
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.internal.transforms.ClasspathEntrySnapshotTransform
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.report.BuildMetricsReporterService
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
internal typealias KotlinCompileConfig = BaseKotlinCompileConfig<KotlinCompile>
internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : AbstractKotlinCompileConfig<TASK> {
@Suppress("ConvertSecondaryConstructorToPrimary")
constructor(compilation: KotlinCompilationData<*>) : super(compilation) {
val javaTaskProvider = when (compilation) {
is KotlinJvmCompilation -> compilation.compileJavaTaskProvider
is KotlinJvmAndroidCompilation -> compilation.compileJavaTaskProvider
is KotlinWithJavaCompilation<*> -> compilation.compileJavaTaskProvider
else -> null
}
configureTaskProvider { taskProvider ->
val snapshotConfiguration = runAtConfigurationTime(taskProvider)
taskProvider.configure { task ->
javaTaskProvider?.let {
task.associatedJavaCompileTaskTargetCompatibility.value(javaTaskProvider.map { it.targetCompatibility })
task.associatedJavaCompileTaskSources.from(javaTaskProvider.map { it.source })
task.associatedJavaCompileTaskName.value(javaTaskProvider.name)
}
task.moduleName.value(providers.provider {
(compilation.kotlinOptions as? KotlinJvmOptions)?.moduleName ?: task.parentKotlinOptionsImpl.orNull?.moduleName
?: compilation.moduleName
})
task.incremental = propertiesProvider.incrementalJvm ?: true
if (propertiesProvider.useFir == true) {
task.kotlinOptions.useFir = true
}
task.usePreciseJavaTracking = propertiesProvider.usePreciseJavaTracking ?: true
task.jvmTargetValidationMode.set(propertiesProvider.jvmTargetValidationMode)
task.classpathSnapshotProperties.useClasspathSnapshot.value(propertiesProvider.useClasspathSnapshot)
task.useKotlinAbiSnapshot.value(propertiesProvider.useKotlinAbiSnapshot).disallowChanges()
if (snapshotConfiguration != null) {
val snapshotFiles = snapshotConfiguration.incoming.artifactView {
it.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
}.files
task.classpathSnapshotProperties.classpathSnapshot.from(snapshotFiles).disallowChanges()
task.classpathSnapshotProperties.classpathSnapshotDir
.value(getClasspathSnapshotDir(task))
.disallowChanges()
} else {
task.classpathSnapshotProperties.classpath.from(task.project.provider { task.libraries })
}
}
}
}
companion object {
private const val TRANSFORMS_REGISTERED = "_kgp_internal_kotlin_compile_transforms_registered"
val ARTIFACT_TYPE_ATTRIBUTE: Attribute<String> = Attribute.of("artifactType", String::class.java)
private const val DIRECTORY_ARTIFACT_TYPE = "directory"
private const val JAR_ARTIFACT_TYPE = "jar"
const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot"
}
private fun registerTransformsOnce(project: Project) {
if (project.extensions.extraProperties.has(TRANSFORMS_REGISTERED)) {
return
}
project.extensions.extraProperties[TRANSFORMS_REGISTERED] = true
val buildMetricsReporterService = BuildMetricsReporterService.registerIfAbsent(project)
project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) {
it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, JAR_ARTIFACT_TYPE)
it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
it.parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir)
buildMetricsReporterService?.apply { it.parameters.buildMetricsReporterService.set(this) }
}
project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) {
it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DIRECTORY_ARTIFACT_TYPE)
it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
it.parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir)
buildMetricsReporterService?.apply { it.parameters.buildMetricsReporterService.set(this) }
}
}
/**
* Prepares for configuration of the task. This method must be called during build configuration, not during task configuration
* (which typically happens after build configuration). The reason is that some actions must be performed early (e.g., creating
* configurations should be done early to avoid issues with composite builds (https://issuetracker.google.com/183952598)).
*/
private fun runAtConfigurationTime(taskProvider: TaskProvider<TASK>): Configuration? {
return if (propertiesProvider.useClasspathSnapshot) {
registerTransformsOnce(project)
project.configurations.detachedConfiguration(
project.dependencies.create(objectFactory.fileCollection().from(taskProvider.get().libraries))
)
} else null
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.tasks.configuration
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink
internal open class KotlinJsIrLinkConfig(
compilation: KotlinJsIrCompilation
) : BaseKotlin2JsCompileConfig<KotlinJsIrLink>(compilation) {
init {
configureTask { task ->
// Link tasks are not affected by compiler plugin, so set to empty
task.pluginClasspath.setFrom(objectFactory.fileCollection())
task.entryModule.fileProvider(compilation.output.classesDirs.elements.map { it.single().asFile }).disallowChanges()
task.compilation = compilation
task.destinationDirectory.fileProvider(task.outputFileProperty.map { it.parentFile })
}
}
}