From ea48b52d43c6453edbd92f455125851c92bf7f02 Mon Sep 17 00:00:00 2001 From: Sebastian Sellmair Date: Mon, 13 Mar 2023 22:36:08 +0100 Subject: [PATCH] [Gradle] GranularMetadataTransformation: ProjectData: Use Future instead of lambda ^KT-34662 Verification Pending --- .../gradle/plugin/KotlinPluginLifecycle.kt | 5 ++-- .../gradle/plugin/KotlinPluginWrapper.kt | 4 +-- .../mpp/GranularMetadataTransformation.kt | 28 +++++++++---------- .../plugin/mpp/ProjectMetadataProviderImpl.kt | 16 +++++------ .../KotlinSourceSetMetadataTransformation.kt | 4 --- .../jetbrains/kotlin/gradle/utils/Future.kt | 9 ++++-- 6 files changed, 31 insertions(+), 35 deletions(-) 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 ed97be4876d..53217998df8 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 @@ -387,6 +387,8 @@ private class KotlinPluginLifecycleImpl(override val project: Project) : KotlinP "${KotlinPluginLifecycle::class.java.name} cannot be started in ProjectState '${project.state}'" } + loopIfNecessary() + project.whenEvaluated { assert(enqueuedActions.getValue(stage).isEmpty()) { "Expected empty queue from '$stage'" } stage = stage.nextOrThrow @@ -445,14 +447,13 @@ private class KotlinPluginLifecycleImpl(override val project: Project) : KotlinP enqueuedActions.getValue(stage).addLast(action) - if (stage == Stage.Configure) { + if (stage == Stage.Configure && isStarted.get()) { loopIfNecessary() } } override fun launch(block: suspend KotlinPluginLifecycle.() -> Unit) { val lifecycle = this - check(isStarted.get()) { "Cannot launch when ${KotlinPluginLifecycle::class.simpleName} is not started" } val coroutine = block.createCoroutine(this, object : Continuation { override val context: CoroutineContext = EmptyCoroutineContext + diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index 26234edc9d6..a8f76242dd8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -77,8 +77,6 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin { checkGradleCompatibility() - project.startKotlinPluginLifecycle() - project.gradle.projectsEvaluated { whenBuildEvaluated(project) } @@ -233,6 +231,8 @@ abstract class KotlinBasePluginWrapper : DefaultKotlinBasePlugin() { project.addNpmDependencyExtension() project.registerBuildKotlinToolingMetadataTask() + + project.startKotlinPluginLifecycle() } internal open fun createTestRegistry(project: Project) = KotlinTestsRegistry(project) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt index 3143f78b9a4..7f50ec78b99 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt @@ -14,12 +14,10 @@ import org.gradle.api.file.FileCollection import org.gradle.api.logging.Logging import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension -import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet -import org.jetbrains.kotlin.gradle.plugin.extraProperties +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 @@ -118,12 +116,9 @@ internal class GranularMetadataTransformation( class ProjectData( val path: String, - sourceSetMetadataOutputsProvider: () -> Map, - moduleIdProvider: () -> ModuleDependencyIdentifier + val sourceSetMetadataOutputs: Future>, + val moduleId: Future ) { - val sourceSetMetadataOutputs by lazy(sourceSetMetadataOutputsProvider) - val moduleId by lazy(moduleIdProvider) - override fun toString(): String = "ProjectData[path='$path']" } @@ -275,7 +270,7 @@ internal class GranularMetadataTransformation( val metadataProvider = when (mppDependencyMetadataExtractor) { is ProjectMppDependencyProjectStructureMetadataExtractor -> ProjectMetadataProvider( sourceSetMetadataOutputs = params.projectData[mppDependencyMetadataExtractor.projectPath]?.sourceSetMetadataOutputs - ?: error("Unexpected project path '${mppDependencyMetadataExtractor.projectPath}'") + ?.getOrThrow() ?: error("Unexpected project path '${mppDependencyMetadataExtractor.projectPath}'") ) is JarMppDependencyProjectStructureMetadataExtractor -> ArtifactMetadataProvider( @@ -308,7 +303,7 @@ internal class GranularMetadataTransformation( is ModuleComponentIdentifier -> ModuleDependencyIdentifier(componentId.group, componentId.module) is ProjectComponentIdentifier -> { if (componentId.build.isCurrentBuild) { - params.projectData[componentId.projectPath]?.moduleId + params.projectData[componentId.projectPath]?.moduleId?.getOrThrow() ?: error("Cant find project Module ID by ${componentId.projectPath}") } else { ModuleDependencyIdentifier( @@ -337,15 +332,18 @@ private val Project.allProjectsData: Map { - return rootProject.allprojects.associateBy { it.path }.mapValues { (path, subProject) -> + return rootProject.allprojects.associateBy { it.path }.mapValues { (path, currentProject) -> GranularMetadataTransformation.ProjectData( path = path, - sourceSetMetadataOutputsProvider = future { subProject.collectSourceSetMetadataOutputs() }::getOrThrow, - moduleIdProvider = { ModuleIds.idOfRootModule(subProject) } + sourceSetMetadataOutputs = currentProject.future { currentProject.collectSourceSetMetadataOutputs() }, + moduleId = currentProject.future { + await(KotlinPluginLifecycle.Stage.AfterFinaliseDsl) + ModuleIds.idOfRootModule(currentProject) + } ) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ProjectMetadataProviderImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ProjectMetadataProviderImpl.kt index 7827a3e1f5c..6d1b04cd06a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ProjectMetadataProviderImpl.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ProjectMetadataProviderImpl.kt @@ -9,8 +9,11 @@ import org.gradle.api.Project import org.gradle.api.file.FileCollection import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.await import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets.MetadataProvider.ProjectMetadataProvider +import org.jetbrains.kotlin.gradle.targets.metadata.findMetadataCompilation import org.jetbrains.kotlin.gradle.targets.native.internal.* private typealias SourceSetName = String @@ -33,7 +36,7 @@ internal class SourceSetMetadataOutputs( private class ProjectMetadataProviderImpl( private val sourceSetMetadataOutputs: Map -): ProjectMetadataProvider() { +) : ProjectMetadataProvider() { override fun getSourceSetCompiledMetadata(sourceSetName: String): FileCollection = sourceSetMetadataOutputs[sourceSetName]?.metadata ?: error("Unexpected source set '$sourceSetName'") @@ -63,16 +66,11 @@ internal suspend fun Project.collectSourceSetMetadataOutputs(): Map { - val commonTarget = metadata() - - val compilations = commonTarget.compilations +private suspend fun KotlinMultiplatformExtension.sourceSetsMetadataOutputs(): Map { + await(KotlinPluginLifecycle.Stage.AfterFinaliseDsl) return sourceSets.mapNotNull { sourceSet -> - val compilation = compilations.findByName(sourceSet.name) - ?: return@mapNotNull null // given source set is not shared - - val destination = when (compilation) { + val destination = when (val compilation = project.findMetadataCompilation(sourceSet) ?: return@mapNotNull null) { is KotlinCommonCompilation -> compilation.output.classesDirs is KotlinSharedNativeCompilation -> compilation.output.classesDirs else -> error("Unexpected compilation type: $compilation") diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/KotlinSourceSetMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/KotlinSourceSetMetadataTransformation.kt index ab09834d64b..65b1c6a3663 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/KotlinSourceSetMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/KotlinSourceSetMetadataTransformation.kt @@ -9,10 +9,6 @@ import org.gradle.api.Project import org.gradle.api.artifacts.Configuration import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.plugin.mpp.* -import org.jetbrains.kotlin.gradle.plugin.mpp.GranularMetadataTransformation -import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution -import org.jetbrains.kotlin.gradle.plugin.mpp.ModuleIds -import org.jetbrains.kotlin.gradle.plugin.mpp.projectDependency import org.jetbrains.kotlin.gradle.targets.metadata.dependsOnClosureWithInterCompilationDependencies import org.jetbrains.kotlin.tooling.core.extrasNullableLazyProperty diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/Future.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/Future.kt index 4a088c5f246..a316ef01f31 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/Future.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/Future.kt @@ -80,7 +80,7 @@ internal fun Project.future(block: suspend Project.() -> T): Future = kot internal fun Project.lazyFuture(block: suspend Project.() -> T): Lazy> = lazy { future(block) } internal fun KotlinPluginLifecycle.future(block: suspend () -> T): Future { - return FutureImpl(CompletableDeferred()).also { future -> + return FutureImpl(lifecycle = this).also { future -> launch { future.completeWith(runCatching { block() }) } } } @@ -90,7 +90,10 @@ internal fun CompletableFuture(): CompletableFuture { } @OptIn(ExperimentalCoroutinesApi::class) -private class FutureImpl(private val deferred: CompletableDeferred = CompletableDeferred()) : CompletableFuture, Serializable { +private class FutureImpl( + private val deferred: CompletableDeferred = CompletableDeferred(), + private val lifecycle: KotlinPluginLifecycle? = null +) : CompletableFuture, Serializable { fun completeWith(result: Result) = deferred.completeWith(result) override fun complete(value: T) { @@ -103,7 +106,7 @@ private class FutureImpl(private val deferred: CompletableDeferred = Compl override fun getOrThrow(): T { return if (deferred.isCompleted) deferred.getCompleted() else throw IllegalLifecycleException( - "Future was not completed yet" + "Future was not completed yet" + if (lifecycle != null) " (stage '${lifecycle.stage}')" else "" ) } }