[Gradle] Map KPM model to Build Tooling Metadata v1.1.0
Update buildKotlinToolingMetadata gradle task KT-49704
This commit is contained in:
+110
-29
@@ -23,7 +23,9 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||
import org.jetbrains.kotlin.gradle.tooling.BuildKotlinToolingMetadataTask
|
||||
@@ -32,12 +34,22 @@ import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.library.KotlinAbiVersion
|
||||
import org.jetbrains.kotlin.tooling.KotlinToolingMetadata
|
||||
import org.jetbrains.kotlin.tooling.toJsonString
|
||||
import org.junit.Assume
|
||||
import org.junit.AssumptionViolatedException
|
||||
import org.junit.Before
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class BuildKotlinToolingMetadataTest {
|
||||
|
||||
@Parameterized.Parameter(0)
|
||||
@JvmField
|
||||
val kpmModelMappingEnabled: Boolean = false
|
||||
|
||||
private val project = ProjectBuilder.builder().build().also{ addBuildEventsListenerRegistryMock(it) } as ProjectInternal
|
||||
private val multiplatformExtension get() = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
|
||||
private val jsExtension get() = project.extensions.getByType(KotlinJsProjectExtension::class.java)
|
||||
@@ -46,6 +58,11 @@ class BuildKotlinToolingMetadataTest {
|
||||
project.extensions.getByType(ExtraPropertiesExtension::class.java).set("kotlin.mpp.enableKotlinToolingMetadataArtifact", "true")
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
project.enableKpmModelMapping(kpmModelMappingEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `multiplatform empty setup`() {
|
||||
project.plugins.apply("kotlin-multiplatform")
|
||||
@@ -57,11 +74,19 @@ class BuildKotlinToolingMetadataTest {
|
||||
assertEquals(KotlinMultiplatformPluginWrapper::class.java.canonicalName, metadata.buildPlugin)
|
||||
assertEquals(project.getKotlinPluginVersion(), metadata.buildPluginVersion)
|
||||
assertEquals(1, metadata.projectTargets.size, "Expected one target (metadata)")
|
||||
assertTrue(
|
||||
KotlinMetadataTarget::class.java.isAssignableFrom(Class.forName(metadata.projectTargets.single().target)),
|
||||
"Expect target to be implement ${KotlinMetadataTarget::class.simpleName}"
|
||||
)
|
||||
assertEquals(common.name, metadata.projectTargets.single().platformType)
|
||||
val targetMetadata = metadata.projectTargets.single()
|
||||
if (kpmModelMappingEnabled) {
|
||||
assertTrue(
|
||||
KotlinGradleFragment::class.java.isAssignableFrom(Class.forName(targetMetadata.target)),
|
||||
"Expect target to be implement ${KotlinGradleFragment::class.simpleName}"
|
||||
)
|
||||
} else {
|
||||
assertTrue(
|
||||
KotlinMetadataTarget::class.java.isAssignableFrom(Class.forName(targetMetadata.target)),
|
||||
"Expect target to be implement ${KotlinMetadataTarget::class.simpleName}"
|
||||
)
|
||||
}
|
||||
assertEquals(common.name, targetMetadata.platformType)
|
||||
assertTrue(metadata.toJsonString().isNotBlank(), "Expected non blank json representation")
|
||||
}
|
||||
|
||||
@@ -87,35 +112,38 @@ class BuildKotlinToolingMetadataTest {
|
||||
val metadata = getKotlinToolingMetadata()
|
||||
assertEquals(KotlinMultiplatformPluginWrapper::class.java.canonicalName, metadata.buildPlugin)
|
||||
|
||||
val expectedTargets = if (kpmModelMappingEnabled) {
|
||||
mapOf(
|
||||
common to KotlinGradleFragmentInternal::class,
|
||||
androidJvm to LegacyMappedVariantWithRuntime::class,
|
||||
jvm to KotlinJvmVariant::class,
|
||||
js to LegacyMappedVariantWithRuntime::class,
|
||||
native to KotlinLinuxX64Variant::class
|
||||
)
|
||||
} else {
|
||||
mapOf(
|
||||
common to KotlinMetadataTarget::class,
|
||||
androidJvm to KotlinAndroidTarget::class,
|
||||
jvm to KotlinJvmTarget::class,
|
||||
js to KotlinJsTarget::class,
|
||||
native to KotlinNativeTargetWithHostTests::class
|
||||
)
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
listOf(common, androidJvm, jvm, js, native).map { it.name }.sorted(),
|
||||
expectedTargets.keys.map { it.name }.sorted(),
|
||||
metadata.projectTargets.map { it.platformType }.sorted()
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
KotlinMetadataTarget::class.java.canonicalName,
|
||||
metadata.projectTargets.single { it.platformType == common.name }.target
|
||||
)
|
||||
expectedTargets.forEach { (platformType, targetClass) ->
|
||||
assertEquals(
|
||||
targetClass.java.canonicalName,
|
||||
metadata.projectTargets.single { it.platformType == platformType.name }.target,
|
||||
"Platform '$platformType' has different target class"
|
||||
)
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
KotlinAndroidTarget::class.java.canonicalName,
|
||||
metadata.projectTargets.single { it.platformType == androidJvm.name }.target
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
KotlinJvmTarget::class.java.canonicalName,
|
||||
metadata.projectTargets.single { it.platformType == jvm.name }.target
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
KotlinJsTarget::class.java.canonicalName,
|
||||
metadata.projectTargets.single { it.platformType == js.name }.target
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
KotlinNativeTargetWithHostTests::class.java.canonicalName,
|
||||
metadata.projectTargets.single { it.platformType == native.name }.target
|
||||
)
|
||||
assertEquals(kpmModelMappingEnabled, metadata.projectSettings.isKPMEnabled, "projectSettings.isKPMEnabled must be set")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,6 +195,7 @@ class BuildKotlinToolingMetadataTest {
|
||||
|
||||
@Test
|
||||
fun js() {
|
||||
Assume.assumeFalse("KPM model mapping is not yet supported in single-platform projects", kpmModelMappingEnabled)
|
||||
project.plugins.apply("org.jetbrains.kotlin.js")
|
||||
val kotlin = jsExtension
|
||||
kotlin.js { nodejs() }
|
||||
@@ -181,13 +210,65 @@ class BuildKotlinToolingMetadataTest {
|
||||
|
||||
@Test
|
||||
fun jvm() {
|
||||
Assume.assumeFalse("KPM model mapping is not yet supported in single-platform projects", kpmModelMappingEnabled)
|
||||
project.plugins.apply("org.jetbrains.kotlin.jvm")
|
||||
val metadata = getKotlinToolingMetadata()
|
||||
assertEquals(org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper::class.java.canonicalName, metadata.buildPlugin)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `multiple native targets`() {
|
||||
project.plugins.apply("kotlin-multiplatform")
|
||||
val kotlin = multiplatformExtension
|
||||
kotlin.linuxX64()
|
||||
kotlin.linuxArm64()
|
||||
|
||||
val metadata = getKotlinToolingMetadata()
|
||||
val nativeTargets = metadata.projectTargets.filter { it.platformType == native.name }.sortedBy { it.extras.native?.konanTarget }
|
||||
assertEquals(2, nativeTargets.size, "Expected only two native targets")
|
||||
val (linuxArm64, linuxX64) = nativeTargets
|
||||
|
||||
assertEquals(
|
||||
"linux_arm64",
|
||||
linuxArm64.extras.native?.konanTarget
|
||||
)
|
||||
assertEquals(
|
||||
"linux_x64",
|
||||
linuxX64.extras.native?.konanTarget
|
||||
)
|
||||
|
||||
if (kpmModelMappingEnabled) {
|
||||
assertEquals(
|
||||
KotlinLinuxArm64Variant::class.java.canonicalName,
|
||||
linuxArm64.target
|
||||
)
|
||||
assertEquals(
|
||||
KotlinLinuxX64Variant::class.java.canonicalName,
|
||||
linuxX64.target
|
||||
)
|
||||
} else {
|
||||
assertEquals(
|
||||
KotlinNativeTarget::class.java.canonicalName,
|
||||
linuxArm64.target
|
||||
)
|
||||
assertEquals(
|
||||
KotlinNativeTargetWithHostTests::class.java.canonicalName,
|
||||
linuxX64.target
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getKotlinToolingMetadata(): KotlinToolingMetadata {
|
||||
val task = project.buildKotlinToolingMetadataTask?.get() ?: error("No ${BuildKotlinToolingMetadataTask.defaultTaskName} task")
|
||||
return task.kotlinToolingMetadata
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters(name = "KPM-Model-Mapping:{0}")
|
||||
fun parameters() = listOf(
|
||||
arrayOf(false),
|
||||
arrayOf(true),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -14,6 +14,7 @@ import org.gradle.api.plugins.ExtraPropertiesExtension
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_KPM_EXPERIMENTAL_MODEL_MAPPING
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_DEFAULT_DEPENDENCY
|
||||
@@ -103,6 +104,10 @@ fun Project.enableHierarchicalStructureByDefault(enabled: Boolean = true) {
|
||||
propertiesExtension.set(KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT, enabled.toString())
|
||||
}
|
||||
|
||||
fun Project.enableKpmModelMapping(enabled: Boolean = true) {
|
||||
propertiesExtension.set(KOTLIN_KPM_EXPERIMENTAL_MODEL_MAPPING, enabled.toString())
|
||||
}
|
||||
|
||||
fun Project.enableDefaultStdlibDependency(enabled: Boolean = true) {
|
||||
project.propertiesExtension.set(KOTLIN_STDLIB_DEFAULT_DEPENDENCY, enabled.toString())
|
||||
}
|
||||
|
||||
+90
-2
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.hasKpmModel
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetContainerDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVariantEnabled
|
||||
@@ -62,7 +64,11 @@ abstract class BuildKotlinToolingMetadataTask : DefaultTask() {
|
||||
|
||||
@get:Internal
|
||||
internal val kotlinToolingMetadata by lazy {
|
||||
project.kotlinExtension.getKotlinToolingMetadata()
|
||||
if (project.hasKpmModel) {
|
||||
project.kpmModelContainer.getKotlinToolingMetadata(project)
|
||||
} else {
|
||||
project.kotlinExtension.getKotlinToolingMetadata()
|
||||
}
|
||||
}
|
||||
|
||||
@get:Input
|
||||
@@ -79,6 +85,87 @@ abstract class BuildKotlinToolingMetadataTask : DefaultTask() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun KpmGradleProjectModelContainer.getKotlinToolingMetadata(project: Project): KotlinToolingMetadata {
|
||||
return KotlinToolingMetadata(
|
||||
schemaVersion = KotlinToolingMetadata.currentSchemaVersion,
|
||||
buildSystem = "Gradle",
|
||||
buildSystemVersion = project.gradle.gradleVersion,
|
||||
buildPlugin = project.plugins.withType(KotlinBasePluginWrapper::class.java).joinToString(";") { it.javaClass.canonicalName },
|
||||
buildPluginVersion = project.getKotlinPluginVersion(),
|
||||
projectSettings = project.buildProjectSettings(),
|
||||
projectTargets = buildProjectTargets()
|
||||
)
|
||||
}
|
||||
|
||||
private fun Project.buildProjectSettings(): KotlinToolingMetadata.ProjectSettings {
|
||||
return KotlinToolingMetadata.ProjectSettings(
|
||||
isHmppEnabled = project.isKotlinGranularMetadataEnabled,
|
||||
isCompatibilityMetadataVariantEnabled = project.isCompatibilityMetadataVariantEnabled,
|
||||
isKPMEnabled = project.hasKpmModel
|
||||
)
|
||||
}
|
||||
|
||||
private fun KpmGradleProjectModelContainer.buildProjectTargets(): List<KotlinToolingMetadata.ProjectTargetMetadata> {
|
||||
val result = mutableSetOf<KotlinToolingMetadata.ProjectTargetMetadata>()
|
||||
val mainModules = modules.filter { it.isMain }
|
||||
|
||||
for (module in mainModules) {
|
||||
result += KotlinToolingMetadata.ProjectTargetMetadata(
|
||||
target = module.common.javaClass.canonicalName,
|
||||
platformType = KotlinPlatformType.common.name,
|
||||
extras = KotlinToolingMetadata.ProjectTargetMetadata.Extras()
|
||||
)
|
||||
|
||||
for (variant in module.variants) {
|
||||
result += KotlinToolingMetadata.ProjectTargetMetadata(
|
||||
target = variant.javaClass.canonicalName,
|
||||
platformType = variant.platformType.name,
|
||||
extras = KotlinToolingMetadata.ProjectTargetMetadata.Extras(
|
||||
jvm = variant.jvmExtrasOrNull(),
|
||||
android = variant.androidExtrasOrNull(),
|
||||
js = variant.jsExtrasOrNull(),
|
||||
native = variant.nativeExtrasOrNull()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return result.toList()
|
||||
}
|
||||
|
||||
private fun KotlinGradleVariant.jvmExtrasOrNull() =
|
||||
when (this) {
|
||||
is KotlinJvmVariant -> KotlinToolingMetadata.ProjectTargetMetadata.JvmExtras(
|
||||
jvmTarget = compilationData.kotlinOptions.jvmTarget,
|
||||
withJavaEnabled = false
|
||||
)
|
||||
is LegacyMappedVariant -> buildJvmExtrasOrNull(compilation.target)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun KotlinGradleVariant.androidExtrasOrNull() =
|
||||
when (this) {
|
||||
is LegacyMappedVariant -> buildAndroidExtrasOrNull(compilation.target)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun KotlinGradleVariant.jsExtrasOrNull() =
|
||||
when (this) {
|
||||
is LegacyMappedVariant -> buildJsExtrasOrNull(compilation.target)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun KotlinGradleVariant.nativeExtrasOrNull() =
|
||||
when (this) {
|
||||
is KotlinNativeVariantInternal -> KotlinToolingMetadata.ProjectTargetMetadata.NativeExtras(
|
||||
konanTarget = konanTarget.name,
|
||||
konanVersion = project.konanVersion.toString(),
|
||||
konanAbiVersion = KotlinAbiVersion.CURRENT.toString()
|
||||
)
|
||||
is LegacyMappedVariant -> buildNativeExtrasOrNull(compilation.target)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun KotlinProjectExtension.getKotlinToolingMetadata(): KotlinToolingMetadata {
|
||||
return KotlinToolingMetadata(
|
||||
schemaVersion = KotlinToolingMetadata.currentSchemaVersion,
|
||||
@@ -94,7 +181,8 @@ private fun KotlinProjectExtension.getKotlinToolingMetadata(): KotlinToolingMeta
|
||||
private fun KotlinProjectExtension.buildProjectSettings(): KotlinToolingMetadata.ProjectSettings {
|
||||
return KotlinToolingMetadata.ProjectSettings(
|
||||
isHmppEnabled = project.isKotlinGranularMetadataEnabled,
|
||||
isCompatibilityMetadataVariantEnabled = project.isCompatibilityMetadataVariantEnabled
|
||||
isCompatibilityMetadataVariantEnabled = project.isCompatibilityMetadataVariantEnabled,
|
||||
isKPMEnabled = false
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user