[Gradle] Future: Support Gradle Configuration Cache

^KT-34662 Verification Pending
This commit is contained in:
Sebastian Sellmair
2023-03-14 11:43:21 +01:00
committed by Space Team
parent ea48b52d43
commit eb9936397b
3 changed files with 93 additions and 10 deletions
@@ -17,10 +17,7 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets.MetadataProvider.ArtifactMetadataProvider
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.utils.Future
import org.jetbrains.kotlin.gradle.utils.LazyResolvedConfiguration
import org.jetbrains.kotlin.gradle.utils.future
import org.jetbrains.kotlin.gradle.utils.getOrPut
import org.jetbrains.kotlin.gradle.utils.*
import java.util.*
internal sealed class MetadataDependencyResolution(
@@ -116,8 +113,8 @@ internal class GranularMetadataTransformation(
class ProjectData(
val path: String,
val sourceSetMetadataOutputs: Future<Map<String, SourceSetMetadataOutputs>>,
val moduleId: Future<ModuleDependencyIdentifier>
val sourceSetMetadataOutputs: LenientFuture<Map<String, SourceSetMetadataOutputs>>,
val moduleId: LenientFuture<ModuleDependencyIdentifier>
) {
override fun toString(): String = "ProjectData[path='$path']"
}
@@ -339,11 +336,11 @@ private fun Project.collectAllProjectsData(): Map<String, GranularMetadataTransf
return rootProject.allprojects.associateBy { it.path }.mapValues { (path, currentProject) ->
GranularMetadataTransformation.ProjectData(
path = path,
sourceSetMetadataOutputs = currentProject.future { currentProject.collectSourceSetMetadataOutputs() },
sourceSetMetadataOutputs = currentProject.future { currentProject.collectSourceSetMetadataOutputs() }.lenient,
moduleId = currentProject.future {
await(KotlinPluginLifecycle.Stage.AfterFinaliseDsl)
ModuleIds.idOfRootModule(currentProject)
}
}.lenient
)
}
}
@@ -47,6 +47,12 @@ internal interface Future<T> {
fun getOrThrow(): T
}
internal interface LenientFuture<T> : Future<T?> {
override suspend fun await(): T
override fun getOrThrow(): T
fun getOrNull(): T?
}
internal interface CompletableFuture<T> : Future<T> {
fun complete(value: T)
}
@@ -69,6 +75,8 @@ internal inline fun <Receiver, reified T> futureExtension(
internal fun <T> Project.future(block: suspend Project.() -> T): Future<T> = kotlinPluginLifecycle.future { block() }
internal val <T> Future<T>.lenient: LenientFuture<T> get() = LenientFutureImpl(this)
/**
* Shortcut for
* ```kotlin
@@ -106,7 +114,48 @@ private class FutureImpl<T>(
override fun getOrThrow(): T {
return if (deferred.isCompleted) deferred.getCompleted() else throw IllegalLifecycleException(
"Future was not completed yet" + if (lifecycle != null) " (stage '${lifecycle.stage}')" else ""
"Future was not completed yet" + if (lifecycle != null) " (stage '${lifecycle.stage}') (${lifecycle.project.displayName})"
else ""
)
}
private fun writeReplace(): Any {
return Surrogate(getOrThrow())
}
private class Surrogate<T>(private val value: T) : Serializable {
private fun readResolve(): Any {
return FutureImpl(CompletableDeferred(value))
}
}
}
private class LenientFutureImpl<T>(
private val future: Future<T>
) : LenientFuture<T>, Serializable {
override suspend fun await(): T {
return future.await()
}
override fun getOrThrow(): T {
return future.getOrThrow()
}
override fun getOrNull(): T? {
return try {
future.getOrThrow()
} catch (t: IllegalLifecycleException) {
return null
}
}
private fun writeReplace(): Any {
return Surrogate(getOrNull())
}
private class Surrogate<T>(private val value: T) : Serializable {
private fun readResolve(): Any {
return LenientFutureImpl(FutureImpl(CompletableDeferred(value)))
}
}
}
@@ -7,6 +7,8 @@
package org.jetbrains.kotlin.gradle.unitTests
import org.jetbrains.kotlin.gradle.idea.testFixtures.utils.deserialize
import org.jetbrains.kotlin.gradle.idea.testFixtures.utils.serialize
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.IllegalLifecycleException
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.FinaliseDsl
import org.jetbrains.kotlin.gradle.plugin.await
@@ -14,10 +16,15 @@ import org.jetbrains.kotlin.gradle.plugin.currentKotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.startKotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.util.buildProject
import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest
import org.jetbrains.kotlin.gradle.utils.CompletableFuture
import org.jetbrains.kotlin.gradle.utils.LenientFuture
import org.jetbrains.kotlin.gradle.utils.future
import org.jetbrains.kotlin.gradle.utils.lenient
import org.junit.Test
import org.junit.jupiter.api.assertThrows
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNull
class FutureTest {
@@ -67,4 +74,34 @@ class FutureTest {
assertEquals(42, future.getOrThrow())
}
}
@Test
fun `test - lenient future`() {
val future = CompletableFuture<Int>()
assertNull(future.lenient.getOrNull())
assertThrows<IllegalLifecycleException> { future.lenient.getOrThrow() }
future.complete(42)
assertEquals(42, future.lenient.getOrThrow())
assertEquals(42, future.lenient.getOrNull())
}
@Test
fun `test - lenient future serialize`() {
val future = CompletableFuture<Int>()
assertFailsWith<IllegalLifecycleException> { future.serialize() }
run {
val futureBinary = future.lenient.serialize()
val deserializedFuture = futureBinary.deserialize() as LenientFuture<*>
assertNull(deserializedFuture.getOrNull())
}
run {
future.complete(42)
val futureBinary = future.lenient.serialize()
val deserializedFuture = futureBinary.deserialize() as LenientFuture<*>
assertEquals(42, deserializedFuture.getOrNull())
}
}
}