[Gradle] Introduce 'LifecycleAwareProperty'
KT-34662
This commit is contained in:
committed by
Space Team
parent
96edfe9048
commit
80ffd72f25
+127
-14
@@ -5,24 +5,79 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.plugin
|
package org.jetbrains.kotlin.gradle.plugin
|
||||||
|
|
||||||
|
import kotlinx.coroutines.currentCoroutineContext
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginLifecycle.IllegalLifecycleException
|
import org.gradle.api.provider.Property
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginLifecycle.Stage
|
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginLifecycle.*
|
||||||
import org.jetbrains.kotlin.gradle.utils.getOrPut
|
import org.jetbrains.kotlin.gradle.utils.getOrPut
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import kotlin.collections.ArrayDeque
|
||||||
|
import kotlin.collections.Map
|
||||||
|
import kotlin.collections.associateWith
|
||||||
|
import kotlin.collections.getValue
|
||||||
|
import kotlin.collections.set
|
||||||
|
import kotlin.collections.toList
|
||||||
import kotlin.coroutines.*
|
import kotlin.coroutines.*
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
/*
|
||||||
|
Util functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
internal fun Project.launch(block: suspend KotlinMultiplatformPluginLifecycle.() -> Unit) {
|
||||||
|
kotlinMultiplatformPluginLifecycle.launch(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Project.launch(stage: Stage, block: suspend KotlinMultiplatformPluginLifecycle.() -> Unit) {
|
||||||
|
launch {
|
||||||
|
await(stage)
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal val Project.kotlinMultiplatformPluginLifecycle: KotlinMultiplatformPluginLifecycle
|
internal val Project.kotlinMultiplatformPluginLifecycle: KotlinMultiplatformPluginLifecycle
|
||||||
get() = extraProperties.getOrPut(KotlinMultiplatformPluginLifecycle::class.java.name) { KotlinMultiplatformPluginLifecycleImpl() }
|
get() = extraProperties.getOrPut(KotlinMultiplatformPluginLifecycle::class.java.name) {
|
||||||
|
KotlinMultiplatformPluginLifecycleImpl(project)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun Project.startKotlinMultiplatformPluginLifecycle() {
|
internal fun Project.startKotlinMultiplatformPluginLifecycle() {
|
||||||
(kotlinMultiplatformPluginLifecycle as KotlinMultiplatformPluginLifecycleImpl).start(this)
|
(kotlinMultiplatformPluginLifecycle as KotlinMultiplatformPluginLifecycleImpl).start()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal inline fun Project.enqueue(stage: Stage, crossinline action: Project.() -> Unit) {
|
internal suspend fun currentMultiplatformPluginLifecycle(): KotlinMultiplatformPluginLifecycle {
|
||||||
kotlinMultiplatformPluginLifecycle.enqueue(stage) { action() }
|
return currentCoroutineContext()[KotlinMultiplatformPluginLifecycleCoroutineContextElement]?.lifecycle
|
||||||
|
?: error("Missing $KotlinMultiplatformPluginLifecycleCoroutineContextElement in currentCoroutineContext")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal suspend fun await(stage: Stage) {
|
||||||
|
currentMultiplatformPluginLifecycle().await(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified T : Any> Project.newLifecycleAwareProperty(
|
||||||
|
finaliseIn: Stage, initialValue: T? = null
|
||||||
|
): LifecycleAwareProperty<T> {
|
||||||
|
return kotlinMultiplatformPluginLifecycle.newLifecycleAwareProperty(T::class.java, finaliseIn, initialValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun <T : Any> Property<T>.findLifecycleAwareProperty(): LifecycleAwareProperty<T>? {
|
||||||
|
return (currentMultiplatformPluginLifecycle() as KotlinMultiplatformPluginLifecycleImpl).findLifecycleAwareProperty(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun <T : Any> Property<T>.awaitFinalValue(): T? {
|
||||||
|
val lifecycleAwareProperty = findLifecycleAwareProperty() ?: throw IllegalArgumentException("Property is not lifecycle aware")
|
||||||
|
return lifecycleAwareProperty.awaitFinalValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun Property<*>.isLifecycleAware(): Boolean {
|
||||||
|
return findLifecycleAwareProperty() != null
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Definition of the Lifecycle and its stages
|
||||||
|
*/
|
||||||
|
|
||||||
internal interface KotlinMultiplatformPluginLifecycle {
|
internal interface KotlinMultiplatformPluginLifecycle {
|
||||||
enum class Stage {
|
enum class Stage {
|
||||||
Configure,
|
Configure,
|
||||||
@@ -39,25 +94,47 @@ internal interface KotlinMultiplatformPluginLifecycle {
|
|||||||
Finalised
|
Finalised
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LifecycleAwareProperty<T : Any> {
|
||||||
|
val finaliseIn: Stage
|
||||||
|
val property: Property<T>
|
||||||
|
suspend fun awaitFinalValue(): T?
|
||||||
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): Property<T> = this.property
|
||||||
|
}
|
||||||
|
|
||||||
|
val project: Project
|
||||||
|
|
||||||
val stage: Stage
|
val stage: Stage
|
||||||
|
|
||||||
fun enqueue(stage: Stage, action: () -> Unit)
|
fun enqueue(stage: Stage, action: KotlinMultiplatformPluginLifecycle.() -> Unit)
|
||||||
|
|
||||||
fun launch(block: suspend KotlinMultiplatformPluginLifecycle.() -> Unit)
|
fun launch(block: suspend KotlinMultiplatformPluginLifecycle.() -> Unit)
|
||||||
|
|
||||||
suspend fun await(stage: Stage)
|
suspend fun await(stage: Stage)
|
||||||
|
|
||||||
|
fun <T : Any> newLifecycleAwareProperty(
|
||||||
|
type: Class<T>, finaliseIn: Stage, initialValue: T?
|
||||||
|
): LifecycleAwareProperty<T>
|
||||||
|
|
||||||
class IllegalLifecycleException(message: String) : IllegalStateException(message)
|
class IllegalLifecycleException(message: String) : IllegalStateException(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class KotlinMultiplatformPluginLifecycleImpl : KotlinMultiplatformPluginLifecycle {
|
|
||||||
|
/*
|
||||||
|
Implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
private class KotlinMultiplatformPluginLifecycleImpl(override val project: Project) : KotlinMultiplatformPluginLifecycle {
|
||||||
private val enqueuedStages: ArrayDeque<Stage> = ArrayDeque(Stage.values().toList())
|
private val enqueuedStages: ArrayDeque<Stage> = ArrayDeque(Stage.values().toList())
|
||||||
private val enqueuedActions: Map<Stage, ArrayDeque<() -> Unit>> = Stage.values().associateWith { ArrayDeque() }
|
private val enqueuedActions: Map<Stage, ArrayDeque<KotlinMultiplatformPluginLifecycle.() -> Unit>> =
|
||||||
|
Stage.values().associateWith { ArrayDeque() }
|
||||||
|
|
||||||
private var configureLoopRunning = AtomicBoolean(false)
|
private var configureLoopRunning = AtomicBoolean(false)
|
||||||
private var isStarted = AtomicBoolean(false)
|
private var isStarted = AtomicBoolean(false)
|
||||||
private var isFinished = AtomicBoolean(false)
|
private var isFinished = AtomicBoolean(false)
|
||||||
|
|
||||||
fun start(project: Project) {
|
private val properties = WeakHashMap<Property<*>, WeakReference<LifecycleAwareProperty<*>>>()
|
||||||
|
|
||||||
|
fun start() {
|
||||||
check(!isStarted.getAndSet(true)) {
|
check(!isStarted.getAndSet(true)) {
|
||||||
"${KotlinMultiplatformPluginLifecycle::class.java.name} already started"
|
"${KotlinMultiplatformPluginLifecycle::class.java.name} already started"
|
||||||
}
|
}
|
||||||
@@ -76,7 +153,7 @@ private class KotlinMultiplatformPluginLifecycleImpl : KotlinMultiplatformPlugin
|
|||||||
val queue = enqueuedActions.getValue(stage)
|
val queue = enqueuedActions.getValue(stage)
|
||||||
do {
|
do {
|
||||||
val action = queue.removeFirstOrNull()
|
val action = queue.removeFirstOrNull()
|
||||||
action?.invoke()
|
action?.invoke(this)
|
||||||
} while (action != null)
|
} while (action != null)
|
||||||
val nextStage = enqueuedStages.removeFirstOrNull() ?: run {
|
val nextStage = enqueuedStages.removeFirstOrNull() ?: run {
|
||||||
isFinished.set(true)
|
isFinished.set(true)
|
||||||
@@ -95,7 +172,7 @@ private class KotlinMultiplatformPluginLifecycleImpl : KotlinMultiplatformPlugin
|
|||||||
val queue = enqueuedActions.getValue(Stage.Configure)
|
val queue = enqueuedActions.getValue(Stage.Configure)
|
||||||
do {
|
do {
|
||||||
val action = queue.removeFirstOrNull()
|
val action = queue.removeFirstOrNull()
|
||||||
action?.invoke()
|
action?.invoke(this)
|
||||||
} while (action != null)
|
} while (action != null)
|
||||||
} finally {
|
} finally {
|
||||||
configureLoopRunning.set(false)
|
configureLoopRunning.set(false)
|
||||||
@@ -104,7 +181,7 @@ private class KotlinMultiplatformPluginLifecycleImpl : KotlinMultiplatformPlugin
|
|||||||
|
|
||||||
override var stage: Stage = enqueuedStages.removeFirst()
|
override var stage: Stage = enqueuedStages.removeFirst()
|
||||||
|
|
||||||
override fun enqueue(stage: Stage, action: () -> Unit) {
|
override fun enqueue(stage: Stage, action: KotlinMultiplatformPluginLifecycle.() -> Unit) {
|
||||||
if (stage < this.stage) {
|
if (stage < this.stage) {
|
||||||
throw IllegalLifecycleException("Cannot enqueue Action for stage '${this.stage}' in current stage '${this.stage}'")
|
throw IllegalLifecycleException("Cannot enqueue Action for stage '${this.stage}' in current stage '${this.stage}'")
|
||||||
}
|
}
|
||||||
@@ -117,10 +194,14 @@ private class KotlinMultiplatformPluginLifecycleImpl : KotlinMultiplatformPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun launch(block: suspend KotlinMultiplatformPluginLifecycle.() -> Unit) {
|
override fun launch(block: suspend KotlinMultiplatformPluginLifecycle.() -> Unit) {
|
||||||
|
val lifecycle = this
|
||||||
check(isStarted.get()) { "Cannot launch when ${KotlinMultiplatformPluginLifecycle::class.simpleName} is not started" }
|
check(isStarted.get()) { "Cannot launch when ${KotlinMultiplatformPluginLifecycle::class.simpleName} is not started" }
|
||||||
check(!isFinished.get()) { "Cannot launch when ${KotlinMultiplatformPluginLifecycle::class.simpleName} is already finished" }
|
check(!isFinished.get()) { "Cannot launch when ${KotlinMultiplatformPluginLifecycle::class.simpleName} is already finished" }
|
||||||
val coroutine = block.createCoroutine(this, object : Continuation<Unit> {
|
val coroutine = block.createCoroutine(this, object : Continuation<Unit> {
|
||||||
override val context: CoroutineContext = EmptyCoroutineContext
|
|
||||||
|
override val context: CoroutineContext = EmptyCoroutineContext +
|
||||||
|
KotlinMultiplatformPluginLifecycleCoroutineContextElement(lifecycle)
|
||||||
|
|
||||||
override fun resumeWith(result: Result<Unit>) = result.getOrThrow()
|
override fun resumeWith(result: Result<Unit>) = result.getOrThrow()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -137,4 +218,36 @@ private class KotlinMultiplatformPluginLifecycleImpl : KotlinMultiplatformPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> newLifecycleAwareProperty(type: Class<T>, finaliseIn: Stage, initialValue: T?): LifecycleAwareProperty<T> {
|
||||||
|
val property = project.objects.property(type)
|
||||||
|
if (initialValue != null) property.set(initialValue)
|
||||||
|
enqueue(finaliseIn) { property.finalizeValue() }
|
||||||
|
val lifecycleAwareProperty = LifecycleAwarePropertyImpl(finaliseIn, property)
|
||||||
|
properties[property] = WeakReference(lifecycleAwareProperty)
|
||||||
|
return lifecycleAwareProperty
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> findLifecycleAwareProperty(property: Property<T>): LifecycleAwareProperty<T>? {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return properties[property]?.get() as? LifecycleAwareProperty<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LifecycleAwarePropertyImpl<T : Any>(
|
||||||
|
override val finaliseIn: Stage,
|
||||||
|
override val property: Property<T>
|
||||||
|
) : LifecycleAwareProperty<T> {
|
||||||
|
override suspend fun awaitFinalValue(): T? {
|
||||||
|
await(finaliseIn)
|
||||||
|
return property.orNull
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class KotlinMultiplatformPluginLifecycleCoroutineContextElement(
|
||||||
|
val lifecycle: KotlinMultiplatformPluginLifecycle
|
||||||
|
) : CoroutineContext.Element {
|
||||||
|
companion object Key : CoroutineContext.Key<KotlinMultiplatformPluginLifecycleCoroutineContextElement>
|
||||||
|
|
||||||
|
override val key: CoroutineContext.Key<KotlinMultiplatformPluginLifecycleCoroutineContextElement> = Key
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -77,6 +77,8 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
|
|||||||
|
|
||||||
checkGradleCompatibility()
|
checkGradleCompatibility()
|
||||||
|
|
||||||
|
project.startKotlinMultiplatformPluginLifecycle()
|
||||||
|
|
||||||
project.gradle.projectsEvaluated {
|
project.gradle.projectsEvaluated {
|
||||||
whenBuildEvaluated(project)
|
whenBuildEvaluated(project)
|
||||||
}
|
}
|
||||||
@@ -323,7 +325,6 @@ abstract class AbstractKotlinMultiplatformPluginWrapper : KotlinBasePluginWrappe
|
|||||||
|
|
||||||
override fun apply(project: Project) {
|
override fun apply(project: Project) {
|
||||||
super.apply(project)
|
super.apply(project)
|
||||||
project.startKotlinMultiplatformPluginLifecycle()
|
|
||||||
project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheckWhenAndroidIsApplied()
|
project.runMultiplatformAndroidGradlePluginCompatibilityHealthCheckWhenAndroidIsApplied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -214,12 +214,12 @@ internal fun applyUserDefinedAttributes(target: AbstractKotlinTarget) {
|
|||||||
// To copy the attributes to the output configurations, find those output configurations and their producing compilations
|
// To copy the attributes to the output configurations, find those output configurations and their producing compilations
|
||||||
// based on the target's components:
|
// based on the target's components:
|
||||||
val outputConfigurationsWithCompilations = target.kotlinComponents.filterIsInstance<KotlinVariant>().flatMap { kotlinVariant ->
|
val outputConfigurationsWithCompilations = target.kotlinComponents.filterIsInstance<KotlinVariant>().flatMap { kotlinVariant ->
|
||||||
kotlinVariant.usages.mapNotNull { usageContext ->
|
kotlinVariant.usages.mapNotNull { usageContext ->
|
||||||
project.configurations.findByName(usageContext.dependencyConfigurationName)?.let { configuration ->
|
project.configurations.findByName(usageContext.dependencyConfigurationName)?.let { configuration ->
|
||||||
configuration to usageContext.compilation
|
configuration to usageContext.compilation
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.toMutableList()
|
}
|
||||||
|
}.toMutableList()
|
||||||
|
|
||||||
val mainCompilation = target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
val mainCompilation = target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||||
val defaultTargetConfiguration = project.configurations.findByName(target.defaultConfigurationName)
|
val defaultTargetConfiguration = project.configurations.findByName(target.defaultConfigurationName)
|
||||||
|
|||||||
+1
-1
@@ -175,7 +175,7 @@ class KotlinMetadataTargetConfigurator :
|
|||||||
private fun createMetadataCompilationsForCommonSourceSets(
|
private fun createMetadataCompilationsForCommonSourceSets(
|
||||||
target: KotlinMetadataTarget,
|
target: KotlinMetadataTarget,
|
||||||
allMetadataJar: TaskProvider<out Jar>
|
allMetadataJar: TaskProvider<out Jar>
|
||||||
) = target.project.enqueue(KotlinMultiplatformPluginLifecycle.Stage.FinaliseCompilations) {
|
) = target.project.launch(KotlinMultiplatformPluginLifecycle.Stage.FinaliseCompilations) {
|
||||||
// Do this after all targets are configured by the user build script
|
// Do this after all targets are configured by the user build script
|
||||||
|
|
||||||
val publishedCommonSourceSets: Set<KotlinSourceSet> = getCommonSourceSetsForMetadataCompilation(project)
|
val publishedCommonSourceSets: Set<KotlinSourceSet> = getCommonSourceSetsForMetadataCompilation(project)
|
||||||
|
|||||||
+8
-7
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.KotlinTargetHierar
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.KotlinTargetHierarchy.Node
|
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.KotlinTargetHierarchy.Node
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.buildKotlinTargetHierarchy
|
import org.jetbrains.kotlin.gradle.plugin.mpp.targetHierarchy.buildKotlinTargetHierarchy
|
||||||
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
|
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
|
||||||
|
import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest
|
||||||
import org.jetbrains.kotlin.gradle.util.main
|
import org.jetbrains.kotlin.gradle.util.main
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
@@ -24,7 +25,7 @@ class KotlinTargetHierarchyDescriptorTest {
|
|||||||
private val kotlin = project.multiplatformExtension
|
private val kotlin = project.multiplatformExtension
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - simple descriptor`() {
|
fun `test - simple descriptor`() = project.runLifecycleAwareTest {
|
||||||
val descriptor = KotlinTargetHierarchyDescriptor {
|
val descriptor = KotlinTargetHierarchyDescriptor {
|
||||||
common {
|
common {
|
||||||
group("groupA") { withCompilations { it.target.name == "a" } }
|
group("groupA") { withCompilations { it.target.name == "a" } }
|
||||||
@@ -61,7 +62,7 @@ class KotlinTargetHierarchyDescriptorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - extend`() {
|
fun `test - extend`() = project.runLifecycleAwareTest {
|
||||||
val descriptor = KotlinTargetHierarchyDescriptor { group("base") }.extend {
|
val descriptor = KotlinTargetHierarchyDescriptor { group("base") }.extend {
|
||||||
group("base") {
|
group("base") {
|
||||||
group("extension") {
|
group("extension") {
|
||||||
@@ -82,7 +83,7 @@ class KotlinTargetHierarchyDescriptorTest {
|
|||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - extend - with new root`() {
|
fun `test - extend - with new root`() = project.runLifecycleAwareTest {
|
||||||
val descriptor = KotlinTargetHierarchyDescriptor { group("base") }.extend {
|
val descriptor = KotlinTargetHierarchyDescriptor { group("base") }.extend {
|
||||||
group("newRoot") {
|
group("newRoot") {
|
||||||
group("base") {
|
group("base") {
|
||||||
@@ -107,7 +108,7 @@ class KotlinTargetHierarchyDescriptorTest {
|
|||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - extend - with two new roots and two extensions`() {
|
fun `test - extend - with two new roots and two extensions`() = project.runLifecycleAwareTest {
|
||||||
val descriptor = KotlinTargetHierarchyDescriptor { group("base") }
|
val descriptor = KotlinTargetHierarchyDescriptor { group("base") }
|
||||||
.extend {
|
.extend {
|
||||||
group("newRoot1") {
|
group("newRoot1") {
|
||||||
@@ -163,7 +164,7 @@ class KotlinTargetHierarchyDescriptorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - cycle`() {
|
fun `test - cycle`() = project.runLifecycleAwareTest {
|
||||||
val descriptor = KotlinTargetHierarchyDescriptor {
|
val descriptor = KotlinTargetHierarchyDescriptor {
|
||||||
group("x") { // decoy 1
|
group("x") { // decoy 1
|
||||||
group("a") {
|
group("a") {
|
||||||
@@ -193,7 +194,7 @@ class KotlinTargetHierarchyDescriptorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - filterCompilations`() {
|
fun `test - filterCompilations`() = project.runLifecycleAwareTest {
|
||||||
val descriptor = KotlinTargetHierarchyDescriptor {
|
val descriptor = KotlinTargetHierarchyDescriptor {
|
||||||
filterCompilations { it.name in setOf("a", "b") }
|
filterCompilations { it.name in setOf("a", "b") }
|
||||||
common {
|
common {
|
||||||
@@ -223,7 +224,7 @@ class KotlinTargetHierarchyDescriptorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - filterCompilations - include them again`() {
|
fun `test - filterCompilations - include them again`() = project.runLifecycleAwareTest {
|
||||||
val descriptor = KotlinTargetHierarchyDescriptor {
|
val descriptor = KotlinTargetHierarchyDescriptor {
|
||||||
withCompilations { true }
|
withCompilations { true }
|
||||||
filterCompilations { it.name == "a" }
|
filterCompilations { it.name == "a" }
|
||||||
|
|||||||
+1
-1
@@ -183,7 +183,7 @@ class KotlinTargetHierarchyDslTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - hierarchy default - is only applied to main and test compilations`() {
|
fun `test - hierarchy default - is only applied to main and test compilations`() = project.runLifecycleAwareTest {
|
||||||
assertNotNull(defaultKotlinTargetHierarchy.buildKotlinTargetHierarchy(kotlin.linuxX64().compilations.main))
|
assertNotNull(defaultKotlinTargetHierarchy.buildKotlinTargetHierarchy(kotlin.linuxX64().compilations.main))
|
||||||
assertNotNull(defaultKotlinTargetHierarchy.buildKotlinTargetHierarchy(kotlin.linuxX64().compilations.test))
|
assertNotNull(defaultKotlinTargetHierarchy.buildKotlinTargetHierarchy(kotlin.linuxX64().compilations.test))
|
||||||
assertNull(defaultKotlinTargetHierarchy.buildKotlinTargetHierarchy(kotlin.linuxX64().compilations.maybeCreate("custom")))
|
assertNull(defaultKotlinTargetHierarchy.buildKotlinTargetHierarchy(kotlin.linuxX64().compilations.maybeCreate("custom")))
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.jetbrains.kotlin.gradle.plugin.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginLifecycle.Stage.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.awaitFinalValue
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.currentMultiplatformPluginLifecycle
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.launch
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.newLifecycleAwareProperty
|
||||||
|
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
|
||||||
|
import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.newProperty
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class LifecycleAwarePropertyTest {
|
||||||
|
private val project = buildProjectWithMPP()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - awaitFinalValue`() = project.runLifecycleAwareTest {
|
||||||
|
val property by project.newLifecycleAwareProperty<Int>(AfterFinaliseRefinesEdges)
|
||||||
|
assertTrue(property.isLifecycleAware())
|
||||||
|
|
||||||
|
launch(BeforeFinaliseRefinesEdges) {
|
||||||
|
property.set(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
launch(FinaliseRefinesEdges) {
|
||||||
|
assertEquals(1, property.get())
|
||||||
|
property.set(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(Configure, currentMultiplatformPluginLifecycle().stage)
|
||||||
|
assertEquals(2, property.awaitFinalValue())
|
||||||
|
assertEquals(AfterFinaliseRefinesEdges, currentMultiplatformPluginLifecycle().stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - awaitFinalValue - on non lifecycle aware property`() = project.runLifecycleAwareTest {
|
||||||
|
val property = project.newProperty<String>()
|
||||||
|
assertFalse(property.isLifecycleAware())
|
||||||
|
assertFailsWith<IllegalArgumentException> { property.awaitFinalValue() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - changing value after finalized`() = project.runLifecycleAwareTest {
|
||||||
|
val property by project.newLifecycleAwareProperty<Int>(AfterEvaluate)
|
||||||
|
property.set(1)
|
||||||
|
|
||||||
|
launch(AfterEvaluate) {
|
||||||
|
assertFailsWith<IllegalStateException> { property.set(2) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* 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.util
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.internal.project.ProjectInternal
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.kotlinMultiplatformPluginLifecycle
|
||||||
|
|
||||||
|
fun Project.runLifecycleAwareTest(block: suspend Project.() -> Unit) {
|
||||||
|
kotlinMultiplatformPluginLifecycle.launch { block() }
|
||||||
|
(this as ProjectInternal).evaluate()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user