diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy.kt b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy.kt index 1bc77c4562b..91e32f56e22 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy.kt @@ -7,11 +7,60 @@ package org.jetbrains.kotlin.gradle.plugin 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 equals(other: Any?): Boolean { - if (other !is ModuleName) return false + if (other !is SourceSetTree) return false return this.name == other.name } @@ -20,11 +69,34 @@ interface KotlinTargetHierarchy { } companion object { - val main = ModuleName("main") - val test = ModuleName("test") - val unitTest = ModuleName("unitTest") - val integrationTest = ModuleName("integrationTest") - val instrumentedTest = ModuleName("instrumentedTest") + /** + * The 'main' SourceSetTree. Typically, with 'commonMain' as the root SourceSet + */ + val main = SourceSetTree("main") + + /** + * 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") } } } diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchyBuilder.kt b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchyBuilder.kt index 180a5cd3aa5..a5d02d7952a 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchyBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchyBuilder.kt @@ -10,9 +10,9 @@ import org.jetbrains.kotlin.konan.target.DEPRECATED_TARGET_MESSAGE interface KotlinTargetHierarchyBuilder { interface Root : KotlinTargetHierarchyBuilder { - fun modules(vararg module: KotlinTargetHierarchy.ModuleName) - fun withModule(vararg module: KotlinTargetHierarchy.ModuleName) - fun excludeModule(vararg module: KotlinTargetHierarchy.ModuleName) + fun sourceSetTrees(vararg tree: KotlinTargetHierarchy.SourceSetTree) + fun withSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) + fun excludeSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) } /* Declaring groups */ diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchy.ModuleName+orNull.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchy.SourceSetTree+orNull.kt similarity index 69% rename from libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchy.ModuleName+orNull.kt rename to libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchy.SourceSetTree+orNull.kt index 311579fcb86..07163cecd77 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchy.ModuleName+orNull.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchy.SourceSetTree+orNull.kt @@ -6,32 +6,32 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy 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.mpp.KotlinAndroidTarget 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.type -internal suspend fun ModuleName.Companion.orNull(compilation: KotlinCompilation<*>): ModuleName? = +internal suspend fun SourceSetTree.Companion.orNull(compilation: KotlinCompilation<*>): SourceSetTree? = when (compilation) { is KotlinJvmAndroidCompilation -> orNull(compilation.target, compilation.androidVariant.type) else -> when (compilation.name) { "main" -> main "test" -> test - else -> ModuleName(compilation.name) + else -> SourceSetTree(compilation.name) } } -internal suspend fun ModuleName.Companion.orNull( +internal suspend fun SourceSetTree.Companion.orNull( target: KotlinAndroidTarget, variantType: AndroidVariantType -): ModuleName? = when (variantType) { +): SourceSetTree? = when (variantType) { AndroidVariantType.Main -> - target.main.targetHierarchy.module.awaitFinalValue() ?: main + target.main.targetHierarchy.sourceSetTree.awaitFinalValue() ?: main AndroidVariantType.UnitTest -> - target.unitTest.targetHierarchy.module.awaitFinalValue() ?: test + target.unitTest.targetHierarchy.sourceSetTree.awaitFinalValue() ?: test AndroidVariantType.InstrumentedTest -> - target.instrumentedTest.targetHierarchy.module.awaitFinalValue() ?: instrumentedTest + target.instrumentedTest.targetHierarchy.sourceSetTree.awaitFinalValue() ?: instrumentedTest AndroidVariantType.Unknown -> null } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchyBuilderImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchyBuilderImpl.kt index ea94b6c4f33..939d2a41118 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchyBuilderImpl.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchyBuilderImpl.kt @@ -60,16 +60,16 @@ private class KotlinTargetHierarchyBuilderRootImpl( ) : KotlinTargetHierarchyBuilder.Root, KotlinTargetHierarchyBuilder by builder { - override fun modules(vararg module: KotlinTargetHierarchy.ModuleName) { - builder.modules = module.toHashSet() + override fun sourceSetTrees(vararg tree: KotlinTargetHierarchy.SourceSetTree) { + builder.modules = tree.toHashSet() } - override fun withModule(vararg module: KotlinTargetHierarchy.ModuleName) { - builder.modules = builder.modules.orEmpty().plus(module) + override fun withSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) { + builder.modules = builder.modules.orEmpty().plus(tree) } - override fun excludeModule(vararg module: KotlinTargetHierarchy.ModuleName) { - val modules = module.toHashSet() + override fun excludeSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) { + val modules = tree.toHashSet() if (modules.isEmpty()) return builder.modules = builder.modules.orEmpty() - modules } @@ -84,7 +84,7 @@ private class KotlinTargetHierarchyBuilderImpl( val children = mutableSetOf() val childrenClosure get() = closure { it.children } - var modules: Set? = null + var modules: Set? = null private var includePredicate: ((KotlinCompilation<*>) -> Boolean) = { false } private var excludePredicate: ((KotlinCompilation<*>) -> Boolean) = { false } @@ -105,7 +105,7 @@ private class KotlinTargetHierarchyBuilderImpl( suspend fun contains(compilation: KotlinCompilation<*>): Boolean { 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 } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchyTree.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchyTree.kt index 2c1b58cb28f..5fa8293e6b8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchyTree.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/KotlinTargetHierarchyTree.kt @@ -26,8 +26,8 @@ internal data class KotlinTargetHierarchyTree( data class Group(val name: String) : Node() { override suspend fun sharedSourceSetName(compilation: KotlinCompilation<*>): String? { - val moduleName = KotlinTargetHierarchy.ModuleName.orNull(compilation)?.name ?: return null - return lowerCamelCaseName(name, moduleName) + val sourceSetTree = KotlinTargetHierarchy.SourceSetTree.orNull(compilation)?.name ?: return null + return lowerCamelCaseName(name, sourceSetTree) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/defaultKotlinTargetHierarchy.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/defaultKotlinTargetHierarchy.kt index d15c3e4efe2..73b2bfe1c12 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/defaultKotlinTargetHierarchy.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/defaultKotlinTargetHierarchy.kt @@ -5,12 +5,12 @@ 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 internal val defaultKotlinTargetHierarchy = KotlinTargetHierarchyDescriptor { /* natural hierarchy is only applied to default 'main'/'test' compilations (by default) */ - withModule(ModuleName.main, ModuleName.test) + withSourceSetTree(SourceSetTree.main, SourceSetTree.test) common { /* All compilations shall be added to the common group by default */ diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/android/configurator/MultiplatformLayoutV2DependsOnConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/android/configurator/MultiplatformLayoutV2DependsOnConfigurator.kt index 6a21399ed9f..b030851e4b6 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/android/configurator/MultiplatformLayoutV2DependsOnConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/android/configurator/MultiplatformLayoutV2DependsOnConfigurator.kt @@ -38,8 +38,8 @@ internal object MultiplatformLayoutV2DependsOnConfigurator : KotlinAndroidSource return@launchInStage } - val module = KotlinTargetHierarchy.ModuleName.orNull(target, variantType) ?: return@launchInStage - val commonSourceSetName = lowerCamelCaseName("common", module.name) + val sourceSetTree = KotlinTargetHierarchy.SourceSetTree.orNull(target, variantType) ?: return@launchInStage + val commonSourceSetName = lowerCamelCaseName("common", sourceSetTree.name) val commonSourceSet = target.project.kotlinExtension.sourceSets.findByName(commonSourceSetName) ?: return@launchInStage kotlinSourceSet.dependsOn(commonSourceSet) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTargetVariantTypeDsl.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTargetVariantTypeDsl.kt index 489a9afedd2..d7e18a553f7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTargetVariantTypeDsl.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTargetVariantTypeDsl.kt @@ -16,7 +16,10 @@ import org.jetbrains.kotlin.gradle.plugin.newKotlinPluginLifecycleAwareProperty @ExperimentalKotlinGradlePluginApi interface KotlinAndroidTargetVariantTypeDsl { interface TargetHierarchyDsl { - val module: Property + /** + * See [KotlinTargetHierarchy.SourceSetTree] + */ + val sourceSetTree: Property } val targetHierarchy: TargetHierarchyDsl @@ -27,7 +30,8 @@ interface KotlinAndroidTargetVariantTypeDsl { internal class KotlinAndroidTargetVariantTypeDslImpl(private val project: Project) : KotlinAndroidTargetVariantTypeDsl { internal inner class TargetHierarchyDslImpl : KotlinAndroidTargetVariantTypeDsl.TargetHierarchyDsl { - override val module: Property by project.newKotlinPluginLifecycleAwareProperty(FinaliseDsl) + override val sourceSetTree: Property + by project.newKotlinPluginLifecycleAwareProperty(FinaliseDsl) } override val targetHierarchy: KotlinAndroidTargetVariantTypeDsl.TargetHierarchyDsl = TargetHierarchyDslImpl() diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinAndroidTargetVariantTypeDslImplTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinAndroidTargetVariantTypeDslImplTest.kt index cd9c9d01ae9..6dc5bedf853 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinAndroidTargetVariantTypeDslImplTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinAndroidTargetVariantTypeDslImplTest.kt @@ -29,27 +29,27 @@ class KotlinAndroidTargetVariantTypeDslImplTest { @Test fun `test - module - not set`() = project.runLifecycleAwareTest { project.kotlinPluginLifecycle.launch { - assertNull(dsl.targetHierarchy.module.orNull) - assertNull(dsl.targetHierarchy.module.awaitFinalValue()) + assertNull(dsl.targetHierarchy.sourceSetTree.orNull) + assertNull(dsl.targetHierarchy.sourceSetTree.awaitFinalValue()) } } @Test fun `test - module - can be set in users afterEvaluate`() = project.runLifecycleAwareTest { - afterEvaluate { dsl.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("x")) } - dsl.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("-set-before-after-evaluate-")) - assertEquals("x", dsl.targetHierarchy.module.awaitFinalValue()?.name) + afterEvaluate { dsl.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("x")) } + dsl.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("-set-before-after-evaluate-")) + assertEquals("x", dsl.targetHierarchy.sourceSetTree.awaitFinalValue()?.name) assertEquals(KotlinPluginLifecycle.Stage.FinaliseDsl, currentKotlinPluginLifecycle().stage) } @Test fun `test - module - cannot be set after FinaliseDsl`() = project.runLifecycleAwareTest { launchInStage(KotlinPluginLifecycle.Stage.FinaliseDsl.previousOrThrow) { - dsl.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("x")) + dsl.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("x")) } 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 project.runLifecycleAwareTest { kotlin.android { - unitTest.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName.test) - instrumentedTest.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName.test) + unitTest.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test) + instrumentedTest.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test) } AfterFinaliseRefinesEdges.await() @@ -86,13 +86,13 @@ class KotlinAndroidTargetVariantTypeDslImplTest { val kotlin = project.multiplatformExtension project.runLifecycleAwareTest { kotlin.android { - unitTest.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("xxx")) - instrumentedTest.targetHierarchy.module.set(KotlinTargetHierarchy.ModuleName("yyy")) + unitTest.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("xxx")) + instrumentedTest.targetHierarchy.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("yyy")) } kotlin.targetHierarchy.default { - withModule(KotlinTargetHierarchy.ModuleName("xxx")) - withModule(KotlinTargetHierarchy.ModuleName("yyy")) + withSourceSetTree(KotlinTargetHierarchy.SourceSetTree("xxx")) + withSourceSetTree(KotlinTargetHierarchy.SourceSetTree("yyy")) } AfterFinaliseRefinesEdges.await()