[Gradle] KotlinTargetHierarchy.Module: Respect configuration from Android
KT-34662
This commit is contained in:
committed by
Space Team
parent
7ab6349ad5
commit
5fe6e3edbb
+3
-2
@@ -13,8 +13,9 @@ interface KotlinTargetHierarchyBuilder {
|
||||
fun group(name: String, build: KotlinTargetHierarchyBuilder.() -> Unit = {})
|
||||
|
||||
/* low-level APIs */
|
||||
fun withCompilations(predicate: (KotlinCompilation<*>) -> Boolean)
|
||||
fun withoutCompilations(predicate: (KotlinCompilation<*>) -> Boolean)
|
||||
fun withCompilations(predicate: suspend (KotlinCompilation<*>) -> Boolean)
|
||||
fun withoutCompilations(predicate: suspend (KotlinCompilation<*>) -> Boolean)
|
||||
|
||||
@Deprecated("Use plain 'withoutCompilations(!predicate) instead'", ReplaceWith("withoutCompilations { !predicate(it) }"))
|
||||
fun filterCompilations(predicate: (KotlinCompilation<*>) -> Boolean) = withoutCompilations { !predicate(it) }
|
||||
|
||||
|
||||
+22
-10
@@ -6,6 +6,8 @@
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy
|
||||
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
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
|
||||
@@ -20,14 +22,14 @@ internal data class KotlinTargetHierarchy(
|
||||
children.withClosure<KotlinTargetHierarchy> { it.children }
|
||||
|
||||
sealed class Node {
|
||||
abstract fun sharedSourceSetName(compilation: KotlinCompilation<*>): String?
|
||||
abstract suspend fun sharedSourceSetName(compilation: KotlinCompilation<*>): String?
|
||||
|
||||
object Root : Node() {
|
||||
override fun sharedSourceSetName(compilation: KotlinCompilation<*>): String? = null
|
||||
override suspend fun sharedSourceSetName(compilation: KotlinCompilation<*>): String? = null
|
||||
}
|
||||
|
||||
data class Group(val name: String) : Node() {
|
||||
override fun sharedSourceSetName(compilation: KotlinCompilation<*>): String? {
|
||||
override suspend fun sharedSourceSetName(compilation: KotlinCompilation<*>): String? {
|
||||
val moduleName = Module.orNull(compilation)?.name ?: return null
|
||||
return lowerCamelCaseName(name, moduleName)
|
||||
}
|
||||
@@ -47,19 +49,29 @@ internal data class KotlinTargetHierarchy(
|
||||
val test = Module("test")
|
||||
private val instrumentedTest = Module("instrumentedTest")
|
||||
|
||||
fun orNull(compilation: KotlinCompilation<*>): Module? = when (compilation) {
|
||||
is KotlinJvmAndroidCompilation -> when (compilation.androidVariant.type) {
|
||||
AndroidVariantType.Main -> main
|
||||
AndroidVariantType.UnitTest -> test
|
||||
AndroidVariantType.InstrumentedTest -> instrumentedTest
|
||||
AndroidVariantType.Unknown -> null
|
||||
}
|
||||
suspend fun orNull(compilation: KotlinCompilation<*>): Module? = when (compilation) {
|
||||
is KotlinJvmAndroidCompilation -> orNull(compilation.target, compilation.androidVariant.type)
|
||||
else -> when (compilation.name) {
|
||||
"main" -> main
|
||||
"test" -> test
|
||||
else -> Module(compilation.name)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun orNull(target: KotlinAndroidTarget, variantType: AndroidVariantType): Module? {
|
||||
return when (variantType) {
|
||||
AndroidVariantType.Main ->
|
||||
Module(target.main.kotlinModuleName.awaitFinalValue() ?: return main)
|
||||
|
||||
AndroidVariantType.UnitTest ->
|
||||
Module(target.unitTest.kotlinModuleName.awaitFinalValue() ?: return test)
|
||||
|
||||
AndroidVariantType.InstrumentedTest ->
|
||||
Module(target.instrumentedTest.kotlinModuleName.awaitFinalValue() ?: return instrumentedTest)
|
||||
|
||||
AndroidVariantType.Unknown -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.tooling.core.closure
|
||||
|
||||
internal fun KotlinTargetHierarchyDescriptor.buildKotlinTargetHierarchy(compilation: KotlinCompilation<*>): KotlinTargetHierarchy? {
|
||||
internal suspend fun KotlinTargetHierarchyDescriptor.buildKotlinTargetHierarchy(compilation: KotlinCompilation<*>): KotlinTargetHierarchy? {
|
||||
val context = KotlinTargetHierarchyBuilderImplContext(compilation)
|
||||
describe(context.getOrCreateBuilder(KotlinTargetHierarchy.Node.Root))
|
||||
return context.build(KotlinTargetHierarchy.Node.Root)
|
||||
@@ -33,10 +33,10 @@ private class KotlinTargetHierarchyBuilderImplContext(private val compilation: K
|
||||
KotlinTargetHierarchyBuilderImpl(this, node)
|
||||
}
|
||||
|
||||
fun build(node: KotlinTargetHierarchy.Node): KotlinTargetHierarchy? {
|
||||
suspend fun build(node: KotlinTargetHierarchy.Node): KotlinTargetHierarchy? {
|
||||
return builtValues.getOrPut(node) {
|
||||
val builder = getOrCreateBuilder(node)
|
||||
if (compilation !in builder) return@getOrPut null
|
||||
if (!builder.contains(compilation)) return@getOrPut null
|
||||
|
||||
/*
|
||||
Keep the hierarchy 'deduplicated'.
|
||||
@@ -64,24 +64,24 @@ private class KotlinTargetHierarchyBuilderImpl(
|
||||
val children = mutableSetOf<KotlinTargetHierarchyBuilderImpl>()
|
||||
val childrenClosure get() = closure { it.children }
|
||||
|
||||
private var includePredicate: ((KotlinCompilation<*>) -> Boolean) = { false }
|
||||
private var excludePredicate: ((KotlinCompilation<*>) -> Boolean) = { false }
|
||||
private var includePredicate: (suspend (KotlinCompilation<*>) -> Boolean) = { false }
|
||||
private var excludePredicate: (suspend (KotlinCompilation<*>) -> Boolean) = { false }
|
||||
|
||||
override fun withCompilations(predicate: (KotlinCompilation<*>) -> Boolean) {
|
||||
override fun withCompilations(predicate: suspend (KotlinCompilation<*>) -> Boolean) {
|
||||
val previousIncludePredicate = this.includePredicate
|
||||
val previousExcludePredicate = this.excludePredicate
|
||||
this.includePredicate = { previousIncludePredicate(it) || predicate(it) }
|
||||
this.excludePredicate = { previousExcludePredicate(it) && !predicate(it) }
|
||||
}
|
||||
|
||||
override fun withoutCompilations(predicate: (KotlinCompilation<*>) -> Boolean) {
|
||||
override fun withoutCompilations(predicate: suspend (KotlinCompilation<*>) -> Boolean) {
|
||||
val previousIncludePredicate = this.includePredicate
|
||||
val previousExcludePredicate = this.excludePredicate
|
||||
this.includePredicate = { previousIncludePredicate(it) && !predicate(it) }
|
||||
this.excludePredicate = { previousExcludePredicate(it) || predicate(it) }
|
||||
}
|
||||
|
||||
operator fun contains(compilation: KotlinCompilation<*>): Boolean {
|
||||
suspend fun contains(compilation: KotlinCompilation<*>): Boolean {
|
||||
/* Return eagerly, when compilation is explicitly excluded */
|
||||
if (excludePredicate(compilation)) return false
|
||||
|
||||
@@ -89,7 +89,7 @@ private class KotlinTargetHierarchyBuilderImpl(
|
||||
if (includePredicate(compilation)) return true
|
||||
|
||||
/* Find any child that includes this compilation */
|
||||
return childrenClosure.any { child -> compilation in child }
|
||||
return childrenClosure.any { child -> child.contains(compilation) }
|
||||
}
|
||||
|
||||
private inline fun withTargets(crossinline predicate: (KotlinTarget) -> Boolean) = withCompilations { predicate(it.target) }
|
||||
|
||||
+6
-4
@@ -19,13 +19,15 @@ internal fun applyKotlinTargetHierarchy(
|
||||
.matching { target -> target.platformType != KotlinPlatformType.common }
|
||||
.all { target ->
|
||||
target.compilations.all forCompilation@{ compilation ->
|
||||
val hierarchy = hierarchyDescriptor.buildKotlinTargetHierarchy(compilation) ?: return@forCompilation
|
||||
applyKotlinTargetHierarchy(hierarchy, compilation, sourceSets)
|
||||
target.project.kotlinMultiplatformPluginLifecycle.launch {
|
||||
val hierarchy = hierarchyDescriptor.buildKotlinTargetHierarchy(compilation) ?: return@launch
|
||||
applyKotlinTargetHierarchy(hierarchy, compilation, sourceSets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyKotlinTargetHierarchy(
|
||||
private suspend fun applyKotlinTargetHierarchy(
|
||||
hierarchy: KotlinTargetHierarchy,
|
||||
compilation: KotlinCompilation<*>,
|
||||
sourceSets: NamedDomainObjectContainer<KotlinSourceSet>
|
||||
@@ -48,7 +50,7 @@ private fun applyKotlinTargetHierarchy(
|
||||
return sharedSourceSet
|
||||
}
|
||||
|
||||
private fun createSharedSourceSetOrNull(
|
||||
private suspend fun createSharedSourceSetOrNull(
|
||||
sourceSets: NamedDomainObjectContainer<KotlinSourceSet>,
|
||||
node: KotlinTargetHierarchy.Node,
|
||||
compilation: KotlinCompilation<*>,
|
||||
|
||||
+8
-13
@@ -11,14 +11,15 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginLifecycle
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_MAIN_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.kotlinMultiplatformPluginLifecycle
|
||||
import org.jetbrains.kotlin.gradle.plugin.launch
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.KotlinTargetHierarchy
|
||||
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.type
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.android.variantType
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
|
||||
internal object MultiplatformLayoutV2DependsOnConfigurator : KotlinAndroidSourceSetConfigurator {
|
||||
override fun configure(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, androidSourceSet: AndroidSourceSet) {
|
||||
@@ -31,22 +32,16 @@ internal object MultiplatformLayoutV2DependsOnConfigurator : KotlinAndroidSource
|
||||
}
|
||||
|
||||
private fun setDefaultDependsOn(target: KotlinAndroidTarget, kotlinSourceSet: KotlinSourceSet, variantType: AndroidVariantType) {
|
||||
target.project.kotlinMultiplatformPluginLifecycle.launch {
|
||||
await(KotlinMultiplatformPluginLifecycle.Stage.FinaliseRefinesEdges)
|
||||
target.project.launch(KotlinMultiplatformPluginLifecycle.Stage.FinaliseRefinesEdges) {
|
||||
/* Only setup default if not KotlinTargetHierarchy was applied */
|
||||
if (target.project.multiplatformExtensionOrNull?.internalKotlinTargetHierarchy?.appliedDescriptors.orEmpty().isNotEmpty()) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
/* Add default dependency on 'commonMain' or 'commonTest' */
|
||||
val commonMain = target.project.kotlinExtension.sourceSets.getByName(COMMON_MAIN_SOURCE_SET_NAME)
|
||||
val commonTest = target.project.kotlinExtension.sourceSets.getByName(COMMON_TEST_SOURCE_SET_NAME)
|
||||
|
||||
when (variantType) {
|
||||
AndroidVariantType.Main -> kotlinSourceSet.dependsOn(commonMain)
|
||||
AndroidVariantType.UnitTest -> kotlinSourceSet.dependsOn(commonTest)
|
||||
AndroidVariantType.InstrumentedTest, AndroidVariantType.Unknown -> Unit
|
||||
}
|
||||
val module = KotlinTargetHierarchy.Module.orNull(target, variantType) ?: return@launch
|
||||
val commonSourceSetName = lowerCamelCaseName("common", module.name)
|
||||
val commonSourceSet = target.project.kotlinExtension.sourceSets.findByName(commonSourceSetName) ?: return@launch
|
||||
kotlinSourceSet.dependsOn(commonSourceSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-1
@@ -12,9 +12,13 @@ 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.attributes.*
|
||||
import org.gradle.api.attributes.Attribute
|
||||
import org.gradle.api.attributes.AttributeContainer
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes
|
||||
import org.jetbrains.kotlin.gradle.targets.android.InternalKotlinAndroidTargetVariantTypeDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.android.KotlinAndroidTargetVariantTypeDsl
|
||||
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
|
||||
import org.jetbrains.kotlin.gradle.utils.forAllAndroidVariants
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
@@ -36,6 +40,15 @@ abstract class KotlinAndroidTarget @Inject constructor(
|
||||
override val compilations: NamedDomainObjectContainer<out KotlinJvmAndroidCompilation> =
|
||||
project.container(KotlinJvmAndroidCompilation::class.java)
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
val main: KotlinAndroidTargetVariantTypeDsl = InternalKotlinAndroidTargetVariantTypeDsl(project)
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
val unitTest: KotlinAndroidTargetVariantTypeDsl = InternalKotlinAndroidTargetVariantTypeDsl(project)
|
||||
|
||||
@ExperimentalKotlinGradlePluginApi
|
||||
val instrumentedTest: KotlinAndroidTargetVariantTypeDsl = InternalKotlinAndroidTargetVariantTypeDsl(project)
|
||||
|
||||
/** 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.
|
||||
*
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.targets.android
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.provider.Property
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginLifecycle.Stage
|
||||
import org.jetbrains.kotlin.gradle.plugin.newLifecycleAwareProperty
|
||||
|
||||
sealed class KotlinAndroidTargetVariantTypeDsl {
|
||||
abstract val kotlinModuleName: Property<String>
|
||||
}
|
||||
|
||||
internal val KotlinAndroidTargetVariantTypeDsl.internal: InternalKotlinAndroidTargetVariantTypeDsl
|
||||
get() = when (this) {
|
||||
is InternalKotlinAndroidTargetVariantTypeDsl -> this
|
||||
}
|
||||
|
||||
internal class InternalKotlinAndroidTargetVariantTypeDsl(
|
||||
val project: Project,
|
||||
) : KotlinAndroidTargetVariantTypeDsl() {
|
||||
|
||||
override val kotlinModuleName: Property<String> by project.newLifecycleAwareProperty<String>(
|
||||
finaliseIn = Stage.BeforeFinaliseRefinesEdges
|
||||
)
|
||||
}
|
||||
-1
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTest
|
||||
import org.jetbrains.kotlin.gradle.testing.internal.reportsDir
|
||||
import org.jetbrains.kotlin.gradle.utils.appendLine
|
||||
import org.jetbrains.kotlin.gradle.utils.isParentOf
|
||||
import org.jetbrains.kotlin.gradle.utils.property
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import org.slf4j.Logger
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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")
|
||||
|
||||
package org.jetbrains.kotlin.gradle.unitTests
|
||||
|
||||
import junit.framework.TestCase.assertNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.awaitFinalValue
|
||||
import org.jetbrains.kotlin.gradle.plugin.kotlinMultiplatformPluginLifecycle
|
||||
import org.jetbrains.kotlin.gradle.targets.android.InternalKotlinAndroidTargetVariantTypeDsl
|
||||
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
|
||||
import org.junit.Test
|
||||
|
||||
class KotlinAndroidTargetVariantTypeDslTest {
|
||||
private val project = buildProjectWithMPP()
|
||||
|
||||
|
||||
@Test
|
||||
fun `test - targetHierarchyModuleName - not set`() {
|
||||
val dsl = InternalKotlinAndroidTargetVariantTypeDsl(project)
|
||||
project.kotlinMultiplatformPluginLifecycle.launch {
|
||||
assertNull(dsl.kotlinModuleName.orNull)
|
||||
assertNull(dsl.kotlinModuleName.awaitFinalValue())
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -201,7 +201,7 @@ class KotlinTargetHierarchyDslTest {
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
stringSetOf("jvmTest", "androidUnitTest", "androidUnitTest", "androidUnitTestDebug", "androidUnitTestRelease"),
|
||||
stringSetOf("androidUnitTest", "androidUnitTestDebug", "androidUnitTestRelease", "jvmTest"),
|
||||
kotlin.dependingSourceSetNames("jvmAndAndroidTest")
|
||||
)
|
||||
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginLifecycle
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.enqueue
|
||||
import org.jetbrains.kotlin.gradle.plugin.launch
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.getHostSpecificMainSharedSourceSets
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.InternalKotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
||||
@@ -70,7 +70,7 @@ class InternalKotlinSourceSetTest {
|
||||
nativeMain.internal.compilations
|
||||
)
|
||||
|
||||
project.enqueue(KotlinMultiplatformPluginLifecycle.Stage.Finalised) {
|
||||
project.launch(KotlinMultiplatformPluginLifecycle.Stage.Finalised) {
|
||||
assertEquals<Set<KotlinCompilation<*>>>(
|
||||
setOf(
|
||||
metadataCompilation,
|
||||
|
||||
Reference in New Issue
Block a user