[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.Project
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Internal
import java.io.File
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. */
open class CompilerPluginConfig {
@get:Internal
protected val optionsByPluginId = mutableMapOf<String, MutableList<SubpluginOption>>()
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.BaseVariant
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.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ExternalDependency
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.Usage
import org.gradle.api.file.FileCollection
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.process.CommandLineArgumentProvider
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
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.internal.Kapt3GradleSubplugin.Companion.isInfoAsWarnings
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKaptKeepKdocCommentsInStubs
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKaptVerbose
import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
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.configuration.*
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream
@@ -53,17 +49,6 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
override fun apply(target: Project) {
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())
}
@@ -82,7 +67,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
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_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.getKaptClasspathSnapshotDir() = temporaryKaptDirectory("classpath-snapshot")
private fun Kapt3SubpluginContext.getKaptIncrementalAnnotationProcessingCache() = temporaryKaptDirectory("incApCache")
private fun Kapt3SubpluginContext.temporaryKaptDirectory(
@@ -326,7 +313,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
Callable {
// 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
val kaptJavaOutput = kaptTaskProvider.get().destinationDir
val kaptJavaOutput = kaptTaskProvider.get().destinationDir.get().asFile
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
private fun Kapt3SubpluginContext.buildOptions(
aptMode: String,
private fun Kapt3SubpluginContext.buildOptionsForAptMode(
javacOptions: Provider<Map<String, String>>
): Provider<List<SubpluginOption>> {
disableAnnotationProcessingInJavaTask()
return project.provider {
val pluginOptions = mutableListOf<SubpluginOption>()
val generatedFilesDir = getKaptGeneratedSourcesDir(project, sourceSetName)
KaptWithAndroid.androidVariantData(this)?.addJavaSourceFoldersToModel(generatedFilesDir)
pluginOptions += SubpluginOption("aptMode", aptMode)
pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir))
pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName)))
pluginOptions += FilesSubpluginOption("incrementalData", listOf(getKaptIncrementalDataDir()))
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
buildKaptSubpluginOptions(
kaptExtension,
project,
javacOptions.get(),
"apt",
generatedSourcesDir = listOf(sourcesOutputDir),
generatedClassesDir = listOf(getKaptGeneratedClassesDir(project, sourceSetName)),
incrementalDataDir = listOf(getKaptIncrementalDataDir()),
includeCompileClasspath = includeCompileClasspath,
kaptStubsDir = listOf(getKaptStubsDir())
) + getAPOptions().get() // apOptions are needed only for "apt" mode
}
}
@@ -425,96 +391,14 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
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> {
val taskClass = if (useWorkerApi) KaptWithoutKotlincTask::class.java else KaptWithKotlincTask::class.java
val taskName = getKaptTaskName("kapt")
var classStructureIfIncremental: Configuration? = null
if (project.isIncrementalKapt()) {
maybeRegisterTransform(project)
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 taskConfigAction = if (taskClass == KaptWithoutKotlincTask::class.java ) {
KaptWithoutKotlincConfigAction(kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile, kaptExtension)
} else {
KaptWithKotlincConfigAction(kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile, kaptExtension)
}
val kaptClasspathConfiguration = project.configurations.create("kaptClasspath_$taskName")
@@ -522,182 +406,97 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
it.isVisible = false
it.isCanBeConsumed = false
}
val kaptTaskProvider = project.registerTask(taskName, taskClass, emptyList()) { kaptTask ->
kaptTask.useBuildCache = kaptExtension.useBuildCache
val kotlinCompileTask = kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile
if (kaptTask is KaptWithoutKotlincTask) {
KaptWithoutKotlincTask.Configurator(kotlinCompileTask).configure(kaptTask)
} else {
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 }
)
)
taskConfigAction.configureTaskProvider { taskProvider ->
if (javaCompile != null) {
val androidVariantData = KaptWithAndroid.androidVariantData(this)
if (androidVariantData != null) {
KaptWithAndroid.registerGeneratedJavaSourceForAndroid(this, project, androidVariantData, taskProvider)
androidVariantData.addJavaSourceFoldersToModel(sourcesOutputDir)
} else {
registerGeneratedJavaSource(taskProvider, javaCompile)
}
disableAnnotationProcessingInJavaTask()
}
kaptTask.kaptClasspath.from(kaptClasspathConfiguration).disallowChanges()
kaptTask.kaptExternalClasspath.from(kaptClasspathConfiguration.fileCollection { it is ExternalDependency })
kaptTask.kaptClasspathConfigurationNames.value(kaptClasspathConfigurations.map { it.name }).disallowChanges()
kotlinCompilation.output.classesDirs.from(taskProvider.flatMap { it.classesDir })
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 {
kaptTask.annotationProcessorOptionProviders.add(it)
task.annotationProcessorOptionProviders.add(it)
}
}
kotlinCompilation.output.classesDirs.from(kaptTaskProvider.map { it.classesDir })
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)
val pluginOptions: Provider<CompilerPluginOptions> = if (taskClass == KaptWithKotlincTask::class.java) {
buildOptionsForAptMode(taskConfigAction.getJavaOptions(task.defaultJavaSourceCompatibility))
} 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 {
kaptExtension.getJavacOptions().toMutableMap().also { result ->
if (javaCompile != null && "-source" !in result && "--source" !in result && "--release" !in result) {
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] = javaCompile.get().sourceCompatibility
}
return if (taskClass == KaptWithoutKotlincTask::class.java) {
taskConfigAction as KaptWithoutKotlincConfigAction
project.registerTask(taskName, KaptWithoutKotlincTask::class.java, emptyList()).also {
taskConfigAction.execute(it)
}
}
if (KaptWithKotlincTask::class.java.isAssignableFrom(taskClass)) {
val subpluginOptions = buildOptions("apt", dslJavacOptions)
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()
} else {
taskConfigAction as KaptWithKotlincConfigAction
project.registerTask(taskName, KaptWithKotlincTask::class.java, emptyList()).also {
taskConfigAction.execute(it)
}
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> {
val properties = PropertiesProvider(project)
val kaptTaskName = getKaptTaskName("kaptGenerateStubs")
val kaptTaskProvider = project.registerTask<KaptGenerateStubsTask>(kaptTaskName)
val projectDir = project.projectDir
val configurator = KaptGenerateStubsTask.Configurator(kotlinCompile, kotlinCompilation, properties)
configurator.runAtConfigurationTime(kaptTaskProvider, project)
kaptTaskProvider.configure { kaptTask ->
configurator.configure(kaptTask)
kaptTask.stubsDir.set(getKaptStubsDir())
kaptTask.destinationDirectory.set(getKaptIncrementalDataDir())
kaptTask.generatedSourcesDirs = listOf(sourcesOutputDir, kotlinSourcesOutputDir)
kaptTask.kaptClasspath.from(kaptClasspathConfigurations)
properties.mapKotlinTaskProperties(kaptTask)
if (!includeCompileClasspath) {
kaptTask.onlyIf {
!(it as KaptGenerateStubsTask).kaptClasspath.isEmpty
}
}
val taskConfig = KaptGenerateStubsConfig(kotlinCompilation, kotlinCompile)
taskConfig.configureTask {
it.stubsDir.set(getKaptStubsDir())
it.destinationDirectory.set(getKaptIncrementalDataDir())
it.exclude(
"${sourcesOutputDir.relativeTo(projectDir).path}/**",
"${kotlinSourcesOutputDir.relativeTo(projectDir).path}/**"
)
it.kaptClasspath.from(kaptClasspathConfigurations)
it.classpathSnapshotProperties.classpathSnapshotDir.fileValue(getKaptClasspathSnapshotDir())
}
taskConfig.execute(kaptTaskProvider)
project.whenEvaluated {
addCompilationSourcesToExternalCompileTask(kotlinCompilation, kaptTaskProvider)
}
val subpluginOptions = buildOptions("stubs", project.provider { kaptExtension.getJavacOptions() })
registerSubpluginOptions(kaptTaskProvider, subpluginOptions)
return kaptTaskProvider
}
@@ -741,7 +540,72 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
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
// 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>) {
javaTaskProvider.configure { javaTask ->
val generatedJavaSources = javaTask.project.fileTree(kaptTask.map { it.destinationDir })
val generatedJavaSources = javaTask.project.fileTree(kaptTask.flatMap { it.destinationDir })
generatedJavaSources.include("**/*.java")
javaTask.source(generatedJavaSources)
}
@@ -18,18 +18,18 @@ package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.file.*
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.Provider
import org.gradle.api.tasks.*
import org.gradle.work.Incremental
import org.gradle.work.NormalizeLineEndings
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
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.destinationAsFile
import java.io.File
@@ -45,38 +45,9 @@ abstract class KaptGenerateStubsTask @Inject constructor(
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
abstract val stubsDir: DirectoryProperty
@get:Internal
lateinit var generatedSourcesDirs: List<File>
@get:Internal("Not an input, just passed as kapt args. ")
abstract val kaptClasspath: ConfigurableFileCollection
@@ -84,11 +55,6 @@ abstract class KaptGenerateStubsTask @Inject constructor(
@Input
fun getIfKaptClasspathIsPresent() = !kaptClasspath.isEmpty
@get:NormalizeLineEndings
@get:Classpath
@Suppress("unused")
internal abstract val kotlinTaskPluginClasspath: ConfigurableFileCollection
@get:Input
abstract val verbose: Property<Boolean>
@@ -105,8 +71,7 @@ abstract class KaptGenerateStubsTask @Inject constructor(
private fun File.isSourceRootAllowed(): Boolean =
!destinationDirectory.get().asFile.isParentOf(this) &&
!stubsDir.asFile.get().isParentOf(this) &&
generatedSourcesDirs.none { it.isParentOf(this) }
!stubsDir.asFile.get().isParentOf(this)
override fun skipCondition(): Boolean = sources.isEmpty && javaSources.isEmpty
@@ -123,10 +88,10 @@ abstract class KaptGenerateStubsTask @Inject constructor(
}
@get:Internal
override val scriptSources: FileCollection = objectFactory.fileCollection()
abstract override val scriptSources: FileCollection
@get:Internal
override val androidLayoutResources: FileCollection = objectFactory.fileCollection()
abstract override val androidLayoutResources: FileCollection
override val incrementalProps: List<FileCollection>
get() = listOf(
@@ -159,11 +124,11 @@ abstract class KaptGenerateStubsTask @Inject constructor(
)
)
val pluginOptionsWithKapt = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath)
args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray()
val pluginOptionsWithKapt = pluginOptions.toSingleCompilerPluginOptions().withWrappedKaptOptions(withApClasspath = kaptClasspath)
args.pluginOptions = (pluginOptionsWithKapt.arguments).toTypedArray()
args.verbose = verbose.get()
args.classpathAsList = this.libraries.filter { it.exists() }.toList()
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.KaptIncrementalChanges
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.UnknownSnapshot
import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.utils.addToStdlib.cast
import java.io.File
import java.util.concurrent.Callable
import java.util.jar.JarFile
import javax.inject.Inject
@@ -36,30 +34,6 @@ abstract class KaptTask @Inject constructor(
TaskWithLocalState,
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 {
cacheOnlyIfEnabledForKotlin()
@@ -95,6 +69,9 @@ abstract class KaptTask @Inject constructor(
@get:InputFiles
abstract val classpathStructure: ConfigurableFileCollection
@get:Internal
abstract val kaptPluginOptions: ListProperty<CompilerPluginOptions>
/**
* Output directory that contains caches necessary to support incremental annotation processing.
*/
@@ -102,13 +79,14 @@ abstract class KaptTask @Inject constructor(
abstract val incAptCache: DirectoryProperty
@get:OutputDirectory
internal lateinit var classesDir: File
internal abstract val classesDir: DirectoryProperty
@get:OutputDirectory
lateinit var destinationDir: File
abstract val destinationDir: DirectoryProperty
/** Used in the model builder only. */
@get:OutputDirectory
lateinit var kotlinSourcesDestinationDir: File
abstract val kotlinSourcesDestinationDir: DirectoryProperty
@get:Nested
internal val annotationProcessorOptionProviders: MutableList<Any> = mutableListOf()
@@ -176,37 +154,8 @@ abstract class KaptTask @Inject constructor(
@get:Input
abstract val verbose: Property<Boolean>
private fun isRootAllowed(file: File): Boolean =
file.exists() &&
!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)
}
}
@get:Internal
abstract val defaultJavaSourceCompatibility: Property<String>
protected fun checkAnnotationProcessorClasspath() {
if (!includeCompileClasspath.get()) return
@@ -35,21 +35,6 @@ abstract class KaptWithKotlincTask @Inject constructor(
CompilerArgumentAwareWithInput<K2JVMCompilerArguments>,
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:Classpath
abstract val pluginClasspath: ConfigurableFileCollection
@@ -59,6 +44,10 @@ abstract class KaptWithKotlincTask @Inject constructor(
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()
abstract override val kotlinDaemonJvmArguments: ListProperty<String>
@@ -74,8 +63,7 @@ abstract class KaptWithKotlincTask @Inject constructor(
))
args.pluginClasspaths = pluginClasspath.toPathsArray()
val pluginOptionsWithKapt: CompilerPluginOptions = pluginOptions.withWrappedKaptOptions(
val pluginOptionsWithKapt: CompilerPluginOptions = kaptPluginOptions.toSingleCompilerPluginOptions().withWrappedKaptOptions(
withApClasspath = kaptClasspath,
changedFiles = changedFiles,
classpathChanges = classpathChanges,
@@ -95,8 +83,11 @@ abstract class KaptWithKotlincTask @Inject constructor(
private var classpathChanges: List<String> = emptyList()
private var processIncrementally = false
private val javaPackagePrefix = objectFactory.property(String::class.java)
private val reportingSettings = objectFactory.property(ReportingSettings::class.java)
@get:Internal
internal abstract val javaPackagePrefix: Property<String>
@get:Internal
internal abstract val reportingSettings: Property<ReportingSettings>
@TaskAction
fun compile(inputChanges: InputChanges) {
@@ -9,6 +9,7 @@ import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.*
@@ -20,13 +21,12 @@ import org.gradle.workers.IsolationMode
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
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.rootOrSelf
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
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.toSingleCompilerPluginOptions
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
import org.jetbrains.kotlin.utils.PathUtil
import org.slf4j.LoggerFactory
@@ -42,16 +42,6 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
private val workerExecutor: WorkerExecutor
) : 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:Classpath
abstract val kaptJars: ConfigurableFileCollection
@@ -66,16 +56,13 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
var mapDiagnosticLocations: Boolean = false
@get:Input
lateinit var annotationProcessorFqNames: List<String>
@get:Internal
internal val processorOptions = CompilerPluginOptions()
abstract val annotationProcessorFqNames: ListProperty<String>
@get:Input
lateinit var javacOptions: Map<String, String>
abstract val javacOptions: MapProperty<String, String>
@get:Input
internal abstract val addJdkClassesToClasspath: Property<Boolean>
abstract val addJdkClassesToClasspath: Property<Boolean>
@get:Internal
internal val projectDir = project.projectDir
@@ -84,11 +71,9 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
val kaptProcessJvmArgs: ListProperty<String> = objectFactory.listProperty<String>().convention(emptyList())
private fun getAnnotationProcessorOptions(): Map<String, String> {
val options = processorOptions.subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID] ?: return emptyMap()
val result = mutableMapOf<String, String>()
for (option in options) {
result[option.key] = option.value
kaptPluginOptions.toSingleCompilerPluginOptions().subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID]?.forEach {
result[it.key] = it.value
}
annotationProcessorOptionProviders.forEach { providers ->
(providers as List<*>).forEach { provider ->
@@ -104,6 +89,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
@TaskAction
fun compile(inputChanges: InputChanges) {
logger.info("Running kapt annotation processing using the Gradle Worker API")
checkProcessorCachingSetup()
checkAnnotationProcessorClasspath()
val incrementalChanges = getIncrementalChanges(inputChanges)
@@ -137,16 +123,16 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
incAptCache.orNull?.asFile,
classpathChanges.toList(),
destinationDir,
classesDir,
destinationDir.get().asFile,
classesDir.get().asFile,
stubsDir.asFile.get(),
kaptClasspath.files.toList(),
kaptExternalClasspath.files.toList(),
annotationProcessorFqNames,
annotationProcessorFqNames.get(),
getAnnotationProcessorOptions(),
javacOptions,
javacOptions.get(),
kaptFlagsForWorker,
@@ -154,7 +140,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
)
// 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.")
return
}
@@ -259,6 +245,15 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
).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
)
) KaptSourceSet.KaptSourceSetType.TEST else KaptSourceSet.KaptSourceSetType.PRODUCTION,
destinationDir,
kotlinSourcesDestinationDir,
classesDir
destinationDir.get().asFile,
kotlinSourcesDestinationDir.get().asFile,
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.isMainCompilationData
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.jvm.KotlinJvmTarget
import org.jetbrains.kotlin.gradle.tasks.*
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.tooling.includeKotlinToolingMetadataInApk
import org.jetbrains.kotlin.gradle.utils.*
@@ -67,7 +67,7 @@ abstract class KotlinCompilationProcessor<out T : AbstractKotlinCompileTool<*>>(
protected val project: Project
get() = kotlinCompilation.project
protected val defaultKotlinDestinationDir: File
protected val defaultKotlinDestinationDir: Provider<Directory>
get() {
val kotlinExt = project.topLevelExtension
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
else
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> =
registerKotlinCompileTask(register = ::doRegisterTask).also { task ->
doRegisterTask(project, kotlinCompilation.compileKotlinTaskName).also { task ->
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() {
addKotlinDirectoriesToJavaSourceSet()
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(
@@ -174,12 +169,11 @@ internal class Kotlin2JvmSourceSetProcessor(
) : KotlinSourceSetProcessor<KotlinCompile>(
tasksProvider, "Compiles the $kotlinCompilation.", kotlinCompilation
) {
override fun doRegisterTask(
project: Project,
taskName: String,
configureAction: (KotlinCompile) -> (Unit)
): TaskProvider<out KotlinCompile> =
tasksProvider.registerKotlinJVMTask(project, taskName, kotlinCompilation, configureAction)
override fun doRegisterTask(project: Project, taskName: String): TaskProvider<out KotlinCompile> {
val configAction = KotlinCompileConfig(kotlinCompilation)
applyStandardTaskConfiguration(configAction)
return tasksProvider.registerKotlinJVMTask(project, taskName, kotlinCompilation.kotlinOptions, configAction)
}
override fun doTargetSpecificProcessing() {
ifKaptEnabled(project) {
@@ -232,12 +226,11 @@ internal class Kotlin2JsSourceSetProcessor(
taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.",
kotlinCompilation = kotlinCompilation
) {
override fun doRegisterTask(
project: Project,
taskName: String,
configureAction: (Kotlin2JsCompile) -> (Unit)
): TaskProvider<out Kotlin2JsCompile> =
tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation, configureAction)
override fun doRegisterTask(project: Project, taskName: String): TaskProvider<out Kotlin2JsCompile> {
val configAction = Kotlin2JsCompileConfig(kotlinCompilation)
applyStandardTaskConfiguration(configAction)
return tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation.kotlinOptions, configAction)
}
override fun doTargetSpecificProcessing() {
project.tasks.named(kotlinCompilation.compileAllTaskName).configure {
@@ -298,27 +291,10 @@ internal class KotlinJsIrSourceSetProcessor(
tasksProvider, taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.",
kotlinCompilation = kotlinCompilation
) {
override fun doRegisterTask(
project: Project,
taskName: String,
configureAction: (Kotlin2JsCompile) -> (Unit)
): 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 doRegisterTask(project: Project, taskName: String): TaskProvider<out Kotlin2JsCompile> {
val configAction = Kotlin2JsCompileConfig(kotlinCompilation)
applyStandardTaskConfiguration(configAction)
return tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation.kotlinOptions, configAction)
}
override fun doTargetSpecificProcessing() {
@@ -331,14 +307,14 @@ internal class KotlinJsIrSourceSetProcessor(
compilation.binaries
.withType(JsIrBinary::class.java)
.all { binary ->
registerKotlinCompileTask(
binary.linkTaskName
) { project, name, action ->
registerJsLink(project, name, binary.mode) { compileTask ->
action(compileTask)
compileTask.dependsOn(kotlinTask)
}
val configAction = KotlinJsIrLinkConfig(compilation)
applyStandardTaskConfiguration(configAction)
configAction.configureTask { task ->
task.modeProperty.set(binary.mode)
task.dependsOn(kotlinTask)
}
tasksProvider.registerKotlinJsIrTask(project, binary.linkTaskName, configAction)
}
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,
configureAction: (KotlinCompileCommon) -> (Unit)
): TaskProvider<out KotlinCompileCommon> =
tasksProvider.registerKotlinCommonTask(project, taskName, kotlinCompilation, configureAction)
override fun doRegisterTask(project: Project, taskName: String): TaskProvider<out KotlinCompileCommon> {
val configAction = KotlinCompileCommonConfig(kotlinCompilation)
applyStandardTaskConfiguration(configAction)
return tasksProvider.registerKotlinCommonTask(project, taskName, kotlinCompilation.kotlinOptions, configAction)
}
}
internal abstract class AbstractKotlinPlugin(
@@ -683,7 +657,7 @@ internal open class KotlinAndroidPlugin(
companion object {
const val MINIMAL_SUPPORTED_AGP_VERSION = "3.6.4"
fun androidTargetHandler(): AbstractAndroidProjectHandler {
val tasksProvider = AndroidTasksProvider()
val tasksProvider = KotlinTasksProvider()
if (androidPluginVersion != null) {
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 kotlinTaskName = compilation.compileKotlinTaskName
tasksProvider.registerKotlinJVMTask(project, kotlinTaskName, compilation) {
it.parentKotlinOptionsImpl.set(rootKotlinOptions)
val configAction = KotlinCompileConfig(compilation)
configAction.configureTask { task ->
task.parentKotlinOptionsImpl.value(rootKotlinOptions).disallowChanges()
task.useModuleDetection.value(true).disallowChanges()
// 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"))
it.description = "Compiles the $variantDataName kotlin."
task.destinationDirectory.set(project.layout.buildDirectory.dir("tmp/kotlin-classes/$variantDataName"))
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:
compilation.source(defaultSourceSet)
@@ -1026,33 +1000,6 @@ private fun SourceSet.clearJavaSrcDirs() {
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
internal val androidPluginVersion by lazy {
try {
@@ -100,19 +100,13 @@ abstract class KotlinBasePluginWrapper : Plugin<Project> {
KotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
val buildMetricReporter = BuildMetricsReporterService.registerIfAbsent(project)
buildMetricReporter?.also { BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it) }
BuildMetricsReporterService.registerIfAbsent(project)?.also {
BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it)
}
HttpReportService.registerIfAbsent(project, kotlinPluginVersion)
?.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 {
coreLibrariesVersion = kotlinPluginVersion
@@ -36,37 +36,6 @@ import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import java.io.File
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) {
private val localProperties: Properties by lazy {
Properties().apply {
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Project
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
@@ -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)
runOnceAfterEvaluated(runOnce, task)
}
internal fun Project.runOnceAfterEvaluated(runOnce: RunOnceAfterEvaluated, task: TaskProvider<*>) {
whenEvaluated { runOnce.onEvaluated() }
task.configure {
runOnce.onConfigure()
}
runOnce.onConfigure()
}
@@ -49,14 +49,20 @@ class SubpluginEnvironment(
val subpluginOptionsProvider = subplugin.applyToCompilation(kotlinCompilation)
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 pluginOptions = it.getPluginOptions()
val subpluginOptions = subpluginOptionsProvider.get()
for (option in subpluginOptions) {
pluginOptions.addPluginArgument(subpluginId, option)
when (it) {
is AbstractKotlinCompile<*> -> it.pluginOptions.add(compilerOptions)
is KotlinNativeCompile -> it.compilerPluginOptions.addPluginArgument(compilerOptions.get())
else -> error("Unexpected task ${it.name}, class: ${it.javaClass}")
}
it.registerSubpluginOptionsAsInputs(subpluginId, subpluginOptions)
}
kotlinCompilation.compileKotlinTaskProvider.configure(configureKotlinTask)
@@ -75,12 +81,6 @@ class SubpluginEnvironment(
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) {
val artifactVersion = artifact.version ?: kotlinPluginVersion
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.AbstractKotlinCompileTool
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.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
@@ -76,7 +77,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
get() {
val pluginOptionsTask = compilerPluginOptionsTask.value ?: return null
return when (pluginOptionsTask) {
is AbstractKotlinCompile<*> -> pluginOptionsTask.pluginOptions
is AbstractKotlinCompile<*> -> pluginOptionsTask.pluginOptions.toSingleCompilerPluginOptions()
is AbstractKotlinNativeCompile<*, *, *> -> pluginOptionsTask.compilerPluginOptions
else -> error("Unexpected task: $pluginOptionsTask")
}.arguments
@@ -5,11 +5,11 @@
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.FileCollection
import org.gradle.api.file.ProjectLayout
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.work.NormalizeLineEndings
import org.gradle.workers.WorkerExecutor
@@ -46,18 +46,6 @@ abstract class KotlinJsIrLink @Inject constructor(
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 {
// Not check sources, only klib module
disallowSourceChanges()
@@ -88,11 +76,16 @@ abstract class KotlinJsIrLink @Inject constructor(
@get:Input
val outputGranularity: KotlinJsIrOutputGranularity = propertiesProvider.jsIrOutputGranularity
// Link tasks are not affected by compiler plugin
override val pluginClasspath: ConfigurableFileCollection = project.objects.fileCollection()
@get:Internal
@get:Deprecated("Please use modeProperty instead.")
var mode: KotlinJsBinaryMode
get() = modeProperty.get()
set(value) {
modeProperty.set(value)
}
@Input
lateinit var mode: KotlinJsBinaryMode
@get:Input
internal abstract val modeProperty: Property<KotlinJsBinaryMode>
private val buildDir = project.buildDir
@@ -16,7 +16,10 @@
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() {
@@ -24,8 +27,10 @@ class CompilerPluginOptions() : CompilerPluginConfig() {
copyOptionsFrom(options)
}
val subpluginOptionsByPluginId = optionsByPluginId
@get:Internal
internal val subpluginOptionsByPluginId = optionsByPluginId
@get:Internal
val arguments: List<String>
get() = optionsByPluginId.flatMap { (pluginId, subplubinOptions) ->
subplubinOptions.map { option ->
@@ -33,6 +38,10 @@ class CompilerPluginOptions() : CompilerPluginConfig() {
}
}
fun addPluginArgument(options: CompilerPluginOptions) {
copyOptionsFrom(options)
}
operator fun plus(options: CompilerPluginConfig?): CompilerPluginOptions {
if (options == null) return this
val newOptions = CompilerPluginOptions()
@@ -42,9 +51,52 @@ class CompilerPluginOptions() : CompilerPluginConfig() {
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) {
options.allOptions().forEach { entry ->
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
import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.model.ObjectFactory
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.internal.tasks.allOutputFiles
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 java.io.File
import javax.inject.Inject
@@ -51,41 +43,6 @@ abstract class KotlinCompileCommon @Inject constructor(
) : AbstractKotlinCompile<K2MetadataCompilerArguments>(objectFactory),
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> =
objectFactory.propertyWithConvention(
gradleCompileTaskProvider.map {
@@ -10,7 +10,6 @@ import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.attributes.Attribute
import org.gradle.api.file.*
import org.gradle.api.invocation.Gradle
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.incremental.*
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.allOutputFiles
import org.jetbrains.kotlin.gradle.internal.transforms.ClasspathEntrySnapshotTransform
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.*
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.report.BuildMetricsReporterService
import org.jetbrains.kotlin.gradle.report.BuildReportMode
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.incremental.*
import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled
@@ -261,42 +256,6 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
) : AbstractKotlinCompileTool<T>(objectFactory),
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 {
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
@get:LocalState
internal val taskBuildLocalStateDirectory: DirectoryProperty = objectFactory.directoryProperty()
internal abstract val taskBuildLocalStateDirectory: DirectoryProperty
@get:Internal
internal val buildHistoryFile
@@ -342,7 +301,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
internal fun reportingSettings() = buildMetricsReporterService.orNull?.parameters?.reportingSettings ?: ReportingSettings()
@get:Input
internal val useModuleDetection: Property<Boolean> = objectFactory.property(Boolean::class.java).value(false)
internal abstract val useModuleDetection: Property<Boolean>
@get:Internal
protected val multiModuleICSettings: MultiModuleICSettings
@@ -350,10 +309,10 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
@get:NormalizeLineEndings
@get:Classpath
open val pluginClasspath: ConfigurableFileCollection = objectFactory.fileCollection()
abstract val pluginClasspath: ConfigurableFileCollection
@get:Internal
internal val pluginOptions = CompilerPluginOptions()
@get:Nested
internal abstract val pluginOptions: ListProperty<CompilerPluginOptions>
/**
@@ -368,7 +327,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
internal val javaOutputDir: DirectoryProperty = objectFactory.directoryProperty()
@get:Internal
internal val sourceSetName: Property<String> = objectFactory.property(String::class.java)
internal abstract val sourceSetName: Property<String>
@get:InputFiles
@get:IgnoreEmptyDirectories
@@ -378,7 +337,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
internal val commonSourceSet: ConfigurableFileCollection = objectFactory.fileCollection()
@get:Input
internal val moduleName: Property<String> = objectFactory.property(String::class.java)
internal abstract val moduleName: Property<String>
@get:Internal
val abiSnapshotFile
@@ -394,12 +353,10 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
internal val friendSourceSets = objectFactory.listProperty(String::class.java)
@get:Internal // takes part in the compiler arguments
val friendPaths: ConfigurableFileCollection = objectFactory.fileCollection()
abstract val friendPaths: ConfigurableFileCollection
private val kotlinLogger by lazy { GradleKotlinLogger(logger) }
abstract override val kotlinDaemonJvmArguments: ListProperty<String>
@get:Internal
protected val gradleCompileTaskProvider: Provider<GradleCompileTaskProvider> = objectFactory
.property(
@@ -473,8 +430,6 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
protected open fun skipCondition(): Boolean = sources.isEmpty
private val projectDir = project.rootProject.projectDir
@get:Internal
protected open val incrementalProps: List<FileCollection>
get() = listOfNotNull(
@@ -489,7 +444,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
) {
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()) {
// 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
internal val multiPlatformEnabled: Property<Boolean> = objectFactory.property(Boolean::class.java)
internal abstract val multiPlatformEnabled: Property<Boolean>
@get:Internal
internal val abstractKotlinCompileArgumentsContributor by lazy {
@@ -568,8 +523,7 @@ open class KotlinCompileArgumentsProvider<T : AbstractKotlinCompile<out CommonCo
val isMultiplatform: Boolean = taskProvider.multiPlatformEnabled.get()
private val pluginData = taskProvider.kotlinPluginData?.orNull
val pluginClasspath: FileCollection = listOfNotNull(taskProvider.pluginClasspath, pluginData?.classpath).reduce(FileCollection::plus)
val pluginOptions: CompilerPluginOptions =
listOfNotNull(taskProvider.pluginOptions, pluginData?.options).reduce(CompilerPluginOptions::plus)
val pluginOptions: CompilerPluginOptions = taskProvider.pluginOptions.toSingleCompilerPluginOptions() + pluginData?.options
}
class KotlinJvmCompilerArgumentsProvider
@@ -596,101 +550,8 @@ abstract class KotlinCompile @Inject constructor(
KotlinJvmCompile,
UsesKotlinJavaToolchain {
internal open class Configurator<T : KotlinCompile>(
kotlinCompilation: KotlinCompilationData<*>,
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)
@get:Internal("Takes part in compiler args.")
internal abstract val parentKotlinOptionsImpl: Property<KotlinJvmOptions>
/** 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
}
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 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.tasks.TaskCollection
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
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.dsl.KotlinCommonOptions
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]
@@ -92,114 +89,42 @@ internal inline fun <reified T : Task> Project.locateOrRegisterTask(
internal open class KotlinTasksProvider {
open fun registerKotlinJVMTask(
project: Project,
name: String,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinCompile) -> (Unit)
project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: KotlinCompileConfig
): TaskProvider<out KotlinCompile> {
val properties = PropertiesProvider(project)
val kotlinCompile = project.registerTask(
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)
return project.registerTask(taskName, KotlinCompile::class.java, constructorArgs = listOf(kotlinOptions)).also {
configuration.execute(it)
}
configure(kotlinCompile, project, properties, compilation)
return kotlinCompile
}
fun registerKotlinJSTask(
project: Project,
name: String,
compilation: KotlinCompilationData<*>,
configureAction: (Kotlin2JsCompile) -> Unit
project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: Kotlin2JsCompileConfig
): TaskProvider<out Kotlin2JsCompile> {
val properties = PropertiesProvider(project)
val result = project.registerTask(
name,
return project.registerTask(
taskName,
Kotlin2JsCompile::class.java,
constructorArgs = listOf(compilation.kotlinOptions)
) {
configureAction(it)
Kotlin2JsCompile.Configurator<Kotlin2JsCompile>(compilation).configure(it)
constructorArgs = listOf(kotlinOptions)
).also {
configuration.execute(it)
}
configure(result, project, properties, compilation)
return result
}
fun registerKotlinJsIrTask(
project: Project,
name: String,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinJsIrLink) -> Unit
project: Project, taskName: String, configuration: KotlinJsIrLinkConfig
): TaskProvider<out KotlinJsIrLink> {
val properties = PropertiesProvider(project)
val result = project.registerTask(
name,
KotlinJsIrLink::class.java
) {
it.compilation = compilation
configureAction(it)
KotlinJsIrLink.Configurator(compilation).configure(it)
return project.registerTask(taskName, KotlinJsIrLink::class.java).also {
configuration.execute(it)
}
configure(result, project, properties, compilation)
return result
}
fun registerKotlinCommonTask(
project: Project,
name: String,
compilation: KotlinCompilationData<*>,
configureAction: (KotlinCompileCommon) -> (Unit)
project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: KotlinCompileCommonConfig
): TaskProvider<out KotlinCompileCommon> {
val properties = PropertiesProvider(project)
val result = project.registerTask(
name,
return project.registerTask(
taskName,
KotlinCompileCommon::class.java,
constructorArgs = listOf(compilation.kotlinOptions)
) {
configureAction(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)
constructorArgs = listOf(kotlinOptions)
).also {
configuration.execute(it)
}
}
}
@@ -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 })
}
}
}