KotlinToolingMetadata: Add stronger typing for target extras

This commit is contained in:
sebastian.sellmair
2021-02-03 18:51:40 +01:00
committed by TeamCityServer
parent 896e77cd32
commit 0a59301f8a
7 changed files with 274 additions and 112 deletions
@@ -25,14 +25,14 @@ internal fun KotlinToolingMetadata.toJsonObject(): JsonObject {
}
}
internal fun KotlinToolingMetadata.ProjectSettings.toJsonObject(): JsonObject {
private fun KotlinToolingMetadata.ProjectSettings.toJsonObject(): JsonObject {
return JsonObject().apply {
addProperty("isHmppEnabled", isHmppEnabled)
addProperty("isCompatibilityMetadataVariantEnabled", isCompatibilityMetadataVariantEnabled)
}
}
internal fun List<KotlinToolingMetadata.ProjectTargetMetadata>.toJsonArray(): JsonArray {
private fun List<KotlinToolingMetadata.ProjectTargetMetadata>.toJsonArray(): JsonArray {
return JsonArray().apply {
this@toJsonArray.forEach { targetMetadata ->
add(targetMetadata.toJsonObject())
@@ -40,20 +40,54 @@ internal fun List<KotlinToolingMetadata.ProjectTargetMetadata>.toJsonArray(): Js
}
}
internal fun KotlinToolingMetadata.ProjectTargetMetadata.toJsonObject(): JsonObject {
private fun KotlinToolingMetadata.ProjectTargetMetadata.toJsonObject(): JsonObject {
return JsonObject().apply {
addProperty("target", target)
addProperty("platformType", platformType)
if (extras.isNotEmpty()) {
add("extras", JsonObject().apply {
for (extra in extras) {
addProperty(extra.key, extra.value)
}
})
extras.toJsonObject().takeIf { it.size() > 0 }?.let { extrasJsonObject ->
add("extras", extrasJsonObject)
}
}
}
private fun KotlinToolingMetadata.ProjectTargetMetadata.Extras.toJsonObject(): JsonObject {
return JsonObject().apply {
jvm?.let { add("jvm", it.toJsonObject()) }
android?.let { add("android", it.toJsonObject()) }
js?.let { add("js", it.toJsonObject()) }
native?.let { add("native", it.toJsonObject()) }
}
}
private fun KotlinToolingMetadata.ProjectTargetMetadata.JvmExtras.toJsonObject(): JsonObject {
return JsonObject().apply {
jvmTarget?.let { addProperty("jvmTarget", it) }
addProperty("withJavaEnabled", withJavaEnabled)
}
}
private fun KotlinToolingMetadata.ProjectTargetMetadata.JsExtras.toJsonObject(): JsonObject {
return JsonObject().apply {
addProperty("isBrowserConfigured", isBrowserConfigured)
addProperty("isNodejsConfigured", isNodejsConfigured)
}
}
private fun KotlinToolingMetadata.ProjectTargetMetadata.NativeExtras.toJsonObject(): JsonObject {
return JsonObject().apply {
addProperty("konanTarget", konanTarget)
addProperty("konanVersion", konanVersion)
addProperty("konanAbiVersion", konanAbiVersion)
}
}
private fun KotlinToolingMetadata.ProjectTargetMetadata.AndroidExtras.toJsonObject(): JsonObject {
return JsonObject().apply {
addProperty("sourceCompatibility", sourceCompatibility)
addProperty("targetCompatibility", targetCompatibility)
}
}
sealed class KotlinToolingMetadataParsingResult {
data class Success(val value: KotlinToolingMetadata) : KotlinToolingMetadataParsingResult()
data class Failure(val reason: String) : KotlinToolingMetadataParsingResult()
@@ -104,19 +138,47 @@ private fun JsonObject.toTargetMetadataOrThrow(): KotlinToolingMetadata.ProjectT
return KotlinToolingMetadata.ProjectTargetMetadata(
target = getOrThrow("target").asString,
platformType = getOrThrow("platformType").asString,
extras = (get("extras") as? JsonObject)?.toTargetMetadataExtrasOrThrow() ?: emptyMap()
extras = (get("extras") as? JsonObject)?.toTargetMetadataExtrasOrThrow()
?: KotlinToolingMetadata.ProjectTargetMetadata.Extras()
)
}
private fun JsonObject.toTargetMetadataExtrasOrThrow(): Map<String, String> {
val map = mutableMapOf<String, String>()
this.keySet().forEach { key ->
val primitive = this[key] as? JsonPrimitive
if (primitive != null) {
map[key] = primitive.asString
}
}
return map.toMap()
private fun JsonObject.toTargetMetadataExtrasOrThrow(): KotlinToolingMetadata.ProjectTargetMetadata.Extras {
return KotlinToolingMetadata.ProjectTargetMetadata.Extras(
jvm = get("jvm")?.asJsonObject?.toJvmExtrasOrThrow(),
android = get("android")?.asJsonObject?.toAndroidExtrasOrThrow(),
js = get("js")?.asJsonObject?.toJsExtrasOrThrow(),
native = get("native")?.asJsonObject?.toNativeExtrasOrThrow()
)
}
private fun JsonObject.toJvmExtrasOrThrow(): KotlinToolingMetadata.ProjectTargetMetadata.JvmExtras {
return KotlinToolingMetadata.ProjectTargetMetadata.JvmExtras(
jvmTarget = get("jvmTarget")?.asString,
withJavaEnabled = getOrThrow("withJavaEnabled").asBoolean
)
}
private fun JsonObject.toJsExtrasOrThrow(): KotlinToolingMetadata.ProjectTargetMetadata.JsExtras {
return KotlinToolingMetadata.ProjectTargetMetadata.JsExtras(
isBrowserConfigured = getOrThrow("isBrowserConfigured").asBoolean,
isNodejsConfigured = getOrThrow("isNodejsConfigured").asBoolean
)
}
private fun JsonObject.toNativeExtrasOrThrow(): KotlinToolingMetadata.ProjectTargetMetadata.NativeExtras {
return KotlinToolingMetadata.ProjectTargetMetadata.NativeExtras(
konanTarget = getOrThrow("konanTarget").asString,
konanVersion = getOrThrow("konanVersion").asString,
konanAbiVersion = getOrThrow("konanAbiVersion").asString
)
}
private fun JsonObject.toAndroidExtrasOrThrow(): KotlinToolingMetadata.ProjectTargetMetadata.AndroidExtras {
return KotlinToolingMetadata.ProjectTargetMetadata.AndroidExtras(
sourceCompatibility = getOrThrow("sourceCompatibility").asString,
targetCompatibility = getOrThrow("targetCompatibility").asString
)
}
private fun JsonObject.getOrThrow(key: String): JsonElement {
@@ -18,6 +18,7 @@ data class KotlinToolingMetadata(
* - org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
* - org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlugin
* - ...
* )
*/
val buildPlugin: String,
val buildPluginVersion: String,
@@ -34,8 +35,36 @@ data class KotlinToolingMetadata(
data class ProjectTargetMetadata(
val target: String,
val platformType: String,
val extras: Map<String, String>
)
val extras: Extras
) {
data class Extras(
val jvm: JvmExtras? = null,
val android: AndroidExtras? = null,
val js: JsExtras? = null,
val native: NativeExtras? = null
)
data class JvmExtras(
val jvmTarget: String?,
val withJavaEnabled: Boolean
)
data class AndroidExtras(
val sourceCompatibility: String,
val targetCompatibility: String,
)
data class JsExtras(
val isBrowserConfigured: Boolean,
val isNodejsConfigured: Boolean,
)
data class NativeExtras(
val konanTarget: String,
val konanVersion: String,
val konanAbiVersion: String
)
}
companion object
}
@@ -10,6 +10,8 @@ import junit.framework.Assert.assertTrue
import org.intellij.lang.annotations.Language
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
@@ -20,48 +22,64 @@ class DeserializeStringTest {
@Test
fun sample1() {
@Language("JSON") val json =
"""
{
"buildSystem": "Gradle",
"buildSystemVersion": "6.7",
"buildPlugin": "org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper",
"buildPluginVersion": "1.5.255-SNAPSHOT",
"projectSettings": {
"isHmppEnabled": false,
"isCompatibilityMetadataVariantEnabled": true
},
"projectTargets": [
{
"target": "org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget",
"platformType": "androidJvm",
"extras": {
@Language("JSON") val json = """
{
"buildSystem": "Gradle",
"buildSystemVersion": "6.7",
"buildPlugin": "org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper",
"buildPluginVersion": "1.5.255-SNAPSHOT",
"projectSettings": {
"isHmppEnabled": false,
"isCompatibilityMetadataVariantEnabled": true
},
"projectTargets": [
{
"target": "org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget",
"platformType": "androidJvm",
"extras": {
"android": {
"sourceCompatibility": "1.7",
"targetCompatibility": "1.7"
}
},
{
"target": "org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget_Decorated",
"platformType": "js",
"extras": {
"isBrowserConfigured": "true",
"isNodejsConfigured": "true"
}
},
{
"target": "org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget_Decorated",
"platformType": "jvm",
"extras": {
"withJavaEnabled": "false",
"jvmTarget": "1.8"
}
},
{
"target": "org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget_Decorated",
"platformType": "common"
}
]
}
},
{
"target": "org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget_Decorated",
"platformType": "js",
"extras": {
"js": {
"isBrowserConfigured": true,
"isNodejsConfigured": true
}
}
},
{
"target": "org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget_Decorated",
"platformType": "jvm",
"extras": {
"jvm": {
"jvmTarget": "1.8",
"withJavaEnabled": false
}
}
},
{
"target": "org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests_Decorated",
"platformType": "native",
"extras": {
"native": {
"konanTarget": "linux_x64",
"konanVersion": "1.5-dev-17775",
"konanAbiVersion": "1.4.2"
}
}
},
{
"target": "org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget_Decorated",
"platformType": "common"
}
]
}
""".trimIndent()
val metadata = KotlinToolingMetadata.parseJsonOrThrow(json)
@@ -71,29 +89,48 @@ class DeserializeStringTest {
assertEquals("1.5.255-SNAPSHOT", metadata.buildPluginVersion)
assertFalse(metadata.projectSettings.isHmppEnabled)
assertTrue(metadata.projectSettings.isCompatibilityMetadataVariantEnabled)
assertEquals(4, metadata.projectTargets.size, "Expected exactly 4 targets")
assertEquals(5, metadata.projectTargets.size, "Expected exactly 4 targets")
val androidJvmTarget = metadata.projectTargets.single { it.platformType == "androidJvm" }
assertEquals("org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget", androidJvmTarget.target)
assertEquals(2, androidJvmTarget.extras.size, "Expected exactly two extras")
assertEquals("1.7", androidJvmTarget.extras["sourceCompatibility"])
assertEquals("1.7", androidJvmTarget.extras["targetCompatibility"])
assertEquals("1.7", androidJvmTarget.extras.android?.sourceCompatibility)
assertEquals("1.7", androidJvmTarget.extras.android?.targetCompatibility)
assertNull(androidJvmTarget.extras.jvm)
assertNull(androidJvmTarget.extras.js)
assertNull(androidJvmTarget.extras.native)
val jsTarget = metadata.projectTargets.single { it.platformType == "js" }
assertEquals("org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget_Decorated", jsTarget.target)
assertEquals(2, jsTarget.extras.size, "Expected exactly two extras")
assertEquals("true", jsTarget.extras["isBrowserConfigured"])
assertEquals("true", jsTarget.extras["isNodejsConfigured"])
assertEquals(true, jsTarget.extras.js?.isBrowserConfigured)
assertEquals(true, jsTarget.extras.js?.isNodejsConfigured)
assertNull(jsTarget.extras.android)
assertNull(jsTarget.extras.jvm)
assertNull(jsTarget.extras.native)
val jvmTarget = metadata.projectTargets.single { it.platformType == "jvm" }
assertEquals("org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget_Decorated", jvmTarget.target)
assertEquals(2, jvmTarget.extras.size, "Expected exactly two extras")
assertEquals("false", jvmTarget.extras["withJavaEnabled"])
assertEquals("1.8", jvmTarget.extras["jvmTarget"])
assertEquals(false, jvmTarget.extras.jvm?.withJavaEnabled)
assertEquals("1.8", jvmTarget.extras.jvm?.jvmTarget)
assertNull(jvmTarget.extras.android)
assertNull(jvmTarget.extras.js)
assertNull(jvmTarget.extras.native)
val nativeTarget = metadata.projectTargets.single { it.platformType == "native" }
assertEquals("org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests_Decorated", nativeTarget.target)
val nativeExtras = assertNotNull(nativeTarget.extras.native)
assertEquals("linux_x64", nativeExtras.konanTarget)
assertEquals("1.5-dev-17775", nativeExtras.konanVersion)
assertEquals("1.4.2", nativeExtras.konanAbiVersion)
assertNull(nativeTarget.extras.android)
assertNull(nativeTarget.extras.jvm)
assertNull(nativeTarget.extras.js)
val commonTarget = metadata.projectTargets.single { it.platformType == "common" }
assertEquals("org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget_Decorated", commonTarget.target)
assertEquals(0, commonTarget.extras.size, "Expected zero extras")
assertNull(commonTarget.extras.android)
assertNull(commonTarget.extras.jvm)
assertNull(commonTarget.extras.js)
assertNull(commonTarget.extras.native)
}
}
@@ -28,10 +28,7 @@ class SerializeAndDeserializeTest {
ProjectTargetMetadata(
target = "generic target",
platformType = "generic platform type",
extras = mapOf(
"extra0" to "extra value0",
"extra1" to "extra value1"
)
extras = ProjectTargetMetadata.Extras()
)
)
)
@@ -44,15 +41,35 @@ class SerializeAndDeserializeTest {
ProjectTargetMetadata(
target = "generic target",
platformType = "generic platform type",
extras = mapOf(
"extra0" to "{ some extra value %\" with, chars to escape",
"extra1" to "extra value1"
extras = ProjectTargetMetadata.Extras(
jvm = ProjectTargetMetadata.JvmExtras(
jvmTarget = null,
withJavaEnabled = true
),
android = ProjectTargetMetadata.AndroidExtras(
sourceCompatibility = "1.8",
targetCompatibility = "1.6"
),
js = ProjectTargetMetadata.JsExtras(
isBrowserConfigured = true,
isNodejsConfigured = false
),
native = ProjectTargetMetadata.NativeExtras(
konanTarget = "linuxX64",
konanVersion = "1.0-generic",
konanAbiVersion = "1.4.2"
)
)
),
ProjectTargetMetadata(
target = "generic target 2 (with no extras)",
platformType = "generic platform type 2",
extras = emptyMap()
extras = ProjectTargetMetadata.Extras(
jvm = ProjectTargetMetadata.JvmExtras(
jvmTarget = "1.8",
withJavaEnabled = true
)
)
)
)
)