[Gradle] Implement SourceSetTreeClassifier API

- This new API will be configurable for 'External Kotlin Targets'
- This change also moves targetHierarchy.android {} into the androidTarget
to avoid potential confusion around the KGP managed AndroidTarget vs
the Google implementation.

KT-58710
This commit is contained in:
Sebastian Sellmair
2023-05-16 11:52:10 +02:00
committed by Space Team
parent dbfa8d4c29
commit ff7e4f7986
17 changed files with 501 additions and 200 deletions
@@ -142,16 +142,6 @@ public abstract interface class org/jetbrains/kotlin/gradle/dsl/KaptJavacOption
public abstract fun option (Ljava/lang/Object;Ljava/lang/Object;)V public abstract fun option (Ljava/lang/Object;Ljava/lang/Object;)V
} }
public abstract interface class org/jetbrains/kotlin/gradle/dsl/KotlinAndroidTargetHierarchyDsl {
public abstract fun getInstrumentedTest ()Lorg/jetbrains/kotlin/gradle/dsl/KotlinAndroidVariantHierarchyDsl;
public abstract fun getMain ()Lorg/jetbrains/kotlin/gradle/dsl/KotlinAndroidVariantHierarchyDsl;
public abstract fun getUnitTest ()Lorg/jetbrains/kotlin/gradle/dsl/KotlinAndroidVariantHierarchyDsl;
}
public abstract interface class org/jetbrains/kotlin/gradle/dsl/KotlinAndroidVariantHierarchyDsl {
public abstract fun getSourceSetTree ()Lorg/gradle/api/provider/Property;
}
public abstract interface class org/jetbrains/kotlin/gradle/dsl/KotlinArtifact : org/gradle/api/Named, org/gradle/api/plugins/ExtensionAware { public abstract interface class org/jetbrains/kotlin/gradle/dsl/KotlinArtifact : org/gradle/api/Named, org/gradle/api/plugins/ExtensionAware {
public abstract fun getArtifactName ()Ljava/lang/String; public abstract fun getArtifactName ()Ljava/lang/String;
public abstract fun getModules ()Ljava/util/Set; public abstract fun getModules ()Ljava/util/Set;
@@ -530,11 +520,9 @@ public abstract interface class org/jetbrains/kotlin/gradle/dsl/KotlinNativeXCFr
} }
public abstract interface class org/jetbrains/kotlin/gradle/dsl/KotlinTargetHierarchyDsl { public abstract interface class org/jetbrains/kotlin/gradle/dsl/KotlinTargetHierarchyDsl {
public abstract fun android (Lkotlin/jvm/functions/Function1;)V
public abstract fun apply (Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchyDescriptor;Lkotlin/jvm/functions/Function1;)V public abstract fun apply (Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchyDescriptor;Lkotlin/jvm/functions/Function1;)V
public abstract fun custom (Lkotlin/jvm/functions/Function1;)V public abstract fun custom (Lkotlin/jvm/functions/Function1;)V
public abstract fun default (Lkotlin/jvm/functions/Function1;)V public abstract fun default (Lkotlin/jvm/functions/Function1;)V
public abstract fun getAndroid ()Lorg/jetbrains/kotlin/gradle/dsl/KotlinAndroidTargetHierarchyDsl;
} }
public final class org/jetbrains/kotlin/gradle/dsl/KotlinTargetHierarchyDsl$DefaultImpls { public final class org/jetbrains/kotlin/gradle/dsl/KotlinTargetHierarchyDsl$DefaultImpls {
@@ -1105,6 +1093,7 @@ public abstract interface class org/jetbrains/kotlin/gradle/plugin/KotlinTargetH
public abstract fun withAndroidNativeArm64 ()V public abstract fun withAndroidNativeArm64 ()V
public abstract fun withAndroidNativeX64 ()V public abstract fun withAndroidNativeX64 ()V
public abstract fun withAndroidNativeX86 ()V public abstract fun withAndroidNativeX86 ()V
public abstract fun withAndroidTarget ()V
public abstract fun withApple ()V public abstract fun withApple ()V
public abstract fun withCompilations (Lkotlin/jvm/functions/Function1;)V public abstract fun withCompilations (Lkotlin/jvm/functions/Function1;)V
public abstract fun withIos ()V public abstract fun withIos ()V
@@ -170,72 +170,4 @@ interface KotlinTargetHierarchyDsl {
* ``` * ```
*/ */
fun custom(describe: KotlinTargetHierarchyBuilder.Root.() -> Unit) fun custom(describe: KotlinTargetHierarchyBuilder.Root.() -> Unit)
/**
* 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
* targetHierarchy.android {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* }
* ```
*
* #### Example 2: Setting up androidInstrumentedTest -> commonTest and removing 'unitTests' from the 'test' [SourceSetTree]
* ```kotlin
* targetHierarchy.android {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* unitTest.sourceSetTree.set(SourceSetTree.unitTest) // ! <- Anything *other* than 'test'
* }
* ```
*/
@ExperimentalKotlinGradlePluginApi
fun android(configure: KotlinAndroidTargetHierarchyDsl.() -> Unit)
/**
* See [android]
*/
@ExperimentalKotlinGradlePluginApi
val android: KotlinAndroidTargetHierarchyDsl
}
@ExperimentalKotlinGradlePluginApi
interface KotlinAndroidTargetHierarchyDsl {
val main: KotlinAndroidVariantHierarchyDsl
val unitTest: KotlinAndroidVariantHierarchyDsl
val instrumentedTest: KotlinAndroidVariantHierarchyDsl
}
@ExperimentalKotlinGradlePluginApi
interface KotlinAndroidVariantHierarchyDsl {
/**
* Configures under which [SourceSetTree] the currently configured Android Variant shall be placed.
* e.g.
*
* ```kotlin
* kotlin {
* targetHierarchy.android {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* }
* }
* ```
*
* Will ensure that all android instrumented tests (androidInstrumentedTest, androidInstrumentedTestDebug, ...)
* will be placed into the 'test' SourceSet tree (with 'commonTest' as root)
*
* See [KotlinTargetHierarchyDsl.android]
*/
val sourceSetTree: Property<SourceSetTree>
} }
@@ -231,6 +231,7 @@ public abstract interface class org/jetbrains/kotlin/gradle/plugin/mpp/external/
public abstract fun getConfigure ()Lkotlin/jvm/functions/Function1; public abstract fun getConfigure ()Lkotlin/jvm/functions/Function1;
public abstract fun getDefaultSourceSet ()Lorg/jetbrains/kotlin/gradle/plugin/KotlinSourceSet; public abstract fun getDefaultSourceSet ()Lorg/jetbrains/kotlin/gradle/plugin/KotlinSourceSet;
public abstract fun getFriendArtifactResolver ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$FriendArtifactResolver; public abstract fun getFriendArtifactResolver ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$FriendArtifactResolver;
public abstract fun getSourceSetTreeClassifier ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier;
} }
public abstract interface class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$CompilationAssociator { public abstract interface class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$CompilationAssociator {
@@ -254,6 +255,7 @@ public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotli
public final fun getCompileTaskName ()Ljava/lang/String; public final fun getCompileTaskName ()Ljava/lang/String;
public final fun getDefaultSourceSet ()Lorg/jetbrains/kotlin/gradle/plugin/KotlinSourceSet; public final fun getDefaultSourceSet ()Lorg/jetbrains/kotlin/gradle/plugin/KotlinSourceSet;
public final fun getFriendArtifactResolver ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$FriendArtifactResolver; public final fun getFriendArtifactResolver ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$FriendArtifactResolver;
public final fun getSourceSetTreeClassifier ()Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier;
public final fun setCompilationAssociator (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$CompilationAssociator;)V public final fun setCompilationAssociator (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$CompilationAssociator;)V
public final fun setCompilationFactory (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$CompilationFactory;)V public final fun setCompilationFactory (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$CompilationFactory;)V
public final fun setCompilationName (Ljava/lang/String;)V public final fun setCompilationName (Ljava/lang/String;)V
@@ -261,6 +263,7 @@ public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotli
public final fun setCompileTaskName (Ljava/lang/String;)V public final fun setCompileTaskName (Ljava/lang/String;)V
public final fun setDefaultSourceSet (Lorg/jetbrains/kotlin/gradle/plugin/KotlinSourceSet;)V public final fun setDefaultSourceSet (Lorg/jetbrains/kotlin/gradle/plugin/KotlinSourceSet;)V
public final fun setFriendArtifactResolver (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$FriendArtifactResolver;)V public final fun setFriendArtifactResolver (Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptor$FriendArtifactResolver;)V
public final fun setSourceSetTreeClassifier (Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier;)V
} }
public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptorKt { public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinCompilationDescriptorKt {
@@ -312,3 +315,44 @@ public final class org/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotli
public static final fun ExternalKotlinTargetDescriptor (Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor; public static final fun ExternalKotlinTargetDescriptor (Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlin/gradle/plugin/mpp/external/ExternalKotlinTargetDescriptor;
} }
public abstract class org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier {
}
public final class org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Default : org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier {
public static final field INSTANCE Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Default;
public fun toString ()Ljava/lang/String;
}
public final class org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Name : org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier {
public fun <init> (Ljava/lang/String;)V
public final fun component1 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;)Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Name;
public static synthetic fun copy$default (Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Name;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Name;
public fun equals (Ljava/lang/Object;)Z
public final fun getName ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final class org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$None : org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier {
public static final field INSTANCE Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$None;
public fun toString ()Ljava/lang/String;
}
public final class org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Property : org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier {
public fun <init> (Lorg/gradle/api/provider/Property;)V
public final fun getProperty ()Lorg/gradle/api/provider/Property;
public fun toString ()Ljava/lang/String;
}
public final class org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Value : org/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier {
public fun <init> (Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy$SourceSetTree;)V
public final fun component1 ()Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy$SourceSetTree;
public final fun copy (Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy$SourceSetTree;)Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Value;
public static synthetic fun copy$default (Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Value;Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy$SourceSetTree;ILjava/lang/Object;)Lorg/jetbrains/kotlin/gradle/plugin/mpp/targetHierarchy/SourceSetTreeClassifier$Value;
public fun equals (Ljava/lang/Object;)Z
public final fun getTree ()Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetHierarchy$SourceSetTree;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
@@ -53,7 +53,7 @@ abstract class KotlinMultiplatformExtension(project: Project) :
} }
internal val internalKotlinTargetHierarchy by lazy { internal val internalKotlinTargetHierarchy by lazy {
KotlinTargetHierarchyDslImpl(project.objects, targets, sourceSets) KotlinTargetHierarchyDslImpl(targets, sourceSets)
} }
@ExperimentalKotlinGradlePluginApi @ExperimentalKotlinGradlePluginApi
@@ -76,13 +76,13 @@ abstract class KotlinMultiplatformExtension(project: Project) :
fun <T : KotlinTarget> targetFromPreset( fun <T : KotlinTarget> targetFromPreset(
preset: KotlinTargetPreset<T>, preset: KotlinTargetPreset<T>,
name: String = preset.name, name: String = preset.name,
configure: T.() -> Unit = { } configure: T.() -> Unit = { },
): T = configureOrCreate(name, preset, configure) ): T = configureOrCreate(name, preset, configure)
fun <T : KotlinTarget> targetFromPreset( fun <T : KotlinTarget> targetFromPreset(
preset: KotlinTargetPreset<T>, preset: KotlinTargetPreset<T>,
name: String, name: String,
configure: Action<T> configure: Action<T>,
) = targetFromPreset(preset, name) { configure.execute(this) } ) = targetFromPreset(preset, name) { configure.execute(this) }
fun <T : KotlinTarget> targetFromPreset(preset: KotlinTargetPreset<T>) = targetFromPreset(preset, preset.name) { } fun <T : KotlinTarget> targetFromPreset(preset: KotlinTargetPreset<T>) = targetFromPreset(preset, preset.name) { }
@@ -100,37 +100,37 @@ interface TargetsFromPresetExtension : NamedDomainObjectCollection<KotlinTarget>
fun <T : KotlinTarget> fromPreset( fun <T : KotlinTarget> fromPreset(
preset: KotlinTargetPreset<T>, preset: KotlinTargetPreset<T>,
name: String, name: String,
configureAction: T.() -> Unit = {} configureAction: T.() -> Unit = {},
): T ): T
fun <T : KotlinTarget> fromPreset( fun <T : KotlinTarget> fromPreset(
preset: KotlinTargetPreset<T>, preset: KotlinTargetPreset<T>,
name: String name: String,
): T = fromPreset(preset, name, {}) ): T = fromPreset(preset, name, {})
fun <T : KotlinTarget> fromPreset( fun <T : KotlinTarget> fromPreset(
preset: KotlinTargetPreset<T>, preset: KotlinTargetPreset<T>,
name: String, name: String,
configureAction: Action<T> configureAction: Action<T>,
): T ): T
} }
internal abstract class DefaultTargetsFromPresetExtension @Inject constructor( internal abstract class DefaultTargetsFromPresetExtension @Inject constructor(
private val targetsContainer: () -> KotlinTargetsContainerWithPresets, private val targetsContainer: () -> KotlinTargetsContainerWithPresets,
val targets: NamedDomainObjectCollection<KotlinTarget> val targets: NamedDomainObjectCollection<KotlinTarget>,
) : TargetsFromPresetExtension, ) : TargetsFromPresetExtension,
NamedDomainObjectCollection<KotlinTarget> by targets { NamedDomainObjectCollection<KotlinTarget> by targets {
override fun <T : KotlinTarget> fromPreset( override fun <T : KotlinTarget> fromPreset(
preset: KotlinTargetPreset<T>, preset: KotlinTargetPreset<T>,
name: String, name: String,
configureAction: T.() -> Unit configureAction: T.() -> Unit,
): T = targetsContainer().configureOrCreate(name, preset, configureAction) ): T = targetsContainer().configureOrCreate(name, preset, configureAction)
override fun <T : KotlinTarget> fromPreset( override fun <T : KotlinTarget> fromPreset(
preset: KotlinTargetPreset<T>, preset: KotlinTargetPreset<T>,
name: String, name: String,
configureAction: Action<T> configureAction: Action<T>,
) = fromPreset(preset, name) { ) = fromPreset(preset, name) {
configureAction.execute(this) configureAction.execute(this)
} }
@@ -142,7 +142,7 @@ internal fun KotlinTarget.isProducedFromPreset(kotlinTargetPreset: KotlinTargetP
internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCreate( internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCreate(
targetName: String, targetName: String,
targetPreset: KotlinTargetPreset<T>, targetPreset: KotlinTargetPreset<T>,
configure: T.() -> Unit configure: T.() -> Unit,
): T { ): T {
val existingTarget = targets.findByName(targetName) val existingTarget = targets.findByName(targetName)
when { when {
@@ -172,7 +172,7 @@ internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCre
internal fun KotlinTargetsContainerWithPresets.configureOrCreateAndroidTargetAndReportDeprecation( internal fun KotlinTargetsContainerWithPresets.configureOrCreateAndroidTargetAndReportDeprecation(
targetName: String, targetName: String,
configure: KotlinAndroidTarget.() -> Unit configure: KotlinAndroidTarget.() -> Unit,
): KotlinAndroidTarget { ): KotlinAndroidTarget {
val targetPreset = presets.getByName("android") as KotlinAndroidTargetPreset val targetPreset = presets.getByName("android") as KotlinAndroidTargetPreset
val result = configureOrCreate(targetName, targetPreset, configure) val result = configureOrCreate(targetName, targetPreset, configure)
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.Companio
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.addBuildListenerForXcode import org.jetbrains.kotlin.gradle.plugin.mpp.apple.addBuildListenerForXcode
import org.jetbrains.kotlin.gradle.plugin.mpp.internal.runDeprecationDiagnostics import org.jetbrains.kotlin.gradle.plugin.mpp.internal.runDeprecationDiagnostics
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.orNull
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.sources.checkSourceSetVisibilityRequirements import org.jetbrains.kotlin.gradle.plugin.sources.checkSourceSetVisibilityRequirements
import org.jetbrains.kotlin.gradle.plugin.sources.internal import org.jetbrains.kotlin.gradle.plugin.sources.internal
@@ -85,7 +86,7 @@ class KotlinMultiplatformPlugin : Plugin<Project> {
} }
private fun exportProjectStructureMetadataForOtherBuilds( private fun exportProjectStructureMetadataForOtherBuilds(
extension: KotlinMultiplatformExtension extension: KotlinMultiplatformExtension,
) { ) {
GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(extension.project) { GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(extension.project) {
extension.kotlinProjectStructureMetadata extension.kotlinProjectStructureMetadata
@@ -168,22 +169,24 @@ class KotlinMultiplatformPlugin : Plugin<Project> {
private fun configureSourceSets(project: Project) = with(project.multiplatformExtension) { private fun configureSourceSets(project: Project) = with(project.multiplatformExtension) {
val production = sourceSets.create(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) /* Create 'commonMain' and 'commonTest' SourceSets */
val test = sourceSets.create(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) sourceSets.create(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
sourceSets.create(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME)
/* Create default 'dependsOn' to commonMain/commonTest (or even common{SourceSetTree}) */
targets.all { target -> targets.all { target ->
project.launchInStage(KotlinPluginLifecycle.Stage.FinaliseRefinesEdges) { project.launchInStage(KotlinPluginLifecycle.Stage.FinaliseRefinesEdges) {
/* Only setup default refines edges when no KotlinTargetHierarchy was applied */ /* Only setup default refines edges when no KotlinTargetHierarchy was applied */
if (project.multiplatformExtension.internalKotlinTargetHierarchy.appliedDescriptors.isNotEmpty()) return@launchInStage if (project.multiplatformExtension.internalKotlinTargetHierarchy.appliedDescriptors.isNotEmpty()) return@launchInStage
target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)?.let { mainCompilation -> target.compilations.forEach { compilation ->
mainCompilation.defaultSourceSet.takeIf { it != production }?.dependsOn(production) val sourceSetTree = KotlinTargetHierarchy.SourceSetTree.orNull(compilation) ?: return@forEach
} val commonSourceSet = sourceSets.findByName(lowerCamelCaseName("common", sourceSetTree.name)) ?: return@forEach
compilation.defaultSourceSet.dependsOn(commonSourceSet)
target.compilations.findByName(KotlinCompilation.TEST_COMPILATION_NAME)?.let { testCompilation ->
testCompilation.defaultSourceSet.takeIf { it != test }?.dependsOn(test)
} }
} }
/* Report the platform to tbe build stats service */
val targetName = if (target is KotlinNativeTarget) val targetName = if (target is KotlinNativeTarget)
target.konanTarget.name target.konanTarget.name
else else
@@ -277,7 +280,7 @@ private fun sourcesJarTask(
project: Project, project: Project,
sourceSets: Future<Map<String, Iterable<File>>>, sourceSets: Future<Map<String, Iterable<File>>>,
taskNamePrefix: String, taskNamePrefix: String,
artifactNameAppendix: String artifactNameAppendix: String,
): TaskProvider<Jar> = ): TaskProvider<Jar> =
sourcesJarTaskNamed(lowerCamelCaseName(taskNamePrefix, "sourcesJar"), taskNamePrefix, project, sourceSets, artifactNameAppendix) sourcesJarTaskNamed(lowerCamelCaseName(taskNamePrefix, "sourcesJar"), taskNamePrefix, project, sourceSets, artifactNameAppendix)
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.DecoratedKotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.DecoratedKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinCompilationDescriptor.* import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinCompilationDescriptor.*
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.SourceSetTreeClassifier
import kotlin.properties.Delegates import kotlin.properties.Delegates
/** /**
@@ -54,6 +55,7 @@ interface ExternalKotlinCompilationDescriptor<T : DecoratedExternalKotlinCompila
val compilationFactory: CompilationFactory<T> val compilationFactory: CompilationFactory<T>
val friendArtifactResolver: FriendArtifactResolver<T>? val friendArtifactResolver: FriendArtifactResolver<T>?
val compilationAssociator: CompilationAssociator<T>? val compilationAssociator: CompilationAssociator<T>?
val sourceSetTreeClassifier: SourceSetTreeClassifier
val configure: ((T) -> Unit)? val configure: ((T) -> Unit)?
} }
@@ -70,6 +72,7 @@ fun <T : DecoratedExternalKotlinCompilation> ExternalKotlinCompilationDescriptor
compilationFactory = compilationFactory, compilationFactory = compilationFactory,
friendArtifactResolver = friendArtifactResolver, friendArtifactResolver = friendArtifactResolver,
compilationAssociator = compilationAssociator, compilationAssociator = compilationAssociator,
sourceSetTreeClassifier = sourceSetTreeClassifier,
configure = this.configure configure = this.configure
) )
} }
@@ -84,6 +87,8 @@ class ExternalKotlinCompilationDescriptorBuilder<T : DecoratedExternalKotlinComp
var compilationFactory: CompilationFactory<T> by Delegates.notNull() var compilationFactory: CompilationFactory<T> by Delegates.notNull()
var friendArtifactResolver: FriendArtifactResolver<T>? = null var friendArtifactResolver: FriendArtifactResolver<T>? = null
var compilationAssociator: CompilationAssociator<T>? = null var compilationAssociator: CompilationAssociator<T>? = null
var sourceSetTreeClassifier: SourceSetTreeClassifier = SourceSetTreeClassifier.Default
internal var configure: ((T) -> Unit)? = null internal var configure: ((T) -> Unit)? = null
fun configure(action: (T) -> Unit) = apply { fun configure(action: (T) -> Unit) = apply {
@@ -101,5 +106,6 @@ private data class ExternalKotlinCompilationDescriptorImpl<T : DecoratedExternal
override val compilationFactory: CompilationFactory<T>, override val compilationFactory: CompilationFactory<T>,
override val friendArtifactResolver: FriendArtifactResolver<T>?, override val friendArtifactResolver: FriendArtifactResolver<T>?,
override val compilationAssociator: CompilationAssociator<T>?, override val compilationAssociator: CompilationAssociator<T>?,
override val sourceSetTreeClassifier: SourceSetTreeClassifier,
override val configure: ((T) -> Unit)?, override val configure: ((T) -> Unit)?,
) : ExternalKotlinCompilationDescriptor<T> ) : ExternalKotlinCompilationDescriptor<T>
@@ -12,9 +12,9 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompi
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationAssociator import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationAssociator
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetsContainer import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSourceSetsContainer
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.* import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.*
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory.KotlinCompilationTaskNamesContainerFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.decoratedInstance import org.jetbrains.kotlin.gradle.plugin.mpp.decoratedInstance
import org.jetbrains.kotlin.gradle.plugin.mpp.external.DecoratedExternalKotlinCompilation.Delegate import org.jetbrains.kotlin.gradle.plugin.mpp.external.DecoratedExternalKotlinCompilation.Delegate
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.sourceSetTreeClassifier
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
/** /**
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
*/ */
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
fun <T : DecoratedExternalKotlinCompilation> DecoratedExternalKotlinTarget.createCompilation( fun <T : DecoratedExternalKotlinCompilation> DecoratedExternalKotlinTarget.createCompilation(
descriptor: ExternalKotlinCompilationDescriptor<T> descriptor: ExternalKotlinCompilationDescriptor<T>,
): T { ): T {
val compilationImplFactory = KotlinCompilationImplFactory( val compilationImplFactory = KotlinCompilationImplFactory(
compilerOptionsFactory = when (platformType) { compilerOptionsFactory = when (platformType) {
@@ -42,7 +42,7 @@ fun <T : DecoratedExternalKotlinCompilation> DecoratedExternalKotlinTarget.creat
KotlinPlatformType.wasm -> KotlinMultiplatformCommonCompilerOptionsFactory KotlinPlatformType.wasm -> KotlinMultiplatformCommonCompilerOptionsFactory
}, },
compilationSourceSetsContainerFactory = { _, _ -> KotlinCompilationSourceSetsContainer(descriptor.defaultSourceSet) }, compilationSourceSetsContainerFactory = { _, _ -> KotlinCompilationSourceSetsContainer(descriptor.defaultSourceSet) },
compilationTaskNamesContainerFactory = KotlinCompilationTaskNamesContainerFactory { target, compilationName -> compilationTaskNamesContainerFactory = { target, compilationName ->
val default = DefaultKotlinCompilationTaskNamesContainerFactory.create(target, compilationName) val default = DefaultKotlinCompilationTaskNamesContainerFactory.create(target, compilationName)
default.copy( default.copy(
compileTaskName = descriptor.compileTaskName ?: default.compileTaskName, compileTaskName = descriptor.compileTaskName ?: default.compileTaskName,
@@ -70,6 +70,7 @@ fun <T : DecoratedExternalKotlinCompilation> DecoratedExternalKotlinTarget.creat
val compilationImpl = compilationImplFactory.create(this, descriptor.compilationName) val compilationImpl = compilationImplFactory.create(this, descriptor.compilationName)
val decoratedCompilation = descriptor.compilationFactory.create(Delegate(compilationImpl)) val decoratedCompilation = descriptor.compilationFactory.create(Delegate(compilationImpl))
decoratedCompilation.sourceSetTreeClassifier = descriptor.sourceSetTreeClassifier
descriptor.configure?.invoke(decoratedCompilation) descriptor.configure?.invoke(decoratedCompilation)
this.delegate.compilations.add(decoratedCompilation) this.delegate.compilations.add(decoratedCompilation)
@@ -83,13 +84,13 @@ fun <T : DecoratedExternalKotlinCompilation> DecoratedExternalKotlinTarget.creat
*/ */
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
fun <T : DecoratedExternalKotlinCompilation> DecoratedExternalKotlinTarget.createCompilation( fun <T : DecoratedExternalKotlinCompilation> DecoratedExternalKotlinTarget.createCompilation(
descriptor: ExternalKotlinCompilationDescriptorBuilder<T>.() -> Unit descriptor: ExternalKotlinCompilationDescriptorBuilder<T>.() -> Unit,
): T { ): T {
return createCompilation(ExternalKotlinCompilationDescriptor(descriptor)) return createCompilation(ExternalKotlinCompilationDescriptor(descriptor))
} }
private fun DecoratedExternalKotlinTarget.setupCompileTask( private fun DecoratedExternalKotlinTarget.setupCompileTask(
compilation: DecoratedExternalKotlinCompilation compilation: DecoratedExternalKotlinCompilation,
) { ) {
val tasksProvider = KotlinTasksProvider() val tasksProvider = KotlinTasksProvider()
val compilationInfo = KotlinCompilationInfo(compilation) val compilationInfo = KotlinCompilationInfo(compilation)
@@ -1,43 +0,0 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
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 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 -> SourceSetTree(compilation.name)
}
}
internal suspend fun SourceSetTree.Companion.orNull(
target: KotlinAndroidTarget,
variantType: AndroidVariantType
): SourceSetTree? {
val multiplatform = target.project.multiplatformExtensionOrNull ?: return null
return when (variantType) {
AndroidVariantType.Main ->
multiplatform.targetHierarchy.android.main.sourceSetTree.awaitFinalValue() ?: main
AndroidVariantType.UnitTest ->
multiplatform.targetHierarchy.android.unitTest.sourceSetTree.awaitFinalValue() ?: test
AndroidVariantType.InstrumentedTest ->
multiplatform.targetHierarchy.android.instrumentedTest.sourceSetTree.awaitFinalValue() ?: instrumentedTest
AndroidVariantType.Unknown -> null
}
}
@@ -61,17 +61,17 @@ private class KotlinTargetHierarchyBuilderRootImpl(
override fun sourceSetTrees(vararg tree: KotlinTargetHierarchy.SourceSetTree) { override fun sourceSetTrees(vararg tree: KotlinTargetHierarchy.SourceSetTree) {
builder.modules = tree.toHashSet() builder.sourceSetTrees = tree.toHashSet()
} }
override fun withSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) { override fun withSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) {
builder.modules = builder.modules.orEmpty().plus(tree) builder.sourceSetTrees = builder.sourceSetTrees.orEmpty().plus(tree)
} }
override fun excludeSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) { override fun excludeSourceSetTree(vararg tree: KotlinTargetHierarchy.SourceSetTree) {
val modules = tree.toHashSet() val modules = tree.toHashSet()
if (modules.isEmpty()) return if (modules.isEmpty()) return
builder.modules = builder.modules.orEmpty() - modules builder.sourceSetTrees = builder.sourceSetTrees.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.SourceSetTree>? = null var sourceSetTrees: 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 }
@@ -104,9 +104,9 @@ private class KotlinTargetHierarchyBuilderImpl(
} }
suspend fun contains(compilation: KotlinCompilation<*>): Boolean { suspend fun contains(compilation: KotlinCompilation<*>): Boolean {
modules?.let { modules -> sourceSetTrees?.let { sourceSetTrees ->
val module = KotlinTargetHierarchy.SourceSetTree.orNull(compilation) ?: return false val sourceSetTree = KotlinTargetHierarchy.SourceSetTree.orNull(compilation) ?: return false
if (module !in modules) return false if (sourceSetTree !in sourceSetTrees) return false
} }
/* Return eagerly, when compilation is explicitly excluded */ /* Return eagerly, when compilation is explicitly excluded */
@@ -7,16 +7,13 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy
import org.gradle.api.DomainObjectCollection import org.gradle.api.DomainObjectCollection
import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidTargetHierarchyDsl
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidVariantHierarchyDsl
import org.jetbrains.kotlin.gradle.dsl.KotlinTargetHierarchyDsl import org.jetbrains.kotlin.gradle.dsl.KotlinTargetHierarchyDsl
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchyBuilder
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchyDescriptor
internal class KotlinTargetHierarchyDslImpl( internal class KotlinTargetHierarchyDslImpl(
objects: ObjectFactory,
private val targets: DomainObjectCollection<KotlinTarget>, private val targets: DomainObjectCollection<KotlinTarget>,
private val sourceSets: NamedDomainObjectContainer<KotlinSourceSet>, private val sourceSets: NamedDomainObjectContainer<KotlinSourceSet>,
) : KotlinTargetHierarchyDsl { ) : KotlinTargetHierarchyDsl {
@@ -24,8 +21,6 @@ internal class KotlinTargetHierarchyDslImpl(
private val _appliedDescriptors = mutableListOf<KotlinTargetHierarchyDescriptor>() private val _appliedDescriptors = mutableListOf<KotlinTargetHierarchyDescriptor>()
val appliedDescriptors: List<KotlinTargetHierarchyDescriptor> get() = _appliedDescriptors val appliedDescriptors: List<KotlinTargetHierarchyDescriptor> get() = _appliedDescriptors
override val android: KotlinAndroidTargetHierarchyDsl = KotlinAndroidTargetHierarchyDslImpl(objects)
override fun apply( override fun apply(
hierarchyDescriptor: KotlinTargetHierarchyDescriptor, hierarchyDescriptor: KotlinTargetHierarchyDescriptor,
describeExtension: (KotlinTargetHierarchyBuilder.Root.() -> Unit)?, describeExtension: (KotlinTargetHierarchyBuilder.Root.() -> Unit)?,
@@ -42,21 +37,8 @@ internal class KotlinTargetHierarchyDslImpl(
override fun custom(describe: KotlinTargetHierarchyBuilder.Root.() -> Unit) { override fun custom(describe: KotlinTargetHierarchyBuilder.Root.() -> Unit) {
apply(KotlinTargetHierarchyDescriptor(describe)) apply(KotlinTargetHierarchyDescriptor(describe))
} }
override fun android(configure: KotlinAndroidTargetHierarchyDsl.() -> Unit) {
android.configure()
}
} }
private fun KotlinTargetHierarchyDescriptor.extendIfNotNull(describe: (KotlinTargetHierarchyBuilder.Root.() -> Unit)?) = private fun KotlinTargetHierarchyDescriptor.extendIfNotNull(describe: (KotlinTargetHierarchyBuilder.Root.() -> Unit)?) =
if (describe == null) this else extend(describe) if (describe == null) this else extend(describe)
internal class KotlinAndroidTargetHierarchyDslImpl(objects: ObjectFactory) : KotlinAndroidTargetHierarchyDsl {
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<KotlinTargetHierarchy.SourceSetTree> = objects.property()
}
@@ -0,0 +1,120 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy
import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree
import org.jetbrains.kotlin.gradle.plugin.awaitFinalValue
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilationFactory
import org.jetbrains.kotlin.tooling.core.extrasLazyProperty
/**
* Classifier providing the corresponding [SourceSetTree] associated with any given [KotlinCompilation]
*
* ### Example: Overwriting 'test' compilations [SourceSetTreeClassifier]:
* Consider the following setup:
* ```kotlin
* kotlin {
* val testCompilation = jvm().compilations.getByName("test")
* }
* ```
*
* In this example, we know that the 'jvm/test' compilation will have a 'jvmTest' SourceSet which
* will depend on 'commonTest' and therefore is part of the 'test' [SourceSetTree].
*
* When another [SourceSetTreeClassifier] is specified, this behaviour is changed.
* Using the External Kotlin Target API:
* ```kotlin
* myTarget.createCompilation {
* compilationName = "test"
* sourceSetTreeClassifier = SourceSetTreeClassifier.Name("unitTest")
* }
* ```
*
* This will create a compilation called 'test' which however will be considered part of the 'unitTest' SourceSetTree.
* The SourceSet of this 'jvm/test' compilation will still be called 'jvmTest' but since its part of the 'unitTest [SourceSetTree],
* there will not be a dependsOn edge to 'commonTest', but (if present) 'commonUnitTest'
*/
@ExternalKotlinTargetApi
sealed class SourceSetTreeClassifier {
/**
* Default Classifier: The name of the compilation will be used to infer the [SourceSetTree]:
* 'main' compilations will be part of [SourceSetTree.main]
* 'test' compilations will be part of [SourceSetTree.test]
* ...
*/
@ExternalKotlinTargetApi
object Default : SourceSetTreeClassifier() {
override fun toString(): String = "Default"
}
/**
* Indicates that the given compilations is not part of any 'named' [SourceSetTree].
* Neither [KotlinTargetHierarchy] will be applied nor default dependsOn edges shall be set.
*/
@ExternalKotlinTargetApi
object None : SourceSetTreeClassifier() {
override fun toString(): String = "None"
}
/**
* Predefined [SourceSetTree] using the [tree] specified.
*/
@ExternalKotlinTargetApi
data class Value(val tree: SourceSetTree) : SourceSetTreeClassifier()
/**
* Predefined [SourceSetTree] using the [name] specified
*/
@ExternalKotlinTargetApi
data class Name(val name: String) : SourceSetTreeClassifier()
/**
* Wrapper around [org.gradle.api.provider.Property] of a given [SourceSetTree] in order to
* make the [SourceSetTree] configurable.
*/
@ExternalKotlinTargetApi
class Property(val property: org.gradle.api.provider.Property<SourceSetTree>) : SourceSetTreeClassifier() {
override fun toString(): String {
return property.toString()
}
}
internal suspend fun classify(compilation: KotlinCompilation<*>): SourceSetTree? {
return when (this) {
is Default -> SourceSetTree(compilation.name)
is Property -> property.awaitFinalValue()
is Value -> tree
is Name -> SourceSetTree(name)
is None -> null
}
}
}
/**
* Returns the classifier configured for a given compilation.
* This is writable, as Android requires overwriting of this default behaviour.
*
* - The KGP maintained target will set the classifier within the [KotlinJvmAndroidCompilationFactory]
* - The external Android target will set this classifier within the 'createCompilation'
*
* It is therefore safe to access this value as soon as a compilation is provided
*/
internal var KotlinCompilation<*>.sourceSetTreeClassifier: SourceSetTreeClassifier by extrasLazyProperty {
SourceSetTreeClassifier.Default
}
/**
* Returns the [SourceSetTree] of a given [KotlinCompilation]:
* Uses the [sourceSetTreeClassifier] under the hood.
* See [SourceSetTreeClassifier]
*/
internal suspend fun SourceSetTree.Companion.orNull(compilation: KotlinCompilation<*>) =
compilation.sourceSetTreeClassifier.classify(compilation)
@@ -11,10 +11,9 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy import org.jetbrains.kotlin.gradle.plugin.awaitFinalValue
import org.jetbrains.kotlin.gradle.plugin.launchInStage import org.jetbrains.kotlin.gradle.plugin.launchInStage
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.orNull
import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidBaseSourceSetName import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidBaseSourceSetName
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
@@ -38,7 +37,13 @@ internal object MultiplatformLayoutV2DependsOnConfigurator : KotlinAndroidSource
return@launchInStage return@launchInStage
} }
val sourceSetTree = KotlinTargetHierarchy.SourceSetTree.orNull(target, variantType) ?: return@launchInStage val sourceSetTree = when (variantType) {
AndroidVariantType.Main -> target.targetHierarchy.main.sourceSetTree.awaitFinalValue()
AndroidVariantType.UnitTest -> target.targetHierarchy.unitTest.sourceSetTree.awaitFinalValue()
AndroidVariantType.InstrumentedTest -> target.targetHierarchy.instrumentedTest.sourceSetTree.awaitFinalValue()
AndroidVariantType.Unknown -> null
} ?: return@launchInStage
val commonSourceSetName = lowerCamelCaseName("common", sourceSetTree.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)
@@ -7,14 +7,13 @@
package org.jetbrains.kotlin.gradle.plugin.mpp package org.jetbrains.kotlin.gradle.plugin.mpp
import com.android.build.gradle.api.BaseVariant import com.android.build.gradle.api.BaseVariant
import org.gradle.api.InvalidUserDataException import org.gradle.api.*
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer import org.gradle.api.attributes.AttributeContainer
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.gradle.utils.forAllAndroidVariants import org.jetbrains.kotlin.gradle.utils.forAllAndroidVariants
@@ -26,7 +25,7 @@ import javax.inject.Inject
abstract class KotlinAndroidTarget @Inject constructor( abstract class KotlinAndroidTarget @Inject constructor(
final override val targetName: String, final override val targetName: String,
project: Project project: Project,
) : AbstractKotlinTarget(project) { ) : AbstractKotlinTarget(project) {
final override val disambiguationClassifier: String = targetName final override val disambiguationClassifier: String = targetName
@@ -37,6 +36,109 @@ 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
val targetHierarchy: KotlinAndroidTargetHierarchyDsl = KotlinAndroidTargetHierarchyDslImpl(project.objects).apply {
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
fun targetHierarchy(configure: Action<KotlinAndroidTargetHierarchyDsl>) {
configure.execute(targetHierarchy)
}
/**
* 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
fun targetHierarchy(configure: KotlinAndroidTargetHierarchyDsl.() -> Unit) {
targetHierarchy.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.
@@ -241,7 +343,7 @@ abstract class KotlinAndroidTarget @Inject constructor(
private fun createSourcesElementsIfNeeded( private fun createSourcesElementsIfNeeded(
variantName: String, variantName: String,
apiElementsConfigurationName: String, apiElementsConfigurationName: String,
sourcesElementsConfigurationName: String sourcesElementsConfigurationName: String,
): Configuration { ): Configuration {
val existingConfiguration = project.configurations.findByName(sourcesElementsConfigurationName) val existingConfiguration = project.configurations.findByName(sourcesElementsConfigurationName)
if (existingConfiguration != null) return existingConfiguration if (existingConfiguration != null) return existingConfiguration
@@ -261,7 +363,7 @@ abstract class KotlinAndroidTarget @Inject constructor(
/** We filter this variant out as it is never requested on the consumer side, while keeping it leads to ambiguity between Android and /** We filter this variant out as it is never requested on the consumer side, while keeping it leads to ambiguity between Android and
* JVM variants due to non-nesting sets of unmatched attributes. */ * JVM variants due to non-nesting sets of unmatched attributes. */
private fun filterOutAndroidVariantAttribute( private fun filterOutAndroidVariantAttribute(
attribute: Attribute<*> attribute: Attribute<*>,
): Boolean = ): Boolean =
attribute.name != "com.android.build.gradle.internal.attributes.VariantAttr" && attribute.name != "com.android.build.gradle.internal.attributes.VariantAttr" &&
attribute.name != "com.android.build.api.attributes.VariantAttr" attribute.name != "com.android.build.api.attributes.VariantAttr"
@@ -269,7 +371,7 @@ abstract class KotlinAndroidTarget @Inject constructor(
private fun filterOutAndroidBuildTypeAttribute( private fun filterOutAndroidBuildTypeAttribute(
it: Attribute<*>, it: Attribute<*>,
valueString: String, valueString: String,
isSinglePublishedVariant: Boolean isSinglePublishedVariant: Boolean,
) = when { ) = when {
PropertiesProvider(project).keepAndroidBuildTypeAttribute -> true PropertiesProvider(project).keepAndroidBuildTypeAttribute -> true
it.name != "com.android.build.api.attributes.BuildTypeAttr" -> true it.name != "com.android.build.api.attributes.BuildTypeAttr" -> true
@@ -281,6 +383,7 @@ abstract class KotlinAndroidTarget @Inject constructor(
} }
private fun filterOutAndroidAgpVersionAttribute( private fun filterOutAndroidAgpVersionAttribute(
attribute: Attribute<*> attribute: Attribute<*>,
): Boolean = attribute.name != "com.android.build.api.attributes.AgpVersionAttr" ): Boolean = attribute.name != "com.android.build.api.attributes.AgpVersionAttr"
} }
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
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.utils.property
@ExperimentalKotlinGradlePluginApi
interface KotlinAndroidTargetHierarchyDsl {
val main: KotlinAndroidVariantHierarchyDsl
val unitTest: KotlinAndroidVariantHierarchyDsl
val instrumentedTest: KotlinAndroidVariantHierarchyDsl
}
@ExperimentalKotlinGradlePluginApi
interface KotlinAndroidVariantHierarchyDsl {
/**
* Configures under which [SourceSetTree] the currently configured Android Variant shall be placed.
* e.g.
*
* ```kotlin
* kotlin {
* targetHierarchy.android {
* instrumentedTest.sourceSetTree.set(SourceSetTree.test)
* }
* }
* ```
*
* Will ensure that all android instrumented tests (androidInstrumentedTest, androidInstrumentedTestDebug, ...)
* will be placed into the 'test' SourceSet tree (with 'commonTest' as root)
*
* See [KotlinTargetHierarchyDsl.android]
*/
val sourceSetTree: Property<SourceSetTree>
}
internal class KotlinAndroidTargetHierarchyDslImpl(objects: ObjectFactory) : KotlinAndroidTargetHierarchyDsl {
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()
}
@@ -12,10 +12,15 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinAndroidCompi
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.AndroidCompilationSourceSetsContainerFactory import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.AndroidCompilationSourceSetsContainerFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinJvmCompilerOptionsFactory import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinJvmCompilerOptionsFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.SourceSetTreeClassifier
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.SourceSetTreeClassifier.Property
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.sourceSetTreeClassifier
import org.jetbrains.kotlin.gradle.plugin.sources.android.AndroidVariantType
import org.jetbrains.kotlin.gradle.plugin.sources.android.type
class KotlinJvmAndroidCompilationFactory internal constructor( class KotlinJvmAndroidCompilationFactory internal constructor(
override val target: KotlinAndroidTarget, override val target: KotlinAndroidTarget,
private val variant: BaseVariant private val variant: BaseVariant,
) : KotlinCompilationFactory<KotlinJvmAndroidCompilation> { ) : KotlinCompilationFactory<KotlinJvmAndroidCompilation> {
override val itemClass: Class<KotlinJvmAndroidCompilation> override val itemClass: Class<KotlinJvmAndroidCompilation>
@@ -34,6 +39,17 @@ class KotlinJvmAndroidCompilationFactory internal constructor(
) )
override fun create(name: String): KotlinJvmAndroidCompilation { override fun create(name: String): KotlinJvmAndroidCompilation {
return project.objects.newInstance(itemClass, compilationImplFactory.create(target, name), variant) return project.objects.newInstance(itemClass, compilationImplFactory.create(target, name), variant).also { compilation ->
configureSourceSetTreeClassifier(compilation)
}
}
private fun configureSourceSetTreeClassifier(compilation: KotlinJvmAndroidCompilation) {
compilation.sourceSetTreeClassifier = when (variant.type) {
AndroidVariantType.Main -> Property(target.targetHierarchy.main.sourceSetTree)
AndroidVariantType.UnitTest -> Property(target.targetHierarchy.unitTest.sourceSetTree)
AndroidVariantType.InstrumentedTest -> Property(target.targetHierarchy.instrumentedTest.sourceSetTree)
AndroidVariantType.Unknown -> SourceSetTreeClassifier.None
}
} }
} }
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName", "DuplicatedCode")
package org.jetbrains.kotlin.gradle.unitTests
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree
import org.jetbrains.kotlin.gradle.plugin.launchInStage
import org.jetbrains.kotlin.gradle.plugin.mpp.external.*
import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinCompilationDescriptor.CompilationFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinTargetDescriptor.TargetFactory
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.SourceSetTreeClassifier
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.orNull
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest
import org.jetbrains.kotlin.gradle.utils.property
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
class ExternalKotlinTargetApiTests {
class FakeTarget(delegate: Delegate) : DecoratedExternalKotlinTarget(delegate)
class FakeCompilation(delegate: Delegate) : DecoratedExternalKotlinCompilation(delegate)
val project = buildProjectWithMPP()
val kotlin = project.multiplatformExtension
private fun ExternalKotlinTargetDescriptorBuilder<FakeTarget>.defaults() {
targetName = "fake"
platformType = KotlinPlatformType.jvm
targetFactory = TargetFactory(::FakeTarget)
}
private fun ExternalKotlinCompilationDescriptorBuilder<FakeCompilation>.defaults() {
compilationName = "fake"
compilationFactory = CompilationFactory(::FakeCompilation)
defaultSourceSet = kotlin.sourceSets.maybeCreate("fake")
}
@Test
fun `test - sourceSetClassifier - default`() = buildProjectWithMPP().runLifecycleAwareTest {
val target = kotlin.createExternalKotlinTarget<FakeTarget> { defaults() }
val compilation = target.createCompilation<FakeCompilation> { defaults() }
assertEquals(SourceSetTree("fake"), SourceSetTree.orNull(compilation))
}
@Test
fun `test - sourceSetClassifier - custom name`() = buildProjectWithMPP().runLifecycleAwareTest {
val target = kotlin.createExternalKotlinTarget<FakeTarget> { defaults() }
val compilation = target.createCompilation<FakeCompilation> {
defaults()
sourceSetTreeClassifier = SourceSetTreeClassifier.Name("mySourceSetTree")
}
assertEquals(SourceSetTree("mySourceSetTree"), SourceSetTree.orNull(compilation))
}
@Test
fun `test - sourceSetClassifier - custom property`() = buildProjectWithMPP().runLifecycleAwareTest {
val myProperty = project.objects.property<SourceSetTree>()
val nullProperty = project.objects.property<SourceSetTree>()
val target = kotlin.createExternalKotlinTarget<FakeTarget> { defaults() }
val mainCompilation = target.createCompilation<FakeCompilation> {
defaults()
sourceSetTreeClassifier = SourceSetTreeClassifier.Property(myProperty)
}
val auxCompilation = target.createCompilation<FakeCompilation>() {
compilationName = "aux"
compilationFactory = CompilationFactory(::FakeCompilation)
defaultSourceSet = kotlin.sourceSets.create("aux")
sourceSetTreeClassifier = SourceSetTreeClassifier.Property(nullProperty)
}
launchInStage(KotlinPluginLifecycle.Stage.FinaliseDsl) {
myProperty.set(SourceSetTree.main)
}
assertEquals(SourceSetTree.main, SourceSetTree.orNull(mainCompilation))
assertNull(SourceSetTree.orNull(auxCompilation))
}
}
@@ -15,7 +15,7 @@ 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.targetHierarchy.KotlinAndroidVariantHierarchyDslImpl import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidVariantHierarchyDslImpl
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
@@ -38,7 +38,7 @@ class KotlinAndroidTargetHierarchyDsl {
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)
assertEquals(KotlinPluginLifecycle.Stage.FinaliseDsl, currentKotlinPluginLifecycle().stage) assertEquals(KotlinPluginLifecycle.Stage.AfterFinaliseDsl, currentKotlinPluginLifecycle().stage)
} }
@Test @Test
@@ -51,9 +51,7 @@ class KotlinAndroidTargetHierarchyDsl {
val kotlin = project.multiplatformExtension val kotlin = project.multiplatformExtension
project.runLifecycleAwareTest { project.runLifecycleAwareTest {
kotlin.androidTarget() kotlin.androidTarget().targetHierarchy {
kotlin.targetHierarchy.android {
unitTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test) unitTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test)
instrumentedTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test) instrumentedTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree.test)
} }
@@ -75,9 +73,7 @@ class KotlinAndroidTargetHierarchyDsl {
val kotlin = project.multiplatformExtension val kotlin = project.multiplatformExtension
project.runLifecycleAwareTest { project.runLifecycleAwareTest {
kotlin.androidTarget() kotlin.androidTarget().targetHierarchy {
kotlin.targetHierarchy.android {
unitTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("xxx")) unitTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("xxx"))
instrumentedTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("yyy")) instrumentedTest.sourceSetTree.set(KotlinTargetHierarchy.SourceSetTree("yyy"))
} }