KPM: reshape the API for setting up publications
Accept a more structured requests for setting up publication. Allow passing lower-level overrides for publication settings of a particular configuration, which is needed to set up legacy targets' publications in KPM.
This commit is contained in:
+100
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.mpp.pm20.util
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.*
|
||||||
|
import org.gradle.api.attributes.Attribute
|
||||||
|
import org.gradle.api.attributes.AttributeContainer
|
||||||
|
import org.gradle.api.capabilities.Capability
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations
|
||||||
|
|
||||||
|
internal fun copyConfigurationForPublishing(
|
||||||
|
project: Project,
|
||||||
|
newName: String,
|
||||||
|
configuration: Configuration,
|
||||||
|
overrideDependencies: (DependencySet.() -> Unit)? = null,
|
||||||
|
overrideArtifacts: (Configuration.(PublishArtifactSet) -> Unit)? = null,
|
||||||
|
overrideAttributes: (Configuration.(AttributeContainer) -> Unit)? = {
|
||||||
|
copyAttributes(it, attributes, it.keySet().minus(ProjectLocalConfigurations.ATTRIBUTE))
|
||||||
|
},
|
||||||
|
overrideCapabilities: (Configuration.(Collection<Capability>) -> Unit)? = null,
|
||||||
|
configureAction: Configuration.() -> Unit = { }
|
||||||
|
) = copyConfiguration(
|
||||||
|
project,
|
||||||
|
newName,
|
||||||
|
configuration,
|
||||||
|
overrideDependencies,
|
||||||
|
overrideArtifacts,
|
||||||
|
overrideAttributes,
|
||||||
|
overrideCapabilities,
|
||||||
|
configureAction = {
|
||||||
|
isCanBeConsumed = false
|
||||||
|
isCanBeResolved = false
|
||||||
|
configureAction()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun copyConfiguration(
|
||||||
|
project: Project,
|
||||||
|
newName: String,
|
||||||
|
configuration: Configuration,
|
||||||
|
overrideDependencies: (DependencySet.() -> Unit)? = null,
|
||||||
|
overrideArtifacts: (Configuration.(PublishArtifactSet) -> Unit)? = null,
|
||||||
|
overrideAttributes: (Configuration.(AttributeContainer) -> Unit)? = null,
|
||||||
|
overrideCapabilities: (Configuration.(Collection<Capability>) -> Unit)? = null,
|
||||||
|
configureAction: Configuration.() -> Unit = { }
|
||||||
|
): Configuration =
|
||||||
|
project.configurations.create(newName).apply {
|
||||||
|
isCanBeConsumed = configuration.isCanBeConsumed
|
||||||
|
isCanBeResolved = configuration.isCanBeResolved
|
||||||
|
|
||||||
|
// dependencies:
|
||||||
|
if (overrideDependencies != null) {
|
||||||
|
withDependencies { dependencySet ->
|
||||||
|
overrideDependencies(dependencySet)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dependencies.addAllLater(project.listProperty { configuration.allDependencies })
|
||||||
|
}
|
||||||
|
|
||||||
|
// artifacts:
|
||||||
|
if (overrideArtifacts != null) {
|
||||||
|
overrideArtifacts(this, artifacts)
|
||||||
|
} else {
|
||||||
|
artifacts.addAllLater(project.listProperty { configuration.allArtifacts })
|
||||||
|
}
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
if (overrideAttributes != null) {
|
||||||
|
overrideAttributes(this, attributes)
|
||||||
|
} else {
|
||||||
|
copyAttributes(configuration.attributes, attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// capabilities
|
||||||
|
if (overrideCapabilities != null) {
|
||||||
|
overrideCapabilities(this, configuration.outgoing.capabilities)
|
||||||
|
} else {
|
||||||
|
configuration.outgoing.capabilities.forEach(outgoing::capability)
|
||||||
|
}
|
||||||
|
|
||||||
|
configureAction(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun copyAttributes(from: AttributeContainer, to: AttributeContainer, keys: Iterable<Attribute<*>> = from.keySet()) {
|
||||||
|
// capture type argument T
|
||||||
|
fun <T : Any> copyOneAttribute(from: AttributeContainer, to: AttributeContainer, key: Attribute<T>) {
|
||||||
|
val value = checkNotNull(from.getAttribute(key))
|
||||||
|
to.attribute(key, value)
|
||||||
|
}
|
||||||
|
for (key in keys) {
|
||||||
|
copyOneAttribute(from, to, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified T> Project.listProperty(noinline itemsProvider: () -> Iterable<T>) =
|
||||||
|
objects.listProperty(T::class.java).apply { set(provider(itemsProvider)) }
|
||||||
+112
-37
@@ -14,12 +14,15 @@ import org.gradle.api.attributes.*
|
|||||||
import org.gradle.api.capabilities.Capability
|
import org.gradle.api.capabilities.Capability
|
||||||
import org.gradle.api.component.AdhocComponentWithVariants
|
import org.gradle.api.component.AdhocComponentWithVariants
|
||||||
import org.gradle.api.component.SoftwareComponentFactory
|
import org.gradle.api.component.SoftwareComponentFactory
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.publish.PublishingExtension
|
import org.gradle.api.publish.PublishingExtension
|
||||||
import org.gradle.api.publish.maven.MavenPublication
|
import org.gradle.api.publish.maven.MavenPublication
|
||||||
import org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication
|
import org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication
|
||||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
|
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyConfigurationForPublishing
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
|
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
|
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
|
||||||
import org.jetbrains.kotlin.gradle.plugin.usageByName
|
import org.jetbrains.kotlin.gradle.plugin.usageByName
|
||||||
@@ -28,17 +31,67 @@ import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
interface PlatformPublicationToMavenRequest {
|
||||||
|
val componentName: String
|
||||||
|
val fromModule: KotlinGradleModule
|
||||||
|
val publicationHolder: SingleMavenPublishedModuleHolder
|
||||||
|
val variantPublicationRequests: Iterable<VariantPublicationRequest>
|
||||||
|
}
|
||||||
|
|
||||||
|
data class BasicPlatformPublicationToMavenRequest(
|
||||||
|
override val componentName: String,
|
||||||
|
override val fromModule: KotlinGradleModule,
|
||||||
|
override val publicationHolder: SingleMavenPublishedModuleHolder,
|
||||||
|
override val variantPublicationRequests: Iterable<VariantPublicationRequest>
|
||||||
|
) : PlatformPublicationToMavenRequest {
|
||||||
|
init {
|
||||||
|
check(variantPublicationRequests.all { it.fromVariant.containingModule === fromModule }) {
|
||||||
|
"Variants for publication should all belong to the fromModule ($fromModule)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** TODO: consider also using this class for exposing a KPM variant's configurations for project-to-project dependencies,
|
||||||
|
* so that a variant may expose an arbitrary set of configurations rather just { API, runtime } or { API } */
|
||||||
|
interface VariantPublicationRequest {
|
||||||
|
val fromVariant: KotlinGradleVariant
|
||||||
|
val publishConfiguration: Configuration
|
||||||
|
}
|
||||||
|
|
||||||
|
data class BasicVariantPublicationRequest(
|
||||||
|
override val fromVariant: KotlinGradleVariant,
|
||||||
|
override val publishConfiguration: Configuration
|
||||||
|
) : VariantPublicationRequest
|
||||||
|
|
||||||
|
|
||||||
fun VariantPublishingConfigurator.configureNativeVariantPublication(variant: KotlinNativeVariantInternal) {
|
fun VariantPublishingConfigurator.configureNativeVariantPublication(variant: KotlinNativeVariantInternal) {
|
||||||
val publishConfigurations = listOfNotNull(
|
val publishConfigurations = listOfNotNull(
|
||||||
variant.apiElementsConfiguration.name,
|
variant.apiElementsConfiguration,
|
||||||
variant.hostSpecificMetadataElementsConfiguration?.name // host-specific metadata may be absent
|
variant.hostSpecificMetadataElementsConfiguration // host-specific metadata may be absent
|
||||||
)
|
)
|
||||||
configurePublishing(variant, variant, publishConfigurations)
|
configureSingleVariantPublishing(variant, variant, publishConfigurations)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VariantPublishingConfigurator.configureSingleVariantPublication(variant: KotlinGradlePublishedVariantWithRuntime) {
|
fun VariantPublishingConfigurator.configureSingleVariantPublication(variant: KotlinGradlePublishedVariantWithRuntime) {
|
||||||
val publishConfigurations = listOf(variant.apiElementsConfiguration.name, variant.runtimeElementsConfiguration.name)
|
val publishConfigurations = listOf(variant.apiElementsConfiguration, variant.runtimeElementsConfiguration)
|
||||||
configurePublishing(variant, variant, publishConfigurations)
|
configureSingleVariantPublishing(variant, variant, publishConfigurations)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun VariantPublishingConfigurator.configureSingleVariantPublishing(
|
||||||
|
variant: KotlinGradleVariant,
|
||||||
|
publishedModuleHolder: SingleMavenPublishedModuleHolder,
|
||||||
|
publishConfigurations: Iterable<Configuration>
|
||||||
|
) {
|
||||||
|
configurePublishing(
|
||||||
|
BasicPlatformPublicationToMavenRequest(
|
||||||
|
platformComponentName(variant),
|
||||||
|
variant.containingModule,
|
||||||
|
publishedModuleHolder,
|
||||||
|
publishConfigurations.map {
|
||||||
|
BasicVariantPublicationRequest(variant, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class VariantPublishingConfigurator @Inject constructor(
|
open class VariantPublishingConfigurator @Inject constructor(
|
||||||
@@ -60,34 +113,39 @@ open class VariantPublishingConfigurator @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun configurePublishing(
|
open fun configurePublishing(
|
||||||
variant: KotlinGradleVariant,
|
request: PlatformPublicationToMavenRequest
|
||||||
publishedModuleHolder: SingleMavenPublishedModuleHolder,
|
|
||||||
publishConfigurations: Iterable<String>
|
|
||||||
) {
|
) {
|
||||||
val componentName = platformComponentName(variant)
|
val componentName = request.componentName
|
||||||
val configurationsMap = publishConfigurations.associateWith { inferMavenScope(variant, it) }
|
|
||||||
|
|
||||||
registerPlatformModulePublication(
|
registerPlatformModulePublication(
|
||||||
componentName,
|
componentName,
|
||||||
publishedModuleHolder,
|
request.publicationHolder,
|
||||||
configurationsMap,
|
request.variantPublicationRequests,
|
||||||
variant.containingModule::ifMadePublic
|
request.fromModule::ifMadePublic
|
||||||
)
|
)
|
||||||
|
|
||||||
/** The MPP plugin doesn't publish the source artifacts as variants; keep that behavior for legacymapped variants */
|
val publishFromVariants = request.variantPublicationRequests.mapTo(mutableSetOf()) { it.fromVariant }
|
||||||
if (variant !is LegacyMappedVariant)
|
|
||||||
configureSourceElementsPublishing(variant)
|
// Collecting sources for multiple variants is not yet supported;
|
||||||
|
// TODO make callers provide the source variants?
|
||||||
|
// The MPP plugin doesn't publish the source artifacts as variants; keep that behavior for legacy-mapped variants for now
|
||||||
|
if (
|
||||||
|
publishFromVariants.size == 1 &&
|
||||||
|
publishFromVariants.none { it is LegacyMappedVariant }
|
||||||
|
) {
|
||||||
|
val singlePublishedVariant = publishFromVariants.single()
|
||||||
|
configureSourceElementsPublishing(componentName, singlePublishedVariant)
|
||||||
|
}
|
||||||
|
|
||||||
registerPlatformVariantsInRootModule(
|
registerPlatformVariantsInRootModule(
|
||||||
publishedModuleHolder,
|
request.publicationHolder,
|
||||||
variant.containingModule,
|
request.fromModule,
|
||||||
publishConfigurations
|
request.variantPublicationRequests
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun configureSourceElementsPublishing(variant: KotlinGradleVariant) {
|
protected open fun configureSourceElementsPublishing(componentName: String, variant: KotlinGradleVariant) {
|
||||||
val configurationName = variant.disambiguateName("sourceElements")
|
val configurationName = variant.disambiguateName("sourceElements")
|
||||||
val componentName = platformComponentName(variant)
|
|
||||||
val docsVariants = DocumentationVariantConfigurator().createSourcesElementsConfiguration(configurationName, variant)
|
val docsVariants = DocumentationVariantConfigurator().createSourcesElementsConfiguration(configurationName, variant)
|
||||||
project.components.withType(AdhocComponentWithVariants::class.java).named(componentName).configure { component ->
|
project.components.withType(AdhocComponentWithVariants::class.java).named(componentName).configure { component ->
|
||||||
component.addVariantsFromConfiguration(docsVariants) { }
|
component.addVariantsFromConfiguration(docsVariants) { }
|
||||||
@@ -102,13 +160,29 @@ open class VariantPublishingConfigurator @Inject constructor(
|
|||||||
protected open fun registerPlatformModulePublication(
|
protected open fun registerPlatformModulePublication(
|
||||||
componentName: String,
|
componentName: String,
|
||||||
publishedModuleHolder: SingleMavenPublishedModuleHolder,
|
publishedModuleHolder: SingleMavenPublishedModuleHolder,
|
||||||
publishConfigurationsWithMavenScopes: Map<String, String?>,
|
variantRequests: Iterable<VariantPublicationRequest>,
|
||||||
whenShouldRegisterPublication: (() -> Unit) -> Unit
|
whenShouldRegisterPublication: (() -> Unit) -> Unit
|
||||||
) {
|
) {
|
||||||
val platformComponent = softwareComponentFactory.adhoc(componentName)
|
val platformComponent = softwareComponentFactory.adhoc(componentName)
|
||||||
project.components.add(platformComponent)
|
project.components.add(platformComponent)
|
||||||
publishConfigurationsWithMavenScopes.forEach { (configurationName, mavenScopeOrNull) ->
|
|
||||||
platformComponent.addVariantsFromConfiguration(project.configurations.getByName(configurationName)) details@{ variantDetails ->
|
variantRequests.forEach { request ->
|
||||||
|
val originalConfiguration = request.publishConfiguration
|
||||||
|
val mavenScopeOrNull = inferMavenScope(request.fromVariant, originalConfiguration.name)
|
||||||
|
|
||||||
|
val publishedConfiguration = copyConfigurationForPublishing(
|
||||||
|
request.fromVariant.project,
|
||||||
|
newName = publishedConfigurationName(originalConfiguration.name) + "-platform",
|
||||||
|
configuration = originalConfiguration,
|
||||||
|
overrideArtifacts = (request as? AdvancedVariantPublicationRequest)
|
||||||
|
?.overrideConfigurationArtifactsForPublication
|
||||||
|
?.let { override -> { artifacts -> artifacts.addAllLater(override) } },
|
||||||
|
overrideAttributes = (request as? AdvancedVariantPublicationRequest)
|
||||||
|
?.overrideConfigurationAttributesForPublication
|
||||||
|
?.let { override -> { attributes -> copyAttributes(override, attributes) } }
|
||||||
|
)
|
||||||
|
|
||||||
|
platformComponent.addVariantsFromConfiguration(publishedConfiguration) details@{ variantDetails ->
|
||||||
// TODO: This is temporary for Android! Make sure to only publish AAR
|
// TODO: This is temporary for Android! Make sure to only publish AAR
|
||||||
val androidArtifactType = variantDetails.configurationVariant.attributes.getAttribute(AndroidArtifacts.ARTIFACT_TYPE)
|
val androidArtifactType = variantDetails.configurationVariant.attributes.getAttribute(AndroidArtifacts.ARTIFACT_TYPE)
|
||||||
if (androidArtifactType != null && androidArtifactType != AndroidArtifacts.ArtifactType.AAR.type) {
|
if (androidArtifactType != null && androidArtifactType != AndroidArtifacts.ArtifactType.AAR.type) {
|
||||||
@@ -138,7 +212,7 @@ open class VariantPublishingConfigurator @Inject constructor(
|
|||||||
protected open fun registerPlatformVariantsInRootModule(
|
protected open fun registerPlatformVariantsInRootModule(
|
||||||
publishedModuleHolder: SingleMavenPublishedModuleHolder,
|
publishedModuleHolder: SingleMavenPublishedModuleHolder,
|
||||||
kotlinModule: KotlinGradleModule,
|
kotlinModule: KotlinGradleModule,
|
||||||
configurationNames: Iterable<String>
|
variantRequests: Iterable<VariantPublicationRequest>
|
||||||
) {
|
) {
|
||||||
val platformModuleDependencyProvider = project.provider {
|
val platformModuleDependencyProvider = project.provider {
|
||||||
val coordinates = publishedModuleHolder.publishedMavenModuleCoordinates
|
val coordinates = publishedModuleHolder.publishedMavenModuleCoordinates
|
||||||
@@ -154,28 +228,29 @@ open class VariantPublishingConfigurator @Inject constructor(
|
|||||||
.withType(AdhocComponentWithVariants::class.java)
|
.withType(AdhocComponentWithVariants::class.java)
|
||||||
.getByName(rootPublicationComponentName(kotlinModule))
|
.getByName(rootPublicationComponentName(kotlinModule))
|
||||||
|
|
||||||
configurationNames.forEach { configurationName ->
|
variantRequests.forEach { variantRequest ->
|
||||||
fun <T : Any> copyAttribute(from: AttributeContainer, to: AttributeContainer, key: Attribute<T>) {
|
val configuration = variantRequest.publishConfiguration
|
||||||
to.attribute(key, checkNotNull(from.getAttribute(key)))
|
project.configurations.create(publishedConfigurationName(configuration.name)).apply {
|
||||||
}
|
|
||||||
|
|
||||||
val originalConfiguration = project.configurations.getByName(configurationName)
|
|
||||||
project.configurations.create(publishedConfigurationName(configurationName)).apply {
|
|
||||||
isCanBeConsumed = false
|
isCanBeConsumed = false
|
||||||
isCanBeResolved = false
|
isCanBeResolved = false
|
||||||
|
|
||||||
setModuleCapability(this, kotlinModule)
|
setModuleCapability(this, kotlinModule)
|
||||||
dependencies.addLater(platformModuleDependencyProvider)
|
dependencies.addLater(platformModuleDependencyProvider)
|
||||||
val originalAttributes = originalConfiguration.attributes
|
copyAttributes(configuration.attributes, this.attributes)
|
||||||
originalAttributes.keySet().forEach {
|
|
||||||
copyAttribute(originalAttributes, attributes, it)
|
|
||||||
}
|
|
||||||
rootSoftwareComponent.addVariantsFromConfiguration(this) { }
|
rootSoftwareComponent.addVariantsFromConfiguration(this) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal data class AdvancedVariantPublicationRequest(
|
||||||
|
override val fromVariant: KotlinGradleVariant,
|
||||||
|
override val publishConfiguration: Configuration,
|
||||||
|
val overrideConfigurationAttributesForPublication: AttributeContainer?,
|
||||||
|
val overrideConfigurationArtifactsForPublication: Provider<out Iterable<PublishArtifact>>?,
|
||||||
|
val includeIntoProjectStructureMetadata: Boolean
|
||||||
|
) : VariantPublicationRequest
|
||||||
|
|
||||||
open class DocumentationVariantConfigurator {
|
open class DocumentationVariantConfigurator {
|
||||||
open fun createSourcesElementsConfiguration(
|
open fun createSourcesElementsConfiguration(
|
||||||
project: Project,
|
project: Project,
|
||||||
@@ -214,4 +289,4 @@ open class DocumentationVariantConfigurator {
|
|||||||
ComputedCapability.fromModuleOrNull(variant.containingModule)
|
ComputedCapability.fromModuleOrNull(variant.containingModule)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
@@ -97,3 +97,6 @@ internal fun Project.filesProvider(
|
|||||||
internal fun <T : Task> T.outputFilesProvider(provider: T.() -> Any): ConfigurableFileCollection {
|
internal fun <T : Task> T.outputFilesProvider(provider: T.() -> Any): ConfigurableFileCollection {
|
||||||
return project.filesProvider(this) { provider() }
|
return project.filesProvider(this) { provider() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified T> Project.listProperty(noinline itemsProvider: () -> Iterable<T>) =
|
||||||
|
objects.listProperty(T::class.java).apply { set(provider(itemsProvider)) }
|
||||||
Reference in New Issue
Block a user