[Gradle] Extract publicationDelegate as Project Stored Property
Previously it was attached to RootSoftwareComponent which has heavy initialization work, for instance it creates new configurations upon creation. The `publicationDelegate` is used in `idOfRootModule` and should not trigger RootSoftwareComponent initialization. After the change `idOfRootModule` became cross-project safe. I.e. Project `foo` can call `idOfRootModule` on project `bar`. ^KT-62877 Verification Pending ^KTIJ-27374 Verification Pending
This commit is contained in:
committed by
Space Team
parent
6bb33cc8bc
commit
5607ae1bc3
+1
-9
@@ -338,15 +338,7 @@ private fun Project.collectAllProjectsData(): Map<String, GranularMetadataTransf
|
|||||||
This double deferral ensures that the value indeed is accessed as late as possible.
|
This double deferral ensures that the value indeed is accessed as late as possible.
|
||||||
Unwrapping the lazy before the buildscript is evaluated will fail with 'future not completed'
|
Unwrapping the lazy before the buildscript is evaluated will fail with 'future not completed'
|
||||||
*/
|
*/
|
||||||
val moduleId = if (currentProject.kotlinExtensionOrNull != null) currentProject.future {
|
val moduleId = currentProject.future { ModuleIds.idOfRootModuleSafe(currentProject) }.lenient
|
||||||
KotlinPluginLifecycle.Stage.AfterFinaliseDsl.await()
|
|
||||||
ModuleIds.idOfRootModule(currentProject)
|
|
||||||
}.lenient else CompletableFuture<Lazy<ModuleDependencyIdentifier>>().apply {
|
|
||||||
currentProject.whenEvaluated {
|
|
||||||
complete(lazy { ModuleIds.idOfRootModule(currentProject) })
|
|
||||||
}
|
|
||||||
}.map { it.value }.lenient
|
|
||||||
|
|
||||||
|
|
||||||
GranularMetadataTransformation.ProjectData(
|
GranularMetadataTransformation.ProjectData(
|
||||||
path = path,
|
path = path,
|
||||||
|
|||||||
+2
-3
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPro
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.await
|
import org.jetbrains.kotlin.gradle.plugin.await
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinUsageContext.PublishOnlyIf
|
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinUsageContext.PublishOnlyIf
|
||||||
import org.jetbrains.kotlin.gradle.targets.metadata.*
|
import org.jetbrains.kotlin.gradle.targets.metadata.*
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.*
|
||||||
import org.jetbrains.kotlin.gradle.utils.Future
|
import org.jetbrains.kotlin.gradle.utils.Future
|
||||||
import org.jetbrains.kotlin.gradle.utils.future
|
import org.jetbrains.kotlin.gradle.utils.future
|
||||||
import org.jetbrains.kotlin.gradle.utils.markResolvable
|
import org.jetbrains.kotlin.gradle.utils.markResolvable
|
||||||
@@ -136,9 +137,7 @@ abstract class KotlinSoftwareComponent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This property is declared in the parent type to allow the usages to reference it without forcing the subtypes to load,
|
val publicationDelegate: MavenPublication? get() = project.kotlinMultiplatformRootPublication.lenient.getOrNull()
|
||||||
// which is needed for compatibility with older Gradle versions
|
|
||||||
var publicationDelegate: MavenPublication? = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinSoftwareComponentWithCoordinatesAndPublication(project: Project, name: String, kotlinTargets: Iterable<KotlinTarget>) :
|
class KotlinSoftwareComponentWithCoordinatesAndPublication(project: Project, name: String, kotlinTargets: Iterable<KotlinTarget>) :
|
||||||
|
|||||||
+9
-4
@@ -12,13 +12,13 @@ import org.gradle.api.artifacts.component.ComponentIdentifier
|
|||||||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||||
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
||||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||||
import org.jetbrains.kotlin.gradle.utils.currentBuild
|
import org.jetbrains.kotlin.gradle.utils.currentBuild
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.future
|
||||||
|
|
||||||
internal object ModuleIds {
|
internal object ModuleIds {
|
||||||
fun fromDependency(dependency: Dependency): ModuleDependencyIdentifier = when (dependency) {
|
fun fromDependency(dependency: Dependency): ModuleDependencyIdentifier = when (dependency) {
|
||||||
is ProjectDependency -> idOfRootModule(dependency.dependencyProject)
|
is ProjectDependency -> @Suppress("DEPRECATION") idOfRootModule(dependency.dependencyProject)
|
||||||
else -> ModuleDependencyIdentifier(dependency.group, dependency.name)
|
else -> ModuleDependencyIdentifier(dependency.group, dependency.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,9 +39,13 @@ internal object ModuleIds {
|
|||||||
else
|
else
|
||||||
fromComponentId(thisProject, component.id)
|
fromComponentId(thisProject, component.id)
|
||||||
|
|
||||||
fun idOfRootModule(project: Project): ModuleDependencyIdentifier =
|
// TODO KT-62911: Replace unsafe idOfRootModule with suspendable version idRootModule
|
||||||
|
@Deprecated("Use suspendable version if possible", replaceWith = ReplaceWith("idOfRootModuleSafe(project)"))
|
||||||
|
fun idOfRootModule(project: Project): ModuleDependencyIdentifier = project.future { idOfRootModuleSafe(project) }.getOrThrow()
|
||||||
|
|
||||||
|
suspend fun idOfRootModuleSafe(project: Project): ModuleDependencyIdentifier =
|
||||||
if (project.multiplatformExtensionOrNull != null) {
|
if (project.multiplatformExtensionOrNull != null) {
|
||||||
val rootPublication = project.multiplatformExtension.rootSoftwareComponent.publicationDelegate
|
val rootPublication = project.kotlinMultiplatformRootPublication.await()
|
||||||
val group = rootPublication?.groupId ?: project.group.toString()
|
val group = rootPublication?.groupId ?: project.group.toString()
|
||||||
val name = rootPublication?.artifactId ?: project.name
|
val name = rootPublication?.artifactId ?: project.name
|
||||||
ModuleDependencyIdentifier(group, name)
|
ModuleDependencyIdentifier(group, name)
|
||||||
@@ -53,5 +57,6 @@ internal object ModuleIds {
|
|||||||
ModuleDependencyIdentifier(null, name)
|
ModuleDependencyIdentifier(null, name)
|
||||||
|
|
||||||
private fun idOfRootModuleByProjectPath(thisProject: Project, projectPath: String): ModuleDependencyIdentifier =
|
private fun idOfRootModuleByProjectPath(thisProject: Project, projectPath: String): ModuleDependencyIdentifier =
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
idOfRootModule(thisProject.project(projectPath))
|
idOfRootModule(thisProject.project(projectPath))
|
||||||
}
|
}
|
||||||
+25
-11
@@ -26,31 +26,45 @@ import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||||
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
||||||
import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask
|
import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.CompletableFuture
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.Future
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.projectStoredProperty
|
||||||
import org.jetbrains.kotlin.gradle.utils.whenEvaluated
|
import org.jetbrains.kotlin.gradle.utils.whenEvaluated
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.withPluginId
|
||||||
|
|
||||||
|
private val Project.completableFutureForKotlinMultiplatformRootPublication: CompletableFuture<MavenPublication?>
|
||||||
|
by projectStoredProperty { CompletableFuture() }
|
||||||
|
internal val Project.kotlinMultiplatformRootPublication: Future<MavenPublication?>
|
||||||
|
get() = completableFutureForKotlinMultiplatformRootPublication
|
||||||
|
|
||||||
internal val MultiplatformPublishingSetupAction = KotlinProjectSetupAction {
|
internal val MultiplatformPublishingSetupAction = KotlinProjectSetupAction {
|
||||||
project.pluginManager.withPlugin("maven-publish") {
|
project.withPluginId(
|
||||||
if (project.kotlinPropertiesProvider.createDefaultMultiplatformPublications) {
|
pluginId = "maven-publish",
|
||||||
project.extensions.configure(PublishingExtension::class.java) { publishing ->
|
whenApplied = {
|
||||||
createRootPublication(project, publishing)
|
if (project.kotlinPropertiesProvider.createDefaultMultiplatformPublications) {
|
||||||
createTargetPublications(project, publishing)
|
project.extensions.configure(PublishingExtension::class.java) { publishing ->
|
||||||
|
createRootPublication(project, publishing).also(completableFutureForKotlinMultiplatformRootPublication::complete)
|
||||||
|
createTargetPublications(project, publishing)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completableFutureForKotlinMultiplatformRootPublication.complete(null)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
project.components.add(project.multiplatformExtension.rootSoftwareComponent)
|
project.components.add(project.multiplatformExtension.rootSoftwareComponent)
|
||||||
}
|
},
|
||||||
|
whenNotApplied = { completableFutureForKotlinMultiplatformRootPublication.complete(null) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root publication that references the platform specific publications as its variants
|
* The root publication that references the platform specific publications as its variants
|
||||||
*/
|
*/
|
||||||
private fun createRootPublication(project: Project, publishing: PublishingExtension) {
|
private fun createRootPublication(project: Project, publishing: PublishingExtension): MavenPublication {
|
||||||
val kotlinSoftwareComponent = project.multiplatformExtension.rootSoftwareComponent
|
val kotlinSoftwareComponent = project.multiplatformExtension.rootSoftwareComponent
|
||||||
|
|
||||||
publishing.publications.create("kotlinMultiplatform", MavenPublication::class.java).apply {
|
return publishing.publications.create("kotlinMultiplatform", MavenPublication::class.java).apply {
|
||||||
from(kotlinSoftwareComponent)
|
from(kotlinSoftwareComponent)
|
||||||
(this as MavenPublicationInternal).publishWithOriginalFileName()
|
(this as MavenPublicationInternal).publishWithOriginalFileName()
|
||||||
kotlinSoftwareComponent.publicationDelegate = this@apply
|
|
||||||
|
|
||||||
addKotlinToolingMetadataArtifactIfNeeded(project)
|
addKotlinToolingMetadataArtifactIfNeeded(project)
|
||||||
}
|
}
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.utils
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterEvaluateBuildscript
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.launchInStage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the given block of code if the Gradle Plugin with [pluginId] is applied to the project. Otherwise,
|
||||||
|
* executes another block of code.
|
||||||
|
*/
|
||||||
|
internal fun <T> Project.withPluginId(
|
||||||
|
pluginId: String,
|
||||||
|
whenApplied: () -> T,
|
||||||
|
whenNotApplied: () -> T,
|
||||||
|
): Future<T> {
|
||||||
|
val result = CompletableFuture<T>()
|
||||||
|
pluginManager.withPlugin(pluginId) { result.complete(whenApplied()) }
|
||||||
|
// All plugins must be applied during evaluation of build script
|
||||||
|
launchInStage(AfterEvaluateBuildscript) { if (!result.isCompleted) result.complete(whenNotApplied()) }
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterEvaluateBuildscript
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.currentKotlinPluginLifecycle
|
||||||
|
import org.jetbrains.kotlin.gradle.util.buildProject
|
||||||
|
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
|
||||||
|
import org.jetbrains.kotlin.gradle.util.kotlin
|
||||||
|
import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.withPluginId
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class PluginManagerUtilTest {
|
||||||
|
|
||||||
|
private fun buildSampleProject(action: Project.() -> Unit = {}) = buildProjectWithMPP {
|
||||||
|
action()
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
linuxX64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - withPluginId - when plugin applied`() {
|
||||||
|
val project = buildProject {
|
||||||
|
plugins.apply("maven-publish")
|
||||||
|
}
|
||||||
|
val future = project.withPluginId(
|
||||||
|
pluginId = "maven-publish",
|
||||||
|
whenApplied = { true },
|
||||||
|
whenNotApplied = { false }
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(future.getOrThrow())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - withPluginId - call withPluginId before plugin is applied`() {
|
||||||
|
val project = buildProject {}
|
||||||
|
val future = project.withPluginId(
|
||||||
|
pluginId = "maven-publish",
|
||||||
|
whenApplied = { true },
|
||||||
|
whenNotApplied = { false }
|
||||||
|
)
|
||||||
|
project.plugins.apply("maven-publish")
|
||||||
|
|
||||||
|
assertTrue(future.getOrThrow())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - withPluginId - plugin not applied`() {
|
||||||
|
val project = buildSampleProject()
|
||||||
|
|
||||||
|
val future = project.withPluginId(
|
||||||
|
pluginId = "some-plugin-id",
|
||||||
|
whenApplied = { false },
|
||||||
|
whenNotApplied = { true },
|
||||||
|
)
|
||||||
|
|
||||||
|
project.runLifecycleAwareTest {
|
||||||
|
assertTrue(future.await())
|
||||||
|
val currentStage = currentKotlinPluginLifecycle().stage
|
||||||
|
assertTrue(currentStage <= AfterEvaluateBuildscript)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user