Draft
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt
index 7ccff51..f9e8e9e 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt
@@ -25,10 +25,10 @@
override val presets: NamedDomainObjectCollection<KotlinTargetPreset<*>> = project.container(KotlinTargetPreset::class.java)
final override val targets: NamedDomainObjectCollection<KotlinTarget> = project.container(KotlinTarget::class.java)
+ internal val targetsState = project.suspendableProperty(targets)
internal suspend fun awaitTargets(): NamedDomainObjectCollection<KotlinTarget> {
- AfterFinaliseDsl.await()
- return targets
+ return targetsState.awaitFinalValue()
}
override val compilerTypeFromProperties: KotlinJsCompilerType? = project.kotlinPropertiesProvider.jsCompiler
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ConsistentAfterEvaluate.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ConsistentAfterEvaluate.kt
new file mode 100644
index 0000000..b1a70ed
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ConsistentAfterEvaluate.kt
@@ -0,0 +1,150 @@
+/*
+ * 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
+
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.completeWith
+import org.gradle.api.Project
+import org.gradle.api.provider.Provider
+import org.jetbrains.kotlin.gradle.utils.getOrPut
+import kotlin.coroutines.*
+
+internal class SuspendableExecutor {
+ private val supervisorJob = SupervisorJob()
+ private val lateEvaluations = mutableListOf<suspend () -> Unit>()
+ fun runNow(block: suspend () -> Unit) {
+ val job = Job(supervisorJob)
+ val continuation = Continuation<Unit>(job) { it.getOrThrow(); job.complete() }
+ block.startCoroutine(continuation)
+ }
+
+ fun runLater(block: suspend () -> Unit) {
+ lateEvaluations += block
+ }
+
+ fun runDeferredEvaluations() {
+ try {
+ while (lateEvaluations.isNotEmpty()) {
+ val code = lateEvaluations.removeFirst()
+ runNow { code() }
+ }
+ supervisorJob.complete()
+ } catch (e: Throwable) {
+ supervisorJob.completeExceptionally(e)
+ }
+
+ check(supervisorJob.children.all { it.isCompleted }) {
+ "Following children are not completed: ${supervisorJob.children.filter { it.isActive }.toList()}"
+ }
+ }
+}
+
+internal interface SuspendableState<T> {
+ fun getFinalValueOrThrow(): T
+ suspend fun awaitFinalValue(): T
+}
+
+private class SuspendableStateImpl<T> : SuspendableState<T> {
+ private val deferred = CompletableDeferred<T>()
+ fun completeWith(result: Result<T>) {
+ deferred.completeWith(result)
+ }
+
+ override fun getFinalValueOrThrow(): T {
+ val exception = deferred.getCompletionExceptionOrNull()
+ if (exception != null) throw exception
+ return deferred.getCompleted()
+ }
+
+ override suspend fun awaitFinalValue(): T = deferred.await()
+}
+
+private fun <T> SuspendableExecutor.evaluate(code: suspend () -> T): SuspendableState<T> {
+ val provider = SuspendableStateImpl<T>()
+ runNow { provider.completeWith(runCatching { code() }) }
+ return provider
+}
+
+internal interface SuspendableMutableState<T> : SuspendableState<T> {
+ fun updateWith(code: suspend (currentValue: T) -> T)
+}
+
+private fun <T> SuspendableExecutor.mutableState(initialValue: T): SuspendableMutableState<T> {
+ val property = SuspendableMutableStateImpl(initialValue)
+ runLater { property.finalizeValue() }
+ return property
+}
+
+private class SuspendableMutableStateImpl<T>(
+ private val initialValue: T,
+ private val state: SuspendableStateImpl<T> = SuspendableStateImpl()
+): SuspendableMutableState<T> {
+ private val mutations: MutableList<suspend (T) -> T> = mutableListOf()
+
+ suspend fun finalizeValue() {
+ val finalResult = runCatching {
+ mutations.fold(initialValue) { currentValue, mutation -> mutation(currentValue) }
+ }
+ state.completeWith(finalResult)
+ }
+
+ override fun updateWith(code: suspend (currentValue: T) -> T) {
+ mutations += code
+ }
+
+ override suspend fun awaitFinalValue(): T = state.awaitFinalValue()
+
+ override fun getFinalValueOrThrow(): T = state.getFinalValueOrThrow()
+}
+
+private val Project.suspendableExecutor get() =
+ extraProperties.getOrPut(SuspendableExecutor::class.java.name) {
+ SuspendableExecutor()
+ }
+
+internal fun <T> Project.provider(code: suspend () -> T): Provider<T> {
+ val suspendableState = suspendableExecutor.evaluate(code)
+ return provider { suspendableState.getFinalValueOrThrow() }
+}
+
+internal fun <T> Project.suspendableProperty(initialValue: T): SuspendableMutableState<T> {
+ val suspendableState = suspendableExecutor.mutableState(initialValue)
+ return suspendableState
+}
+
+internal class SuspendableWrappers(
+ private val executor: SuspendableExecutor
+) {
+ private val entities = mutableMapOf<Any, WrappedEntity<*>>()
+ class WrappedEntity<T: Any> (
+ val state: SuspendableMutableState<T>,
+ val entity: T
+ )
+
+ fun <T: Any> getOrWrap(entity: T): WrappedEntity<T> {
+ @Suppress("UNCHECKED_CAST")
+ return entities.getOrPut(entity) {
+ val state = executor.mutableState(entity)
+ WrappedEntity(state, entity)
+ } as WrappedEntity<T>
+ }
+}
+
+fun main() {
+ val evaluator = SuspendableExecutor()
+ val p1 = evaluator.mutableState(emptyList<Int>())
+ val p2 = evaluator.mutableState(emptyList<Int>())
+ val p3 = evaluator.mutableState(emptyList<Int>())
+ val p0 = evaluator.evaluate { p1.awaitFinalValue() }
+ p1.updateWith { it + p2.awaitFinalValue() + 1 }
+ p2.updateWith { it + p3.awaitFinalValue() + 2 }
+ p3.updateWith { it + 3 }
+
+ evaluator.runDeferredEvaluations()
+ println(p0.getFinalValueOrThrow())
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt
index d152174..13848b0 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt
@@ -65,9 +65,9 @@
*
* If the lifecycle already finished and Gradle moved to its execution phase, then the block will be invoked right away.
*/
-internal fun Project.launch(block: suspend KotlinPluginLifecycle.() -> Unit) {
- kotlinPluginLifecycle.launch(block)
-}
+//internal fun Project.launch(block: suspend KotlinPluginLifecycle.() -> Unit) {
+// kotlinPluginLifecycle.launch(block)
+//}
/**
* See [launch] and [launchInRequiredStage]
@@ -76,12 +76,12 @@
* @param block Is guaranteed to be executed *not before* [stage]. However, when this function is called in a higher stage then specified
* the [block] will still be launched.
*/
-internal fun Project.launchInStage(stage: Stage, block: suspend KotlinPluginLifecycle.() -> Unit) {
- launch {
- await(stage)
- block()
- }
-}
+//internal fun Project.launchInStage(stage: Stage, block: suspend KotlinPluginLifecycle.() -> Unit) {
+// launch {
+// await(stage)
+// block()
+// }
+//}
/**
* See also [launch]
@@ -98,13 +98,13 @@
* }
* ```
*/
-internal fun Project.launchInRequiredStage(stage: Stage, block: suspend KotlinPluginLifecycle.() -> Unit) {
- launchInStage(stage) {
- requiredStage(stage) {
- block()
- }
- }
-}
+//internal fun Project.launchInRequiredStage(stage: Stage, block: suspend KotlinPluginLifecycle.() -> Unit) {
+// launchInStage(stage) {
+// requiredStage(stage) {
+// block()
+// }
+// }
+//}
/**
* Universal way of retrieving the current lifecycle
@@ -118,9 +118,9 @@
/**
* Will start the lifecycle, this shall be called before the [kotlinPluginLifecycle] is effectively used
*/
-internal fun Project.startKotlinPluginLifecycle() {
- (kotlinPluginLifecycle as KotlinPluginLifecycleImpl).start()
-}
+//internal fun Project.startKotlinPluginLifecycle() {
+// (kotlinPluginLifecycle as KotlinPluginLifecycleImpl).start()
+//}
/**
* Similar to [currentCoroutineContext]: Returns the current [KotlinPluginLifecycle] instance used to launch
@@ -135,9 +135,9 @@
* Suspends execution until we *at least* reached the specified [this@await]
* This will return right away if the specified [this@await] was already executed or we are currently executing the [this@await]
*/
-internal suspend fun Stage.await() {
- currentKotlinPluginLifecycle().await(this)
-}
+//internal suspend fun Stage.await() {
+// currentKotlinPluginLifecycle().await(this)
+//}
/**
* See [LifecycleAwareProperty]
@@ -154,18 +154,18 @@
* }
* ```
*/
-internal inline fun <reified T : Any> Project.newKotlinPluginLifecycleAwareProperty(
- finaliseIn: Stage = Stage.FinaliseDsl, initialValue: T? = null
-): LifecycleAwareProperty<T> {
- return kotlinPluginLifecycle.newLifecycleAwareProperty(T::class.java, finaliseIn, initialValue)
-}
+//internal inline fun <reified T : Any> Project.newKotlinPluginLifecycleAwareProperty(
+// finaliseIn: Stage = Stage.FinaliseDsl, initialValue: T? = null
+//): LifecycleAwareProperty<T> {
+// return kotlinPluginLifecycle.newLifecycleAwareProperty(T::class.java, finaliseIn, initialValue)
+//}
/**
* Will return the [LifecycleAwareProperty] instance if the given receiver was created by [newKotlinPluginLifecycleAwareProperty]
*/
-internal suspend fun <T : Any> Property<T>.findKotlinPluginLifecycleAwareProperty(): LifecycleAwareProperty<T>? {
- return (currentKotlinPluginLifecycle() as KotlinPluginLifecycleImpl).findLifecycleAwareProperty(this)
-}
+//internal suspend fun <T : Any> Property<T>.findKotlinPluginLifecycleAwareProperty(): LifecycleAwareProperty<T>? {
+// return (currentKotlinPluginLifecycle() as KotlinPluginLifecycleImpl).findLifecycleAwareProperty(this)
+//}
/**
* Will suspend until the property finalises its value and therefore a final value can returned.
@@ -175,32 +175,32 @@
* If a property was not created using 'newKotlinPluginLifecycleAwareProperty' then the execution
* will suspend until 'FinaliseDsl' and calls [Property.finalizeValue] before returnign the actual value
*/
-internal suspend fun <T : Any> Property<T>.awaitFinalValue(): T? {
- val lifecycleAwareProperty = findKotlinPluginLifecycleAwareProperty()
- if (lifecycleAwareProperty != null) {
- return lifecycleAwareProperty.awaitFinalValue()
- }
-
- Stage.FinaliseDsl.await()
- finalizeValue()
- return orNull
-}
+//internal suspend fun <T : Any> Property<T>.awaitFinalValue(): T? {
+// val lifecycleAwareProperty = findKotlinPluginLifecycleAwareProperty()
+// if (lifecycleAwareProperty != null) {
+// return lifecycleAwareProperty.awaitFinalValue()
+// }
+//
+// Stage.FinaliseDsl.await()
+// finalizeValue()
+// return orNull
+//}
/**
* @return true if this property has an associated [LifecycleAwareProperty]
*/
-internal suspend fun Property<*>.isKotlinPluginLifecycleAware(): Boolean {
- return findKotlinPluginLifecycleAwareProperty() != null
-}
+//internal suspend fun Property<*>.isKotlinPluginLifecycleAware(): Boolean {
+// return findKotlinPluginLifecycleAwareProperty() != null
+//}
/**
* See also [withRestrictedStages]
*
* Will ensure that the given [block] can only execute in the given [stage]
*/
-internal suspend fun <T> requiredStage(stage: Stage, block: suspend () -> T): T {
- return withRestrictedStages(hashSetOf(stage), block)
-}
+//internal suspend fun <T> requiredStage(stage: Stage, block: suspend () -> T): T {
+// return withRestrictedStages(hashSetOf(stage), block)
+//}
/**
* See also [withRestrictedStages]
@@ -216,9 +216,9 @@
* }
* ```
*/
-internal suspend fun <T> requireCurrentStage(block: suspend () -> T): T {
- return requiredStage(currentKotlinPluginLifecycle().stage, block)
-}
+//internal suspend fun <T> requireCurrentStage(block: suspend () -> T): T {
+// return requiredStage(currentKotlinPluginLifecycle().stage, block)
+//}
/**
* Will ensure that the given [block] cannot leave the specified allowed stages [allowed]
@@ -233,11 +233,11 @@
* }
* ```
*/
-internal suspend fun <T> withRestrictedStages(allowed: Set<Stage>, block: suspend () -> T): T {
- return withContext(RestrictedLifecycleStages(currentKotlinPluginLifecycle(), allowed)) {
- block()
- }
-}
+//internal suspend fun <T> withRestrictedStages(allowed: Set<Stage>, block: suspend () -> T): T {
+// return withContext(RestrictedLifecycleStages(currentKotlinPluginLifecycle(), allowed)) {
+// block()
+// }
+//}
/*
Definition of the Lifecycle and its stages
@@ -476,7 +476,7 @@
) : LifecycleAwareProperty<T> {
override suspend fun awaitFinalValue(): T? {
- finaliseIn.await()
+ //finaliseIn.await()
return property.orNull
}
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt
index 9329a46..614b43d 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt
@@ -6,9 +6,12 @@
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
package org.jetbrains.kotlin.gradle.utils
+import org.gradle.api.InvalidUserCodeException
import org.gradle.api.Project
import org.gradle.api.artifacts.repositories.ArtifactRepository
import org.gradle.api.file.FileTree
+import org.gradle.api.initialization.resolve.RepositoriesMode
+import org.gradle.api.internal.GradleInternal
import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.compilerRunner.KotlinNativeToolRunner
import org.jetbrains.kotlin.compilerRunner.konanHome
@@ -87,14 +90,19 @@
}
private fun setupRepo(repoUrl: String): ArtifactRepository {
- return project.repositories.ivy { repo ->
- repo.setUrl(repoUrl)
- repo.patternLayout {
- it.artifact("[artifact]-[revision].[ext]")
+ try {
+ return project.repositories.ivy { repo ->
+ repo.setUrl(repoUrl)
+ repo.patternLayout {
+ it.artifact("[artifact]-[revision].[ext]")
+ }
+ repo.metadataSources {
+ it.artifact()
+ }
}
- repo.metadataSources {
- it.artifact()
- }
+ } catch (e: InvalidUserCodeException) {
+ logger.error("e: Can't add Kotlin Native Distribution repository. Please add it yourself, default repository url: '$repoUrl'")
+ throw e
}
}