[Gradle] Reshape API surface for setting Android SourceSetTrees

^KT-58710 Verification Pending
This commit is contained in:
Sebastian Sellmair
2023-05-16 13:22:38 +02:00
committed by Space Team
parent e1d48847dc
commit 2dcaad2d03
6 changed files with 59 additions and 136 deletions
@@ -5,10 +5,8 @@
package org.jetbrains.kotlin.gradle.dsl package org.jetbrains.kotlin.gradle.dsl
import org.gradle.api.provider.Property
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchyBuilder import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchyBuilder
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchyDescriptor import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchyDescriptor
@@ -38,9 +38,9 @@ internal object MultiplatformLayoutV2DependsOnConfigurator : KotlinAndroidSource
} }
val sourceSetTree = when (variantType) { val sourceSetTree = when (variantType) {
AndroidVariantType.Main -> target.targetHierarchy.main.sourceSetTree.awaitFinalValue() AndroidVariantType.Main -> target.mainVariant.sourceSetTree.awaitFinalValue()
AndroidVariantType.UnitTest -> target.targetHierarchy.unitTest.sourceSetTree.awaitFinalValue() AndroidVariantType.UnitTest -> target.unitTestVariant.sourceSetTree.awaitFinalValue()
AndroidVariantType.InstrumentedTest -> target.targetHierarchy.instrumentedTest.sourceSetTree.awaitFinalValue() AndroidVariantType.InstrumentedTest -> target.instrumentedTestVariant.sourceSetTree.awaitFinalValue()
AndroidVariantType.Unknown -> null AndroidVariantType.Unknown -> null
} ?: return@launchInStage } ?: return@launchInStage
@@ -36,110 +36,53 @@ abstract class KotlinAndroidTarget @Inject constructor(
override val compilations: NamedDomainObjectContainer<out KotlinJvmAndroidCompilation> = override val compilations: NamedDomainObjectContainer<out KotlinJvmAndroidCompilation> =
project.container(KotlinJvmAndroidCompilation::class.java) project.container(KotlinJvmAndroidCompilation::class.java)
/**
* Configure Android specific settings within the context of [KotlinTargetHierarchy].
* The difference between Android and other targets is that the build author is free to choose
* the names of compilations, whereas Android is using predefined SourceSet names.
*
* ### Default dependsOn edges
* By default, Kotlin Multiplatform will set the following default dependsOn edges:
* - `androidMain` -> `commonMain`
* - `androidUnitTest` -> `commonTest`
*
* In this default setup, SourceSets like `androidInstrumentedTest` will *not* dependOn `commonTest`.
* This API can be used to change the default behavior
*
* #### Example 1: Setting up androidInstrumentedTest -> commonTest
* This can be done by putting the 'androidInstrumentedTest' variants into the 'test' [SourceSetTree]:
* ```kotlin
* androidTarget().targetHierarchy {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* }
* ```
*
* #### Example 2: Setting up androidInstrumentedTest -> commonTest and removing 'unitTests' from the 'test' [SourceSetTree]
* ```kotlin
* androidTarget().targetHierarchy {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* unitTest.sourceSetTree.set(SourceSetTree.unitTest) // ! <- Anything *other* than 'test'
* }
* ```
*/
@ExperimentalKotlinGradlePluginApi @ExperimentalKotlinGradlePluginApi
val targetHierarchy: KotlinAndroidTargetHierarchyDsl = KotlinAndroidTargetHierarchyDslImpl(project.objects).apply { val mainVariant: KotlinAndroidTargetVariantDsl = KotlinAndroidTargetVariantDslImpl(project.objects).apply {
main.sourceSetTree.convention(SourceSetTree.main) sourceSetTree.convention(SourceSetTree.main)
unitTest.sourceSetTree.convention(SourceSetTree.test)
instrumentedTest.sourceSetTree.convention(SourceSetTree.instrumentedTest)
} }
/**
* Configure Android specific settings within the context of [KotlinTargetHierarchy].
* The difference between Android and other targets is that the build author is free to choose
* the names of compilations, whereas Android is using predefined SourceSet names.
*
* ### Default dependsOn edges
* By default, Kotlin Multiplatform will set the following default dependsOn edges:
* - `androidMain` -> `commonMain`
* - `androidUnitTest` -> `commonTest`
*
* In this default setup, SourceSets like `androidInstrumentedTest` will *not* dependOn `commonTest`.
* This API can be used to change the default behavior
*
* #### Example 1: Setting up androidInstrumentedTest -> commonTest
* This can be done by putting the 'androidInstrumentedTest' variants into the 'test' [SourceSetTree]:
* ```kotlin
* androidTarget().targetHierarchy {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* }
* ```
*
* #### Example 2: Setting up androidInstrumentedTest -> commonTest and removing 'unitTests' from the 'test' [SourceSetTree]
* ```kotlin
* androidTarget().targetHierarchy {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* unitTest.sourceSetTree.set(SourceSetTree.unitTest) // ! <- Anything *other* than 'test'
* }
* ```
*/
@ExperimentalKotlinGradlePluginApi @ExperimentalKotlinGradlePluginApi
fun targetHierarchy(configure: Action<KotlinAndroidTargetHierarchyDsl>) { fun mainVariant(action: Action<KotlinAndroidTargetVariantDsl>) {
configure.execute(targetHierarchy) action.execute(mainVariant)
} }
/**
* Configure Android specific settings within the context of [KotlinTargetHierarchy].
* The difference between Android and other targets is that the build author is free to choose
* the names of compilations, whereas Android is using predefined SourceSet names.
*
* ### Default dependsOn edges
* By default, Kotlin Multiplatform will set the following default dependsOn edges:
* - `androidMain` -> `commonMain`
* - `androidUnitTest` -> `commonTest`
*
* In this default setup, SourceSets like `androidInstrumentedTest` will *not* dependOn `commonTest`.
* This API can be used to change the default behavior
*
* #### Example 1: Setting up androidInstrumentedTest -> commonTest
* This can be done by putting the 'androidInstrumentedTest' variants into the 'test' [SourceSetTree]:
* ```kotlin
* androidTarget().targetHierarchy {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* }
* ```
*
* #### Example 2: Setting up androidInstrumentedTest -> commonTest and removing 'unitTests' from the 'test' [SourceSetTree]
* ```kotlin
* androidTarget().targetHierarchy {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* unitTest.sourceSetTree.set(SourceSetTree.unitTest) // ! <- Anything *other* than 'test'
* }
* ```
*/
@ExperimentalKotlinGradlePluginApi @ExperimentalKotlinGradlePluginApi
fun targetHierarchy(configure: KotlinAndroidTargetHierarchyDsl.() -> Unit) { fun mainVariant(configure: KotlinAndroidTargetVariantDsl.() -> Unit) {
targetHierarchy.configure() mainVariant.configure()
} }
@ExperimentalKotlinGradlePluginApi
val unitTestVariant: KotlinAndroidTargetVariantDsl = KotlinAndroidTargetVariantDslImpl(project.objects).apply {
sourceSetTree.convention(SourceSetTree.test)
}
@ExperimentalKotlinGradlePluginApi
fun unitTestVariant(action: Action<KotlinAndroidTargetVariantDsl>) {
action.execute(unitTestVariant)
}
@ExperimentalKotlinGradlePluginApi
fun unitTestVariant(configure: KotlinAndroidTargetVariantDsl.() -> Unit) {
unitTestVariant.configure()
}
@ExperimentalKotlinGradlePluginApi
val instrumentedTestVariant: KotlinAndroidTargetVariantDsl = KotlinAndroidTargetVariantDslImpl(project.objects).apply {
sourceSetTree.convention(SourceSetTree.instrumentedTest)
}
@ExperimentalKotlinGradlePluginApi
fun instrumentedTestVariant(action: Action<KotlinAndroidTargetVariantDsl>) {
action.execute(instrumentedTestVariant)
}
@ExperimentalKotlinGradlePluginApi
fun instrumentedTestVariant(configure: KotlinAndroidTargetVariantDsl.() -> Unit) {
instrumentedTestVariant.configure()
}
/** Names of the Android library variants that should be published from the target's project within the default publications which are /** Names of the Android library variants that should be published from the target's project within the default publications which are
* set up if the `maven-publish` Gradle plugin is applied. * set up if the `maven-publish` Gradle plugin is applied.
* *
@@ -9,47 +9,30 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.KotlinTargetHierarchyDsl
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree
import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.utils.property
@ExperimentalKotlinGradlePluginApi
interface KotlinAndroidTargetHierarchyDsl {
val main: KotlinAndroidVariantHierarchyDsl
val unitTest: KotlinAndroidVariantHierarchyDsl
val instrumentedTest: KotlinAndroidVariantHierarchyDsl
}
@ExperimentalKotlinGradlePluginApi @ExperimentalKotlinGradlePluginApi
interface KotlinAndroidVariantHierarchyDsl { interface KotlinAndroidTargetVariantDsl {
/** /**
* Configures under which [SourceSetTree] the currently configured Android Variant shall be placed. * Configures under which [SourceSetTree] the currently configured Android Variant shall be placed.
* e.g. * e.g.
* *
* ```kotlin * ```kotlin
* kotlin { * kotlin {
* targetHierarchy.android { * androidTarget().instrumentedTest {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test) * sourceSetTree.set(SourceSetTree.test)
* } * }
* } * }
* ``` * ```
* *
* Will ensure that all android instrumented tests (androidInstrumentedTest, androidInstrumentedTestDebug, ...) * Will ensure that all android instrumented tests (androidInstrumentedTest, androidInstrumentedTestDebug, ...)
* will be placed into the 'test' SourceSet tree (with 'commonTest' as root) * will be placed into the 'test' SourceSet tree (with 'commonTest' as root)
*
* See [KotlinTargetHierarchyDsl.android]
*/ */
val sourceSetTree: Property<SourceSetTree> val sourceSetTree: Property<SourceSetTree>
} }
internal class KotlinAndroidTargetHierarchyDslImpl(objects: ObjectFactory) : KotlinAndroidTargetHierarchyDsl { internal class KotlinAndroidTargetVariantDslImpl(objects: ObjectFactory) : KotlinAndroidTargetVariantDsl {
override val main: KotlinAndroidVariantHierarchyDsl = KotlinAndroidVariantHierarchyDslImpl(objects)
override val unitTest: KotlinAndroidVariantHierarchyDsl = KotlinAndroidVariantHierarchyDslImpl(objects)
override val instrumentedTest: KotlinAndroidVariantHierarchyDsl = KotlinAndroidVariantHierarchyDslImpl(objects)
}
internal class KotlinAndroidVariantHierarchyDslImpl(objects: ObjectFactory) : KotlinAndroidVariantHierarchyDsl {
override val sourceSetTree: Property<SourceSetTree> = objects.property() override val sourceSetTree: Property<SourceSetTree> = objects.property()
} }
@@ -46,9 +46,9 @@ class KotlinJvmAndroidCompilationFactory internal constructor(
private fun configureSourceSetTreeClassifier(compilation: KotlinJvmAndroidCompilation) { private fun configureSourceSetTreeClassifier(compilation: KotlinJvmAndroidCompilation) {
compilation.sourceSetTreeClassifier = when (variant.type) { compilation.sourceSetTreeClassifier = when (variant.type) {
AndroidVariantType.Main -> Property(target.targetHierarchy.main.sourceSetTree) AndroidVariantType.Main -> Property(target.mainVariant.sourceSetTree)
AndroidVariantType.UnitTest -> Property(target.targetHierarchy.unitTest.sourceSetTree) AndroidVariantType.UnitTest -> Property(target.unitTestVariant.sourceSetTree)
AndroidVariantType.InstrumentedTest -> Property(target.targetHierarchy.instrumentedTest.sourceSetTree) AndroidVariantType.InstrumentedTest -> Property(target.instrumentedTestVariant.sourceSetTree)
AndroidVariantType.Unknown -> SourceSetTreeClassifier.None AndroidVariantType.Unknown -> SourceSetTreeClassifier.None
} }
} }
@@ -15,17 +15,16 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinal
import org.jetbrains.kotlin.gradle.plugin.awaitFinalValue import org.jetbrains.kotlin.gradle.plugin.awaitFinalValue
import org.jetbrains.kotlin.gradle.plugin.currentKotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.currentKotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.kotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.kotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidVariantHierarchyDslImpl import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTargetVariantDslImpl
import org.jetbrains.kotlin.gradle.util.* import org.jetbrains.kotlin.gradle.util.*
import org.junit.Test import org.junit.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFails
class KotlinAndroidTargetHierarchyDsl { class KotlinAndroidTargetHierarchyDsl {
@Test @Test
fun `test - module - not set`() = buildProjectWithMPP().runLifecycleAwareTest { fun `test - module - not set`() = buildProjectWithMPP().runLifecycleAwareTest {
val dsl = KotlinAndroidVariantHierarchyDslImpl(project.objects) val dsl = KotlinAndroidTargetVariantDslImpl(project.objects)
project.kotlinPluginLifecycle.launch { project.kotlinPluginLifecycle.launch {
assertNull(dsl.sourceSetTree.orNull) assertNull(dsl.sourceSetTree.orNull)
assertNull(dsl.sourceSetTree.awaitFinalValue()) assertNull(dsl.sourceSetTree.awaitFinalValue())
@@ -34,7 +33,7 @@ class KotlinAndroidTargetHierarchyDsl {
@Test @Test
fun `test - module - can be set in users afterEvaluate`() = buildProjectWithMPP().runLifecycleAwareTest { fun `test - module - can be set in users afterEvaluate`() = buildProjectWithMPP().runLifecycleAwareTest {
val dsl = KotlinAndroidVariantHierarchyDslImpl(project.objects) val dsl = KotlinAndroidTargetVariantDslImpl(project.objects)
afterEvaluate { dsl.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("x")) } afterEvaluate { dsl.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("x")) }
dsl.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("-set-before-after-evaluate-")) dsl.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("-set-before-after-evaluate-"))
assertEquals("x", dsl.sourceSetTree.awaitFinalValue()?.name) assertEquals("x", dsl.sourceSetTree.awaitFinalValue()?.name)
@@ -51,9 +50,9 @@ class KotlinAndroidTargetHierarchyDsl {
val kotlin = project.multiplatformExtension val kotlin = project.multiplatformExtension
project.runLifecycleAwareTest { project.runLifecycleAwareTest {
kotlin.androidTarget().targetHierarchy { kotlin.androidTarget {
unitTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test) unitTestVariant.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test)
instrumentedTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test) instrumentedTestVariant.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test)
} }
AfterFinaliseRefinesEdges.await() AfterFinaliseRefinesEdges.await()
@@ -73,9 +72,9 @@ class KotlinAndroidTargetHierarchyDsl {
val kotlin = project.multiplatformExtension val kotlin = project.multiplatformExtension
project.runLifecycleAwareTest { project.runLifecycleAwareTest {
kotlin.androidTarget().targetHierarchy { kotlin.androidTarget {
unitTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("xxx")) unitTestVariant.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("xxx"))
instrumentedTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("yyy")) instrumentedTestVariant.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("yyy"))
} }
kotlin.targetHierarchy.default { kotlin.targetHierarchy.default {