[Gradle] Rename KotlinTargetHierarchy.ModuleName to .SourceSetTree

^KT-58209 Verification Pending
This commit is contained in:
Sebastian Sellmair
2023-04-24 16:04:48 +02:00
committed by Space Team
parent 1d23d7de17
commit 16369bc008
9 changed files with 123 additions and 47 deletions
@@ -7,11 +7,60 @@ package org.jetbrains.kotlin.gradle.plugin
interface KotlinTargetHierarchy { interface KotlinTargetHierarchy {
class ModuleName(val name: String) { /**
* When applying any [KotlinTargetHierarchyDescriptor] (e.g. by calling `targetHierarchy.default()`), the descriptor will
* be applied on individual compilations, creating multiple trees of shared SourceSets.
*
* The name of given shared source set within the target hierarchy will be built by
* `lowerCamelCase(nameOfGroup, nameOfSourceSetTree)`
* So for the 'common' group within the 'main' tree the shared SourceSet name will be 'commonMain'
*
* The most default case will create two well known SourceSetTrees:
* - The `main` tree with `commonMain` as its root SourceSet
* - The `test` tree with `commonTest` as its root SourceSet
*
* e.g.
* ```kotlin
* kotlin {
* targetHierarchy.default()
* jvm()
* iosX64()
* iosArm64()
* }
* ```
*
* will create two SourceSetTrees: "main" and "test"
* ```
* "main" "test"
*
* commonMain commonTest
* | |
* | |
* +----------+----------+ +----------+----------+
* | | | |
* ... jvmMain ... jvmTest
* | |
* | |
* iosMain iosTest
* | |
* +----+-----+ +----+-----+
* | | | |
* iosX64Main iosArm64Main iosX64Test iosArm64Test
* ```
*
*
* Usually, the name of the compilation correlates to the name of the SourceSetTree:
* As seen in the previous example, the "main" tree under the "commonMain" root contains all 'main' compilations of the projects
* targets. The "test" tree under the "commonTest" root contains all 'test' compilations of the projects targets.
*
* There are some exceptions, where the name of the compilations cannot be chosen by the user directly (Android)
* In this case, the name of the SourceSet can be configured outside the target hierarchy DSL.
*/
class SourceSetTree(val name: String) {
override fun toString(): String = name override fun toString(): String = name
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (other !is ModuleName) return false if (other !is SourceSetTree) return false
return this.name == other.name return this.name == other.name
} }
@@ -20,11 +69,34 @@ interface KotlinTargetHierarchy {
} }
companion object { companion object {
val main = ModuleName("main") /**
val test = ModuleName("test") * The 'main' SourceSetTree. Typically, with 'commonMain' as the root SourceSet
val unitTest = ModuleName("unitTest") */
val integrationTest = ModuleName("integrationTest") val main = SourceSetTree("main")
val instrumentedTest = ModuleName("instrumentedTest")
/**
* The 'test' SourceSetTree. Typically, with 'commonTest' as the root SourceSet
*/
val test = SourceSetTree("test")
/**
* Special pre-defined SourceSetTree: Can be used to introduce a new tree with 'commonUnitTest' as the root SourceSet
* e.g. relevant for organising Android unitTest compilations/SourceSets
*/
val unitTest = SourceSetTree("unitTest")
/**
* Special pre-defined SourceSetTree: Can be used to introduce a new tree with 'commonInstrumentedTest' as the root SourceSet
* e.g. relevant for organising Android instrumented compilations/SourceSets
*/
val instrumentedTest = SourceSetTree("instrumentedTest")
/**
* Special pre-defined SourceSetTree: Can be used to introduce a new tree with 'commonIntegrationTest' as root SourceSEt
*/
val integrationTest = SourceSetTree("integrationTest")
} }
} }
} }
@@ -10,9 +10,9 @@ import org.jetbrains.kotlin.konan.target.DEPRECATED_TARGET_MESSAGE
interface KotlinTargetHierarchyBuilder { interface KotlinTargetHierarchyBuilder {
interface Root : KotlinTargetHierarchyBuilder { interface Root : KotlinTargetHierarchyBuilder {
fun modules(vararg module: KotlinTargetHierarchy.ModuleName) fun sourceSetTrees(vararg tree: KotlinTargetHierarchy.SourceSetTree)
fun withModule(vararg module: KotlinTargetHierarchy.ModuleName) fun withSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree)
fun excludeModule(vararg module: KotlinTargetHierarchy.ModuleName) fun excludeSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree)
} }
/* Declaring groups */ /* Declaring groups */
@@ -6,32 +6,32 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.ModuleName import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree
import org.jetbrains.kotlin.gradle.plugin.awaitFinalValue import org.jetbrains.kotlin.gradle.plugin.awaitFinalValue
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidVariantType import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidVariantType
import org.jetbrains.kotlin.gradle.plugin.sources.android.type import org.jetbrains.kotlin.gradle.plugin.sources.android.type
internal suspend fun ModuleName.Companion.orNull(compilation: KotlinCompilation<*>): ModuleName? = internal suspend fun SourceSetTree.Companion.orNull(compilation: KotlinCompilation<*>): SourceSetTree? =
when (compilation) { when (compilation) {
is KotlinJvmAndroidCompilation -> orNull(compilation.target, compilation.androidVariant.type) is KotlinJvmAndroidCompilation -> orNull(compilation.target, compilation.androidVariant.type)
else -> when (compilation.name) { else -> when (compilation.name) {
"main" -> main "main" -> main
"test" -> test "test" -> test
else -> ModuleName(compilation.name) else -> SourceSetTree(compilation.name)
} }
} }
internal suspend fun ModuleName.Companion.orNull( internal suspend fun SourceSetTree.Companion.orNull(
target: KotlinAndroidTarget, target: KotlinAndroidTarget,
variantType: AndroidVariantType variantType: AndroidVariantType
): ModuleName? = when (variantType) { ): SourceSetTree? = when (variantType) {
AndroidVariantType.Main -> AndroidVariantType.Main ->
target.main.targetHierarchy.module.awaitFinalValue() ?: main target.main.targetHierarchy.sourceSetTree.awaitFinalValue() ?: main
AndroidVariantType.UnitTest -> AndroidVariantType.UnitTest ->
target.unitTest.targetHierarchy.module.awaitFinalValue() ?: test target.unitTest.targetHierarchy.sourceSetTree.awaitFinalValue() ?: test
AndroidVariantType.InstrumentedTest -> AndroidVariantType.InstrumentedTest ->
target.instrumentedTest.targetHierarchy.module.awaitFinalValue() ?: instrumentedTest target.instrumentedTest.targetHierarchy.sourceSetTree.awaitFinalValue() ?: instrumentedTest
AndroidVariantType.Unknown -> null AndroidVariantType.Unknown -> null
} }
@@ -60,16 +60,16 @@ private class KotlinTargetHierarchyBuilderRootImpl(
) : KotlinTargetHierarchyBuilder.Root, KotlinTargetHierarchyBuilder by builder { ) : KotlinTargetHierarchyBuilder.Root, KotlinTargetHierarchyBuilder by builder {
override fun modules(vararg module: KotlinTargetHierarchy.ModuleName) { override fun sourceSetTrees(vararg tree: KotlinTargetHierarchy.SourceSetTree) {
builder.modules = module.toHashSet() builder.modules = tree.toHashSet()
} }
override fun withModule(vararg module: KotlinTargetHierarchy.ModuleName) { override fun withSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) {
builder.modules = builder.modules.orEmpty().plus(module) builder.modules = builder.modules.orEmpty().plus(tree)
} }
override fun excludeModule(vararg module: KotlinTargetHierarchy.ModuleName) { override fun excludeSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) {
val modules = module.toHashSet() val modules = tree.toHashSet()
if (modules.isEmpty()) return if (modules.isEmpty()) return
builder.modules = builder.modules.orEmpty() - modules builder.modules = builder.modules.orEmpty() - modules
} }
@@ -84,7 +84,7 @@ private class KotlinTargetHierarchyBuilderImpl(
val children = mutableSetOf<KotlinTargetHierarchyBuilderImpl>() val children = mutableSetOf<KotlinTargetHierarchyBuilderImpl>()
val childrenClosure get() = closure { it.children } val childrenClosure get() = closure { it.children }
var modules: Set<KotlinTargetHierarchy.ModuleName>? = null var modules: Set<KotlinTargetHierarchy.SourceSetTree>? = null
private var includePredicate: ((KotlinCompilation<*>) -> Boolean) = { false } private var includePredicate: ((KotlinCompilation<*>) -> Boolean) = { false }
private var excludePredicate: ((KotlinCompilation<*>) -> Boolean) = { false } private var excludePredicate: ((KotlinCompilation<*>) -> Boolean) = { false }
@@ -105,7 +105,7 @@ private class KotlinTargetHierarchyBuilderImpl(
suspend fun contains(compilation: KotlinCompilation<*>): Boolean { suspend fun contains(compilation: KotlinCompilation<*>): Boolean {
modules?.let { modules -> modules?.let { modules ->
val module = KotlinTargetHierarchy.ModuleName.orNull(compilation) ?: return false val module = KotlinTargetHierarchy.SourceSetTree.orNull(compilation) ?: return false
if (module !in modules) return false if (module !in modules) return false
} }
@@ -26,8 +26,8 @@ internal data class KotlinTargetHierarchyTree(
data class Group(val name: String) : Node() { data class Group(val name: String) : Node() {
override suspend fun sharedSourceSetName(compilation: KotlinCompilation<*>): String? { override suspend fun sharedSourceSetName(compilation: KotlinCompilation<*>): String? {
val moduleName = KotlinTargetHierarchy.ModuleName.orNull(compilation)?.name ?: return null val sourceSetTree = KotlinTargetHierarchy.SourceSetTree.orNull(compilation)?.name ?: return null
return lowerCamelCaseName(name, moduleName) return lowerCamelCaseName(name, sourceSetTree)
} }
} }
@@ -5,12 +5,12 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.ModuleName import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchyDescriptor import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchyDescriptor
internal val defaultKotlinTargetHierarchy = KotlinTargetHierarchyDescriptor { internal val defaultKotlinTargetHierarchy = KotlinTargetHierarchyDescriptor {
/* natural hierarchy is only applied to default 'main'/'test' compilations (by default) */ /* natural hierarchy is only applied to default 'main'/'test' compilations (by default) */
withModule(ModuleName.main, ModuleName.test) withSourceSetTree(SourceSetTree.main, SourceSetTree.test)
common { common {
/* All compilations shall be added to the common group by default */ /* All compilations shall be added to the common group by default */
@@ -38,8 +38,8 @@ internal object MultiplatformLayoutV2DependsOnConfigurator : KotlinAndroidSource
return@launchInStage return@launchInStage
} }
val module = KotlinTargetHierarchy.ModuleName.orNull(target, variantType) ?: return@launchInStage val sourceSetTree = KotlinTargetHierarchy.SourceSetTree.orNull(target, variantType) ?: return@launchInStage
val commonSourceSetName = lowerCamelCaseName("common", module.name) val commonSourceSetName = lowerCamelCaseName("common", sourceSetTree.name)
val commonSourceSet = target.project.kotlinExtension.sourceSets.findByName(commonSourceSetName) ?: return@launchInStage val commonSourceSet = target.project.kotlinExtension.sourceSets.findByName(commonSourceSetName) ?: return@launchInStage
kotlinSourceSet.dependsOn(commonSourceSet) kotlinSourceSet.dependsOn(commonSourceSet)
} }
@@ -16,7 +16,10 @@ import org.jetbrains.kotlin.gradle.plugin.newKotlinPluginLifecycleAwareProperty
@ExperimentalKotlinGradlePluginApi @ExperimentalKotlinGradlePluginApi
interface KotlinAndroidTargetVariantTypeDsl { interface KotlinAndroidTargetVariantTypeDsl {
interface TargetHierarchyDsl { interface TargetHierarchyDsl {
val module: Property<KotlinTargetHierarchy.ModuleName> /**
* See [KotlinTargetHierarchy.SourceSetTree]
*/
val sourceSetTree: Property<KotlinTargetHierarchy.SourceSetTree>
} }
val targetHierarchy: TargetHierarchyDsl val targetHierarchy: TargetHierarchyDsl
@@ -27,7 +30,8 @@ interface KotlinAndroidTargetVariantTypeDsl {
internal class KotlinAndroidTargetVariantTypeDslImpl(private val project: Project) : KotlinAndroidTargetVariantTypeDsl { internal class KotlinAndroidTargetVariantTypeDslImpl(private val project: Project) : KotlinAndroidTargetVariantTypeDsl {
internal inner class TargetHierarchyDslImpl : KotlinAndroidTargetVariantTypeDsl.TargetHierarchyDsl { internal inner class TargetHierarchyDslImpl : KotlinAndroidTargetVariantTypeDsl.TargetHierarchyDsl {
override val module: Property<KotlinTargetHierarchy.ModuleName> by project.newKotlinPluginLifecycleAwareProperty(FinaliseDsl) override val sourceSetTree: Property<KotlinTargetHierarchy.SourceSetTree>
by project.newKotlinPluginLifecycleAwareProperty(FinaliseDsl)
} }
override val targetHierarchy: KotlinAndroidTargetVariantTypeDsl.TargetHierarchyDsl = TargetHierarchyDslImpl() override val targetHierarchy: KotlinAndroidTargetVariantTypeDsl.TargetHierarchyDsl = TargetHierarchyDslImpl()
@@ -29,27 +29,27 @@ class KotlinAndroidTargetVariantTypeDslImplTest {
@Test @Test
fun `test - module - not set`() = project.runLifecycleAwareTest { fun `test - module - not set`() = project.runLifecycleAwareTest {
project.kotlinPluginLifecycle.launch { project.kotlinPluginLifecycle.launch {
assertNull(dsl.targetHierarchy.module.orNull) assertNull(dsl.targetHierarchy.sourceSetTree.orNull)
assertNull(dsl.targetHierarchy.module.awaitFinalValue()) assertNull(dsl.targetHierarchy.sourceSetTree.awaitFinalValue())
} }
} }
@Test @Test
fun `test - module - can be set in users afterEvaluate`() = project.runLifecycleAwareTest { fun `test - module - can be set in users afterEvaluate`() = project.runLifecycleAwareTest {
afterEvaluate { dsl.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("x")) } afterEvaluate { dsl.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("x")) }
dsl.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("-set-before-after-evaluate-")) dsl.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("-set-before-after-evaluate-"))
assertEquals("x", dsl.targetHierarchy.module.awaitFinalValue()?.name) assertEquals("x", dsl.targetHierarchy.sourceSetTree.awaitFinalValue()?.name)
assertEquals(KotlinPluginLifecycle.Stage.FinaliseDsl, currentKotlinPluginLifecycle().stage) assertEquals(KotlinPluginLifecycle.Stage.FinaliseDsl, currentKotlinPluginLifecycle().stage)
} }
@Test @Test
fun `test - module - cannot be set after FinaliseDsl`() = project.runLifecycleAwareTest { fun `test - module - cannot be set after FinaliseDsl`() = project.runLifecycleAwareTest {
launchInStage(KotlinPluginLifecycle.Stage.FinaliseDsl.previousOrThrow) { launchInStage(KotlinPluginLifecycle.Stage.FinaliseDsl.previousOrThrow) {
dsl.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("x")) dsl.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("x"))
} }
launchInStage(KotlinPluginLifecycle.Stage.FinaliseDsl) { launchInStage(KotlinPluginLifecycle.Stage.FinaliseDsl) {
assertFails { dsl.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("y")) } assertFails { dsl.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("y")) }
} }
} }
@@ -64,8 +64,8 @@ class KotlinAndroidTargetVariantTypeDslImplTest {
val kotlin = project.multiplatformExtension val kotlin = project.multiplatformExtension
project.runLifecycleAwareTest { project.runLifecycleAwareTest {
kotlin.android { kotlin.android {
unitTest.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName.test) unitTest.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test)
instrumentedTest.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName.test) instrumentedTest.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test)
} }
AfterFinaliseRefinesEdges.await() AfterFinaliseRefinesEdges.await()
@@ -86,13 +86,13 @@ class KotlinAndroidTargetVariantTypeDslImplTest {
val kotlin = project.multiplatformExtension val kotlin = project.multiplatformExtension
project.runLifecycleAwareTest { project.runLifecycleAwareTest {
kotlin.android { kotlin.android {
unitTest.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("xxx")) unitTest.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("xxx"))
instrumentedTest.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("yyy")) instrumentedTest.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("yyy"))
} }
kotlin.targetHierarchy.default { kotlin.targetHierarchy.default {
withModule(KotlinTargetHierarchy.ModuleName("xxx")) withSourceSetTree(KotlinTargetHierarchy.SourceSetTree("xxx"))
withModule(KotlinTargetHierarchy.ModuleName("yyy")) withSourceSetTree(KotlinTargetHierarchy.SourceSetTree("yyy"))
} }
AfterFinaliseRefinesEdges.await() AfterFinaliseRefinesEdges.await()