Store sensitive plugin options in Task inputs

This commit is contained in:
Anton Lakotka
2021-04-30 00:14:01 +02:00
committed by Space
parent 9e084a7256
commit bc7ff04f1f
4 changed files with 105 additions and 31 deletions
@@ -118,7 +118,7 @@ class KpmCompilerPluginTest {
group = "test",
artifact = artifact
),
options = options.map { PluginData.PluginOption(it.key, it.value) }
options = options.map { StringOption(it.key, it.value) }
)
override fun forMetadataCompilation(fragment: KotlinModuleFragment) = metadataArtifact?.let(::pluginData)
@@ -7,12 +7,14 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.plugin.FilesSubpluginOption
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.KotlinCompilerPluginData
import org.jetbrains.kotlin.gradle.utils.newProperty
import org.jetbrains.kotlin.project.model.*
import java.io.File
internal fun Project.compilerPluginProviderForMetadata(
fragment: KotlinGradleFragment,
@@ -35,29 +37,69 @@ private fun Project.compilerPluginDataProvider(
compilationData: KotlinCompilationData<*>,
pluginDataList: () -> List<PluginData>
): Provider<KotlinCompilerPluginData> {
val configurationName = compilationData.pluginClasspathConfigurationName()
val pluginClasspathConfiguration =
configurations.maybeCreate(configurationName).apply {
isCanBeConsumed = false
isCanBeResolved = true
isVisible = false
}
val pluginOptions = CompilerPluginOptions()
return newProperty {
for (pluginData in pluginDataList()) {
dependencies.add(pluginClasspathConfiguration.name, pluginData.artifact.toGradleCoordinates(project))
pluginData.options.forEach { (key, value) ->
pluginOptions.addPluginArgument(pluginData.pluginId, SubpluginOption(key, value))
}
}
KotlinCompilerPluginData(
classpath = pluginClasspathConfiguration,
options = pluginOptions
)
val configurationName = compilationData.pluginClasspathConfigurationName()
val builder = CompilerPluginOptionsBuilder(project, configurationName)
builder += pluginDataList()
builder.build()
}.apply { finalizeValueOnRead() }
}
private fun PluginData.ArtifactCoordinates.toGradleCoordinates(project: Project): String =
"$group:$artifact:${version ?: project.getKotlinPluginVersion()}"
internal class CompilerPluginOptionsBuilder(
private val project: Project,
private val configurationName: String
) {
private val pluginOptions = CompilerPluginOptions()
private val artifacts = mutableListOf<String>()
private val gradleInputs = mutableMapOf<String, String>()
private val gradleInputFiles = mutableSetOf<File>()
operator fun plusAssign(pluginData: PluginData) {
artifacts += pluginData.artifact.toGradleCoordinates()
for (option in pluginData.options) {
pluginOptions.addPluginArgument(pluginData.pluginId, option.toSubpluginOption())
if (option.sensitive) {
addToInputs(pluginData.pluginId, option)
}
}
}
operator fun plusAssign(pluginDataCollection: Collection<PluginData>) {
for (pluginData in pluginDataCollection) {
this += pluginData
}
}
private fun addToInputs(pluginId: String, option: PluginOption) = when(option) {
is FilesOption -> gradleInputFiles += option.files
is StringOption -> gradleInputs["${pluginId}.${option.key}"] = option.value
}
fun build(): KotlinCompilerPluginData {
val pluginClasspathConfiguration =
project.configurations.maybeCreate(configurationName).apply {
isCanBeConsumed = false
isCanBeResolved = true
isVisible = false
}
artifacts.forEach { project.dependencies.add(configurationName, it) }
return KotlinCompilerPluginData(
classpath = pluginClasspathConfiguration,
options = pluginOptions,
inputs = gradleInputs,
inputFiles = gradleInputFiles
)
}
private fun PluginOption.toSubpluginOption() = when (this) {
is FilesOption -> FilesSubpluginOption(key, files)
is StringOption -> SubpluginOption(key, value)
}
private fun PluginData.ArtifactCoordinates.toGradleCoordinates(): String =
"$group:$artifact:${version ?: project.getKotlinPluginVersion()}"
}
@@ -783,5 +783,19 @@ data class KotlinCompilerPluginData(
val classpath: FileCollection,
@get:Internal
val options: CompilerPluginOptions
val options: CompilerPluginOptions,
/**
* Used only for Up-to-date checks
*/
@get:Input
val inputs: Map<String, String>,
/**
* Used only for Up-to-date checks
*/
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
val inputFiles: Set<File>
)
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.project.model
import java.io.File
/**
* Adapts Kotlin Compiler Plugin for Multiplatform Kotlin Project Model
* Build System uses this interface to identify applicable plugin artifacts and its options
@@ -45,13 +47,30 @@ data class PluginData(
val artifact: String,
val version: String? = null
)
data class PluginOption(
val key: String,
val value: String
)
}
sealed class PluginOption {
abstract val key: String
/**
* when true a value of given plugin option is sensitive for incremental compilation
* when false compilation task can be skipped even if value differs from previous one
*/
abstract val sensitive: Boolean
}
data class StringOption(
override val key: String,
val value: String,
override val sensitive: Boolean = true
) : PluginOption()
data class FilesOption(
override val key: String,
val files: List<File>,
override val sensitive: Boolean = true
) : PluginOption()
// TODO: It should be part of "Compilation Process": KotlinModule.compilationRequestFor(METADATA | PLATFORM) -> CompilationRequest
// But there is no such thing at the moment :)
fun KotlinModuleFragment.metadataCompilationPluginData(): List<PluginData> =
@@ -81,8 +100,7 @@ abstract class BasicKpmCompilerPlugin : KpmCompilerPlugin {
protected abstract fun nativePluginArtifact(): PluginData.ArtifactCoordinates?
protected abstract val pluginOptions: List<PluginData.PluginOption>
protected abstract val pluginOptions: List<PluginOption>
override fun forMetadataCompilation(fragment: KotlinModuleFragment) = pluginDataOrNull(commonPluginArtifact())