[kpm] kgp: Integrate IdeaKpm.* protobuf serialization into IdeaKpmProjectModelBuilder

- Rename IdeaKpmProjectModelBuildingContext to IdeaKpmProjectBuildingContext
- Support building IdeaKpmProjectContainer
- Implement IdeaKpmSerializationContext on Gradle side

^KT-52568 In Progress
This commit is contained in:
sebastian.sellmair
2022-06-13 14:22:09 +02:00
committed by Space
parent 2a5457f59d
commit 2d04d4f06e
8 changed files with 122 additions and 18 deletions
@@ -65,6 +65,7 @@ dependencies {
commonCompileOnly(project(":kotlin-tooling-metadata"))
commonImplementation(project(":kotlin-gradle-plugin-idea"))
commonImplementation(project(":kotlin-gradle-plugin-idea-proto"))
commonImplementation(project(":kotlin-util-klib"))
commonImplementation(project(":native:kotlin-klib-commonizer-api"))
commonImplementation(project(":kotlin-project-model"))
@@ -5,6 +5,9 @@ package org.jetbrains.kotlin.gradle.kpm.idea
import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.gradle.kpm.external.ExternalVariantApi
import org.jetbrains.kotlin.gradle.kpm.idea.IdeaKpmProjectModelBuilder.FragmentConstraint
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmExtrasSerializationExtension
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmExtrasSerializationExtensionBuilder
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmSerializationContext
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.native
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmFragment
@@ -13,10 +16,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.containingVariants
import org.jetbrains.kotlin.project.model.KpmVariant
import java.io.File
internal interface IdeaKpmProjectModelBuildingContext {
internal interface IdeaKpmProjectBuildingContext {
val dependencyResolver: IdeaKpmDependencyResolver
companion object Empty : IdeaKpmProjectModelBuildingContext {
companion object Empty : IdeaKpmProjectBuildingContext {
override val dependencyResolver: IdeaKpmDependencyResolver = IdeaKpmDependencyResolver.Empty
}
}
@@ -124,12 +127,19 @@ interface IdeaKpmProjectModelBuilder {
constraint: FragmentConstraint
)
fun buildIdeaKpmProjectModel(): IdeaKpmProject
@ExternalVariantApi
fun registerExtrasSerializationExtension(
extension: IdeaKpmExtrasSerializationExtension
)
fun buildSerializationContext(): IdeaKpmSerializationContext
fun buildIdeaKpmProject(): IdeaKpmProject
companion object
}
internal fun IdeaKpmProjectModelBuildingContext.IdeaKpmProject(extension: KotlinPm20ProjectExtension): IdeaKpmProject {
internal fun IdeaKpmProjectBuildingContext.IdeaKpmProject(extension: KotlinPm20ProjectExtension): IdeaKpmProject {
return IdeaKpmProjectImpl(
gradlePluginVersion = extension.project.getKotlinPluginVersion(),
coreLibrariesVersion = extension.coreLibrariesVersion,
@@ -154,3 +164,10 @@ infix fun FragmentConstraint.and(
operator fun FragmentConstraint.not() = FragmentConstraint { fragment ->
this@not(fragment).not()
}
@ExternalVariantApi
fun IdeaKpmProjectModelBuilder.registerExtrasSerializationExtension(
builder: IdeaKpmExtrasSerializationExtensionBuilder.() -> Unit
) {
registerExtrasSerializationExtension(IdeaKpmExtrasSerializationExtension(builder))
}
@@ -11,13 +11,20 @@ import org.gradle.api.Project
import org.gradle.tooling.provider.model.ToolingModelBuilder
import org.jetbrains.kotlin.gradle.kpm.external.ExternalVariantApi
import org.jetbrains.kotlin.gradle.kpm.idea.IdeaKpmProjectModelBuilder.*
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmExtrasSerializationExtension
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmSerializationContext
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.kpm.idea.proto.toByteArray
import org.jetbrains.kotlin.tooling.core.UnsafeApi
internal class IdeaKpmProjectModelBuilderImpl @UnsafeApi("Use factory methods instead") constructor(
private val extension: KotlinPm20ProjectExtension,
) : ToolingModelBuilder, IdeaKpmProjectModelBuilder {
private inner class IdeaKpmBuildingContextImpl : IdeaKpmProjectBuildingContext {
override val dependencyResolver = createDependencyResolver()
}
private data class RegisteredDependencyResolver(
val resolver: IdeaKpmDependencyResolver,
val constraint: FragmentConstraint,
@@ -39,6 +46,7 @@ internal class IdeaKpmProjectModelBuilderImpl @UnsafeApi("Use factory methods in
private val registeredDependencyResolvers = mutableListOf<RegisteredDependencyResolver>()
private val registeredDependencyTransformers = mutableListOf<RegisteredDependencyTransformer>()
private val registeredDependencyEffects = mutableListOf<RegisteredDependencyEffect>()
private val registeredExtrasSerializationExtensions = mutableListOf<IdeaKpmExtrasSerializationExtension>()
override fun registerDependencyResolver(
resolver: IdeaKpmDependencyResolver,
@@ -70,20 +78,37 @@ internal class IdeaKpmProjectModelBuilderImpl @UnsafeApi("Use factory methods in
)
}
override fun buildIdeaKpmProjectModel(): IdeaKpmProject {
return Context().IdeaKpmProject(extension)
override fun registerExtrasSerializationExtension(
extension: IdeaKpmExtrasSerializationExtension
) {
registeredExtrasSerializationExtensions.add(extension)
}
override fun buildSerializationContext(): IdeaKpmSerializationContext {
return IdeaKpmSerializationContext(
logger = extension.project.logger,
extrasSerializationExtensions = registeredExtrasSerializationExtensions.toList()
)
}
override fun buildIdeaKpmProject(): IdeaKpmProject =
IdeaKpmBuildingContextImpl().IdeaKpmProject(extension)
override fun canBuild(modelName: String): Boolean =
modelName == IdeaKpmProject::class.java.name
modelName == IdeaKpmProject::class.java.name || modelName == IdeaKpmProjectContainer::class.java.name
override fun buildAll(modelName: String, project: Project): IdeaKpmProject {
override fun buildAll(modelName: String, project: Project): Any {
check(project === extension.project) { "Expected project ${extension.project.path}, found ${project.path}" }
return buildIdeaKpmProjectModel()
}
private inner class Context : IdeaKpmProjectModelBuildingContext {
override val dependencyResolver = createDependencyResolver()
return when (modelName) {
IdeaKpmProject::class.java.name -> buildIdeaKpmProject()
IdeaKpmProjectContainer::class.java.name -> IdeaKpmProjectContainer(
buildIdeaKpmProject().toByteArray(buildSerializationContext())
)
else -> throw IllegalArgumentException("Unexpected modelName: $modelName")
}
}
private fun createDependencyResolver(): IdeaKpmDependencyResolver {
@@ -0,0 +1,61 @@
/*
* 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.kpm.idea
import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmExtrasSerializationExtension
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmExtrasSerializer
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmSerializationContext
import org.jetbrains.kotlin.gradle.kpm.idea.serialize.IdeaKpmSerializationLogger
import org.jetbrains.kotlin.tooling.core.Extras
internal fun IdeaKpmSerializationContext(
logger: Logger, extrasSerializationExtensions: List<IdeaKpmExtrasSerializationExtension>
): IdeaKpmSerializationContext {
return IdeaKpmSerializationContextImpl(
extrasSerializationExtension = IdeaKpmCompositeExtrasSerializationExtension(logger, extrasSerializationExtensions),
logger = IdeaKpmSerializationLoggerImpl(logger)
)
}
private class IdeaKpmSerializationContextImpl(
override val extrasSerializationExtension: IdeaKpmExtrasSerializationExtension,
override val logger: IdeaKpmSerializationLogger
) : IdeaKpmSerializationContext
/* Simple composite implementation, reporting conflicting extensions */
private class IdeaKpmCompositeExtrasSerializationExtension(
private val logger: Logger,
private val extensions: List<IdeaKpmExtrasSerializationExtension>
) : IdeaKpmExtrasSerializationExtension {
override fun <T : Any> serializer(key: Extras.Key<T>): IdeaKpmExtrasSerializer<T>? {
val serializers = extensions.mapNotNull { it.serializer(key) }
if (serializers.size == 1) {
return serializers.single()
}
if (serializers.size > 1) {
logger.error("Conflicting serializers found for Extras.Key $key: $serializers")
return null
}
return null
}
}
/* Simple Gradle logger based implementation */
private class IdeaKpmSerializationLoggerImpl(
private val logger: Logger,
) : IdeaKpmSerializationLogger {
override fun report(severity: IdeaKpmSerializationLogger.Severity, message: String, cause: Throwable?) {
val text = "[KPM] Serialization: $message"
when (severity) {
IdeaKpmSerializationLogger.Severity.WARNING -> logger.warn(text, cause)
IdeaKpmSerializationLogger.Severity.ERROR -> logger.error(text, cause)
}
}
}
@@ -8,12 +8,12 @@ package org.jetbrains.kotlin.gradle.kpm.idea
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.tooling.core.emptyExtras
internal fun IdeaKpmProjectModelBuildingContext.IdeaKpmFragment(fragment: GradleKpmFragment): IdeaKpmFragment {
internal fun IdeaKpmProjectBuildingContext.IdeaKpmFragment(fragment: GradleKpmFragment): IdeaKpmFragment {
return if (fragment is GradleKpmVariant) buildIdeaKpmVariant(fragment)
else buildIdeaKpmFragment(fragment)
}
private fun IdeaKpmProjectModelBuildingContext.buildIdeaKpmFragment(fragment: GradleKpmFragment): IdeaKpmFragment {
private fun IdeaKpmProjectBuildingContext.buildIdeaKpmFragment(fragment: GradleKpmFragment): IdeaKpmFragment {
return IdeaKpmFragmentImpl(
coordinates = IdeaKpmFragmentCoordinates(fragment),
platforms = fragment.containingVariants.map { variant -> IdeaKpmPlatform(variant) }.toSet(),
@@ -25,7 +25,7 @@ private fun IdeaKpmProjectModelBuildingContext.buildIdeaKpmFragment(fragment: Gr
)
}
private fun IdeaKpmProjectModelBuildingContext.buildIdeaKpmVariant(variant: GradleKpmVariant): IdeaKpmVariant {
private fun IdeaKpmProjectBuildingContext.buildIdeaKpmVariant(variant: GradleKpmVariant): IdeaKpmVariant {
return IdeaKpmVariantImpl(
fragment = buildIdeaKpmFragment(variant),
platform = IdeaKpmPlatform(variant),
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.gradle.kpm.idea
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmModule
internal fun IdeaKpmProjectModelBuildingContext.IdeaKpmModule(module: GradleKpmModule): IdeaKpmModule {
internal fun IdeaKpmProjectBuildingContext.IdeaKpmModule(module: GradleKpmModule): IdeaKpmModule {
return IdeaKpmModuleImpl(
coordinates = IdeaKpmModuleCoordinates(module),
fragments = module.fragments.toList().map { fragment -> IdeaKpmFragment(fragment) }
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.konan.target.HostManager
@Suppress("unused")
/* Receiver acts as scope, or key to that function */
internal fun IdeaKpmProjectModelBuildingContext.IdeaKpmPlatform(variant: GradleKpmVariant): IdeaKpmPlatform {
internal fun IdeaKpmProjectBuildingContext.IdeaKpmPlatform(variant: GradleKpmVariant): IdeaKpmPlatform {
when (variant) {
is GradleKpmJvmVariant -> return IdeaKpmJvmPlatformImpl(variant.compilationData.kotlinOptions.jvmTarget ?: JvmTarget.DEFAULT.name)
is GradleKpmNativeVariantInternal -> return IdeaKpmNativePlatformImpl(variant.konanTarget.name)
@@ -28,5 +28,5 @@ fun Project.applyKpmPlugin(configure: KotlinPm20ProjectExtension.() -> Unit = {}
}
fun KotlinPm20ProjectExtension.buildIdeaKpmProjectModel(): IdeaKpmProject {
return ideaKpmProjectModelBuilder.buildIdeaKpmProjectModel()
return ideaKpmProjectModelBuilder.buildIdeaKpmProject()
}