[KPM] Implement KotlinExternalModelContainer
KT-51262 KT-51220
This commit is contained in:
committed by
Space
parent
55448943af
commit
f1655e5f4e
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.gradle.kpm.idea.InternalKotlinGradlePluginApi
|
||||
import java.io.Serializable
|
||||
|
||||
interface KotlinHasExternalModel {
|
||||
val external: KotlinExternalModelContainer
|
||||
}
|
||||
|
||||
abstract class KotlinExternalModelContainer internal constructor() : Serializable {
|
||||
abstract operator fun <T : Any> contains(key: KotlinExternalModelKey<T>): Boolean
|
||||
abstract operator fun <T : Any> get(key: KotlinExternalModelKey<T>): T?
|
||||
fun <T : Any> getOrThrow(key: KotlinExternalModelKey<T>): T = get(key)
|
||||
?: throw NoSuchElementException("Missing external model for ${key.id}")
|
||||
|
||||
@InternalKotlinGradlePluginApi
|
||||
companion object {
|
||||
fun mutable(): KotlinMutableExternalModelContainer = KotlinMutableExternalModelContainerImpl()
|
||||
}
|
||||
|
||||
object Empty : KotlinExternalModelContainer() {
|
||||
override fun <T : Any> contains(key: KotlinExternalModelKey<T>): Boolean = false
|
||||
override fun <T : Any> get(key: KotlinExternalModelKey<T>): T? = null
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KotlinMutableExternalModelContainer internal constructor() : KotlinExternalModelContainer() {
|
||||
abstract operator fun <T : Any> set(key: KotlinExternalModelKey<T>, value: T)
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.gradle.kpm.idea.InternalKotlinGradlePluginApi
|
||||
import java.io.Serializable
|
||||
|
||||
internal class KotlinMutableExternalModelContainerImpl : KotlinMutableExternalModelContainer(), Serializable {
|
||||
private val values = mutableMapOf<KotlinExternalModelKey<*>, Any>()
|
||||
|
||||
@Synchronized
|
||||
override fun <T : Any> set(key: KotlinExternalModelKey<T>, value: T) {
|
||||
values[key] = value
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun <T : Any> contains(key: KotlinExternalModelKey<T>): Boolean {
|
||||
return key in values
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@Suppress("unchecked_cast")
|
||||
override fun <T : Any> get(key: KotlinExternalModelKey<T>): T? {
|
||||
return values[key]?.let { it as T }
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun writeReplace(): Any {
|
||||
val serializedValues = values.filterKeys { it.serializer != null }
|
||||
.mapValues { (key, value) ->
|
||||
@Suppress("unchecked_cast")
|
||||
val serializer = checkNotNull(key.serializer) as KotlinExternalModelSerializer<Any>
|
||||
serializer.serialize(value)
|
||||
}.mapKeys { (key, _) -> key.id }
|
||||
.toMutableMap()
|
||||
|
||||
return SerializedKotlinExternalModelContainer(serializedValues)
|
||||
}
|
||||
}
|
||||
|
||||
private class SerializedKotlinExternalModelContainer(
|
||||
private val serializedValues: MutableMap<KotlinExternalModelId<*>, ByteArray>
|
||||
) : KotlinExternalModelContainer(), Serializable {
|
||||
|
||||
private val deserializedValues = mutableMapOf<KotlinExternalModelId<*>, Any>()
|
||||
|
||||
@Synchronized
|
||||
override fun <T : Any> contains(key: KotlinExternalModelKey<T>): Boolean {
|
||||
return key.id in deserializedValues || key.id in serializedValues
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@Suppress("unchecked_cast")
|
||||
override fun <T : Any> get(key: KotlinExternalModelKey<T>): T? {
|
||||
deserializedValues[key.id]?.let { return it as T }
|
||||
val serializedValue = serializedValues.remove(key.id) ?: return null
|
||||
val deserializedValue = key.serializer?.deserialize(serializedValue) ?: return null
|
||||
deserializedValues[key.id] = deserializedValue
|
||||
return deserializedValue
|
||||
}
|
||||
|
||||
@InternalKotlinGradlePluginApi
|
||||
companion object {
|
||||
private const val serialVersionUID = 0L
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName")
|
||||
|
||||
package org.jetbrains.kotlin.gradle.kpm
|
||||
|
||||
import org.jetbrains.kotlin.gradle.kpm.idea.InternalKotlinGradlePluginApi
|
||||
import java.io.Serializable
|
||||
|
||||
inline fun <reified T : Any> KotlinExternalModelId(disambiguationName: String? = null): KotlinExternalModelId<T> {
|
||||
return KotlinExternalModelId(KotlinExternalModelType(), disambiguationName)
|
||||
}
|
||||
|
||||
class KotlinExternalModelId<T : Any> @PublishedApi internal constructor(
|
||||
internal val type: KotlinExternalModelType<T>,
|
||||
private val disambiguationName: String? = null
|
||||
) : Serializable {
|
||||
override fun toString(): String {
|
||||
return if (disambiguationName == null) type.toString()
|
||||
else "$disambiguationName:$type"
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as KotlinExternalModelId<*>
|
||||
if (type != other.type) return false
|
||||
if (disambiguationName != other.disambiguationName) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = type.hashCode()
|
||||
result = 31 * result + (disambiguationName?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
@InternalKotlinGradlePluginApi
|
||||
companion object {
|
||||
private const val serialVersionUID = 0L
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName")
|
||||
|
||||
package org.jetbrains.kotlin.gradle.kpm
|
||||
|
||||
inline fun <reified T : Any> KotlinExternalModelKey(
|
||||
disambiguationName: String? = null, serializer: KotlinExternalModelSerializer<T>? = null
|
||||
): KotlinExternalModelKey<T> = KotlinExternalModelKey(KotlinExternalModelId(disambiguationName), serializer)
|
||||
|
||||
inline fun <reified T : Any> KotlinExternalModelKey(serializer: KotlinExternalModelSerializer<T>): KotlinExternalModelKey<T> =
|
||||
KotlinExternalModelKey(KotlinExternalModelId(), serializer)
|
||||
|
||||
class KotlinExternalModelKey<T : Any> @PublishedApi internal constructor(
|
||||
internal val id: KotlinExternalModelId<T>,
|
||||
internal val serializer: KotlinExternalModelSerializer<T>? = null,
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as KotlinExternalModelKey<*>
|
||||
|
||||
if (id != other.id) return false
|
||||
if (serializer != other.serializer) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + (serializer?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.gradle.kpm.idea.InternalKotlinGradlePluginApi
|
||||
import java.io.*
|
||||
|
||||
interface KotlinExternalModelSerializer<T : Any> {
|
||||
fun serialize(value: T): ByteArray
|
||||
fun deserialize(data: ByteArray): T
|
||||
|
||||
@InternalKotlinGradlePluginApi
|
||||
companion object {
|
||||
inline fun <reified T : Serializable> serializable(): KotlinExternalModelSerializer<T> =
|
||||
KotlinSerializableExternalModelSerializer(T::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal class KotlinSerializableExternalModelSerializer<T : Serializable>(
|
||||
private val clazz: Class<T>
|
||||
) : KotlinExternalModelSerializer<T> {
|
||||
override fun serialize(value: T): ByteArray {
|
||||
return ByteArrayOutputStream().run {
|
||||
ObjectOutputStream(this).use { stream -> stream.writeObject(value) }
|
||||
toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
override fun deserialize(data: ByteArray): T {
|
||||
return ObjectInputStream(ByteArrayInputStream(data)).use { stream ->
|
||||
clazz.cast(stream.readObject())
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.gradle.kpm.idea.InternalKotlinGradlePluginApi
|
||||
import java.io.Serializable
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
@Suppress("FunctionName")
|
||||
inline fun <reified T : Any> KotlinExternalModelType(): KotlinExternalModelType<T> {
|
||||
return KotlinExternalModelType(externalModelTypeSignature(typeOf<T>()))
|
||||
}
|
||||
|
||||
class KotlinExternalModelType</* Used as phantom type */ @Suppress("unused") T: Any>
|
||||
@PublishedApi internal constructor(private val signature: String) : Serializable {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is KotlinExternalModelType<*>) return false
|
||||
if (other.signature != this.signature) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = 31 * signature.hashCode()
|
||||
override fun toString(): String = "ExternalModelType($signature)"
|
||||
|
||||
@InternalKotlinGradlePluginApi
|
||||
companion object {
|
||||
private const val serialVersionUID = 0L
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun externalModelTypeSignature(type: KType): String {
|
||||
require(!type.isMarkedNullable) { "Unexpected nullable type. Found $type" }
|
||||
require(type.arguments.isEmpty()) { "Parameterized types are not supported. Found $type" }
|
||||
val classifier = requireNotNull(type.classifier) { "Expected classifier. Found $type" }
|
||||
val clazz = (classifier as? KClass<*>) ?: throw IllegalArgumentException("Expected KClass classifier. Found $classifier")
|
||||
return clazz.qualifiedName ?: throw IllegalArgumentException("Missing qualifiedName in $type")
|
||||
}
|
||||
+4
-1
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.kpm.idea
|
||||
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinExternalModelContainer
|
||||
import java.io.Serializable
|
||||
|
||||
interface IdeaKotlinFragment : Serializable {
|
||||
@@ -14,6 +15,7 @@ interface IdeaKotlinFragment : Serializable {
|
||||
val directRefinesDependencies: Collection<IdeaKotlinFragment>
|
||||
val sourceDirectories: Collection<IdeaKotlinSourceDirectory>
|
||||
val resourceDirectories: Collection<IdeaKotlinResourceDirectory>
|
||||
val external: KotlinExternalModelContainer
|
||||
}
|
||||
|
||||
@InternalKotlinGradlePluginApi
|
||||
@@ -23,7 +25,8 @@ data class IdeaKotlinFragmentImpl(
|
||||
override val dependencies: Collection<IdeaKotlinFragmentDependency>,
|
||||
override val directRefinesDependencies: Collection<IdeaKotlinFragment>,
|
||||
override val sourceDirectories: Collection<IdeaKotlinSourceDirectory>,
|
||||
override val resourceDirectories: Collection<IdeaKotlinResourceDirectory>
|
||||
override val resourceDirectories: Collection<IdeaKotlinResourceDirectory>,
|
||||
override val external: KotlinExternalModelContainer
|
||||
) : IdeaKotlinFragment {
|
||||
|
||||
@InternalKotlinGradlePluginApi
|
||||
|
||||
@@ -7,6 +7,7 @@ plugins {
|
||||
dependencies {
|
||||
implementation(gradleKotlinDsl())
|
||||
compileOnly(project(":kotlin-gradle-plugin"))
|
||||
compileOnly(project(":kotlin-gradle-plugin-idea"))
|
||||
compileOnly("com.android.tools.build:gradle:7.0.0")
|
||||
}
|
||||
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:OptIn(InternalKotlinGradlePluginApi::class)
|
||||
|
||||
package org.jetbrains.kotlin.gradle.android
|
||||
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinExternalModelKey
|
||||
import org.jetbrains.kotlin.gradle.kpm.idea.InternalKotlinGradlePluginApi
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
|
||||
internal val androidDslKey = KotlinExternalModelKey<AndroidDsl>()
|
||||
|
||||
class AndroidDsl : Serializable {
|
||||
var compileSdk = 0
|
||||
var isMinifyEnabled: Boolean = false
|
||||
var androidManifest: File? = null
|
||||
}
|
||||
+5
@@ -78,4 +78,9 @@ fun KotlinGradleModule.createKotlinAndroidVariant(androidVariant: BaseVariant) {
|
||||
androidVariant.getCompileClasspath(mainBytecodeKey),
|
||||
project.getAndroidRuntimeJars()
|
||||
)
|
||||
|
||||
val androidDsl = AndroidDsl()
|
||||
androidDsl.androidManifest = project.file("AndroidManifest.xml")
|
||||
androidDsl.compileSdk = 23
|
||||
androidCommon.external[androidDslKey] = androidDsl
|
||||
}
|
||||
|
||||
+4
-3
@@ -6,9 +6,10 @@
|
||||
package org.jetbrains.kotlin.gradle.android
|
||||
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleFragment
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleFragmentInternal
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
|
||||
|
||||
val KotlinGradleModule.androidCommon: KotlinGradleFragment
|
||||
get() = fragments.findByName("android") ?: fragments.create("android") { fragment ->
|
||||
val KotlinGradleModule.androidCommon: KotlinGradleFragmentInternal
|
||||
get() = (fragments.findByName("android") ?: fragments.create("android") { fragment ->
|
||||
fragment.refines(common)
|
||||
}
|
||||
}) as KotlinGradleFragmentInternal
|
||||
|
||||
+4
-1
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.kpm.idea
|
||||
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinExternalModelContainer
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinHasExternalModel
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleFragment
|
||||
|
||||
internal fun KotlinGradleFragment.toIdeaKotlinFragment(
|
||||
@@ -21,7 +23,8 @@ internal fun KotlinGradleFragment.toIdeaKotlinFragment(
|
||||
sourceDirectories = kotlinSourceRoots.sourceDirectories.files.toList().map { file ->
|
||||
IdeaKotlinSourceDirectoryImpl(file)
|
||||
},
|
||||
resourceDirectories = emptyList()
|
||||
resourceDirectories = emptyList(),
|
||||
external = (this as? KotlinHasExternalModel)?.external ?: KotlinExternalModelContainer.Empty
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.plugin.mpp.external
|
||||
|
||||
import kotlin.reflect.KType
|
||||
|
||||
|
||||
interface ExternalModelContainer {
|
||||
|
||||
}
|
||||
|
||||
interface MutableExternalModelContainer {
|
||||
|
||||
}
|
||||
+8
-1
@@ -12,6 +12,9 @@ import org.gradle.api.file.SourceDirectorySet
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.util.ConfigureUtil
|
||||
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinExternalModelContainer
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinHasExternalModel
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinMutableExternalModelContainer
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
|
||||
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinDependencyHandler
|
||||
@@ -31,7 +34,9 @@ open class KotlinGradleFragmentInternal @Inject constructor(
|
||||
final override val containingModule: KotlinGradleModule,
|
||||
final override val fragmentName: String,
|
||||
dependencyConfigurations: KotlinFragmentDependencyConfigurations
|
||||
) : KotlinGradleFragment, KotlinFragmentDependencyConfigurations by dependencyConfigurations {
|
||||
) : KotlinGradleFragment,
|
||||
KotlinFragmentDependencyConfigurations by dependencyConfigurations,
|
||||
KotlinHasExternalModel {
|
||||
|
||||
final override fun getName(): String = fragmentName
|
||||
|
||||
@@ -43,6 +48,8 @@ open class KotlinGradleFragmentInternal @Inject constructor(
|
||||
// FIXME check for consistency
|
||||
override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder()
|
||||
|
||||
override val external: KotlinMutableExternalModelContainer = KotlinExternalModelContainer.mutable()
|
||||
|
||||
override fun refines(other: KotlinGradleFragment) {
|
||||
checkCanRefine(other)
|
||||
refines(containingModule.fragments.named(other.name))
|
||||
|
||||
Reference in New Issue
Block a user