Add publishing configurator, call it from the variant factories

This commit is contained in:
Sergey Igushkin
2021-03-20 17:32:54 +03:00
parent 1271fabffa
commit c1fe0d7158
6 changed files with 163 additions and 129 deletions
@@ -50,10 +50,14 @@ interface KotlinNativeVariant : KotlinGradleVariant {
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.native
/** A configuration name for the metadata of the host-specific fragments which this variant includes,
* if applies to this Native variant; null otherwise */
val hostSpecificMetadataElementsConfigurationName: String?
var enableEndorsedLibraries: Boolean
}
interface SingleMavenPublicationHolder {
interface SingleMavenPublishedModuleHolder {
fun assignMavenPublication(publication: MavenPublication)
val defaultPublishedModuleSuffix: String?
val publishedMavenModuleCoordinates: PublishedModuleCoordinatesProvider
@@ -19,7 +19,10 @@ open class KotlinNativeVariantInternal(
val konanTarget: KonanTarget
) : KotlinNativeVariant,
KotlinGradleVariantInternal(containingModule, fragmentName),
SingleMavenPublicationHolder by DefaultSingleMavenPublicationHolder(containingModule, fragmentName) {
SingleMavenPublishedModuleHolder by DefaultSingleMavenPublishedModuleHolder(containingModule, fragmentName) {
final override val hostSpecificMetadataElementsConfigurationName: String?
get() = disambiguateName("hostSpecificMetadataElements").takeIf { includesHostSpecificMetadata }
override var enableEndorsedLibraries: Boolean = false
@@ -33,6 +36,9 @@ open class KotlinNativeVariantInternal(
internal val compilationData by lazy { KotlinNativeVariantCompilationData(this) }
}
internal val KotlinNativeVariantInternal.includesHostSpecificMetadata: Boolean
get() = isHostSpecificKonanTargetsSet(setOf(konanTarget))
// FIXME codegen
open class KotlinLinuxX64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.LINUX_X64)
@@ -49,6 +49,7 @@ open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>(
override fun create(name: String): T =
super.create(name).also { result ->
configureHostSpecificMetadata(result)
configureVariantPublishing(result)
}
@@ -80,22 +81,10 @@ open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>(
}
}
open fun configureVariantPublishing(variant: T) {
val rootSoftwareComponent =
project.components
.withType(AdhocComponentWithVariants::class.java)
.getByName(rootPublicationComponentName(module))
private fun configureHostSpecificMetadata(variant: T) {
val hostSpecificConfigurationNameIfEnabled = variant.hostSpecificMetadataElementsConfigurationName
?: return
val platformModuleDependencyProvider = project.provider {
val coordinates = variant.publishedMavenModuleCoordinates
(project.dependencies.create("${coordinates.group}:${coordinates.name}:${coordinates.version}") as ModuleDependency).apply {
if (module.moduleClassifier != null) {
capabilities { it.requireCapability(CalculatedCapability.fromModule(module)) }
}
}
}
val apiElements = project.configurations.getByName(variant.apiElementsConfigurationName)
val hostSpecificMetadataJar = project.registerTask<Jar>(variant.disambiguateName("hostSpecificMetadataJar")) { jar ->
jar.archiveClassifier.set("metadata")
jar.archiveAppendix.set(variant.disambiguateName(""))
@@ -103,7 +92,7 @@ open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>(
.withAll { metadataCompilation ->
val fragment = metadataCompilation.fragment
if (metadataCompilation is KotlinNativeFragmentMetadataCompilationData) {
jar.from(project.files(Callable {
jar.from(project.files(project.provider {
if (fragment in variant.refinesClosure && fragment.isNativeHostSpecific())
project.filesWithUnpackedArchives(metadataCompilation.output.allOutputs, setOf(KLIB_FILE_EXTENSION))
else emptyList<Any>()
@@ -111,7 +100,8 @@ open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>(
}
}
}
val hostSpecificMetadataElements = project.configurations.create(variant.hostSpecificMetadataConfigurationName).apply {
val apiElements = project.configurations.getByName(variant.apiElementsConfigurationName)
project.configurations.create(hostSpecificConfigurationNameIfEnabled).apply {
isCanBeResolved = false
isCanBeConsumed = false
setPlatformAttributesAndMetadataUsage(variant)
@@ -120,49 +110,10 @@ open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>(
set(project.provider { apiElements.allDependencies })
})
}
}
// FIXME inject vs internal API
val platformComponentName = platformComponentName(variant)
val platformComponent = (project as ProjectInternal).services
.get(SoftwareComponentFactory::class.java)
.adhoc(platformComponentName)
project.components.add(platformComponent)
platformComponent.addVariantsFromConfiguration(apiElements) {
it.mapToMavenScope("compile")
}
platformComponent.addVariantsFromConfiguration(hostSpecificMetadataElements) { }
module.ifMadePublic {
project.pluginManager.withPlugin("maven-publish") {
project.extensions.getByType(PublishingExtension::class.java).apply {
publications.create(platformComponentName, MavenPublication::class.java).apply {
(this as DefaultMavenPublication).isAlias = true
from(platformComponent)
variant.assignMavenPublication(this)
artifactId = dashSeparatedName(project.name, variant.defaultPublishedModuleSuffix)
}
}
}
}
val publishedApiConfiguration =
project.configurations.create(publishedConfigurationName(variant.apiElementsConfigurationName)).apply {
isCanBeConsumed = false
isCanBeResolved = false
configureApiElementsConfiguration(variant, this)
setModuleCapability(this, module)
dependencies.addLater(platformModuleDependencyProvider)
}
val publishedMetadataConfiguration =
project.configurations.create(publishedConfigurationName(variant.hostSpecificMetadataConfigurationName)).apply {
isCanBeConsumed = false
isCanBeResolved = false
setPlatformAttributesAndMetadataUsage(variant)
setModuleCapability(this, module)
dependencies.addLater(platformModuleDependencyProvider)
}
rootSoftwareComponent.addVariantsFromConfiguration(publishedApiConfiguration) { }
rootSoftwareComponent.addVariantsFromConfiguration(publishedMetadataConfiguration) { }
open fun configureVariantPublishing(variant: T) {
VariantPublishingConfigurator.get(project).configureNativeVariantPublication(variant)
}
private fun Configuration.setPlatformAttributesAndMetadataUsage(variant: T) {
@@ -5,8 +5,12 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import jdk.internal.org.objectweb.asm.tree.VarInsnNode
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.attributes.Usage
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.component.SoftwareComponentFactory
@@ -22,6 +26,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.sourcesJarTask
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.project.model.refinesClosure
import javax.inject.Inject
abstract class AbstractKotlinGradleVariantFactory<T : KotlinGradleVariant>(
module: KotlinGradleModule
@@ -142,71 +147,10 @@ abstract class AbstractKotlinGradleRuntimePublishedVariantFactory<T : KotlinGrad
}
open fun configureVariantPublishing(variant: T) {
val rootSoftwareComponent =
project.components
.withType(AdhocComponentWithVariants::class.java)
.getByName(rootPublicationComponentName(module))
val platformModuleDependencyProvider = project.provider {
val coordinates = variant.publishedMavenModuleCoordinates
(project.dependencies.create("${coordinates.group}:${coordinates.name}:${coordinates.version}") as ModuleDependency).apply {
if (module.moduleClassifier != null) {
capabilities { it.requireCapability(CalculatedCapability.fromModule(module)) }
}
}
}
// FIXME inject vs internal API
val platformComponentName = platformComponentName(variant)
val platformComponent = (project as ProjectInternal).services
.get(SoftwareComponentFactory::class.java)
.adhoc(platformComponentName)
project.components.add(platformComponent)
platformComponent.addVariantsFromConfiguration(project.configurations.getByName(variant.apiElementsConfigurationName)) {
it.mapToMavenScope("compile")
}
platformComponent.addVariantsFromConfiguration(project.configurations.getByName(variant.runtimeElementsConfigurationName)) {
it.mapToMavenScope("runtime")
}
module.ifMadePublic {
project.pluginManager.withPlugin("maven-publish") {
project.extensions.getByType(PublishingExtension::class.java).apply {
publications.create(platformComponentName, MavenPublication::class.java).apply {
(this as DefaultMavenPublication).isAlias = true
from(platformComponent)
variant.assignMavenPublication(this)
artifactId = dashSeparatedName(project.name, variant.defaultPublishedModuleSuffix)
}
}
}
}
val publishedApiConfiguration =
project.configurations.create(publishedConfigurationName(variant.apiElementsConfigurationName)).apply {
isCanBeConsumed = false
isCanBeResolved = false
configureApiElementsConfiguration(variant, this)
setModuleCapability(this, module)
dependencies.addLater(platformModuleDependencyProvider)
}
val publishedRuntimeConfiguration =
project.configurations.create(publishedConfigurationName(variant.runtimeElementsConfigurationName)).apply {
isCanBeConsumed = false
isCanBeResolved = false
configureRuntimeElementsConfiguration(variant, this)
setModuleCapability(this, module)
dependencies.addLater(platformModuleDependencyProvider)
}
listOf(publishedApiConfiguration, publishedRuntimeConfiguration).forEach {
rootSoftwareComponent.addVariantsFromConfiguration(it) { }
}
VariantPublishingConfigurator.get(project).configureSingleVariantPublication(variant)
}
open fun platformComponentName(variant: T) = variant.disambiguateName("")
}
internal fun setModuleCapability(configuration: Configuration, module: KotlinGradleModule) {
if (module.moduleClassifier != null) {
configuration.outgoing.capability(CalculatedCapability.fromModule(module))
@@ -60,10 +60,10 @@ abstract class KotlinGradleVariantInternal(
internal val KotlinGradleVariant.compileDependencyConfiguration: Configuration
get() = containingModule.project.configurations.getByName(compileDependencyConfigurationName)
class DefaultSingleMavenPublicationHolder(
class DefaultSingleMavenPublishedModuleHolder(
private var module: KotlinGradleModule,
override val defaultPublishedModuleSuffix: String?
) : SingleMavenPublicationHolder {
) : SingleMavenPublishedModuleHolder {
private val project get() = module.project
private var assignedMavenPublication: MavenPublication? = null
@@ -114,7 +114,7 @@ private fun defaultModuleSuffix(module: KotlinGradleModule, variantName: String)
abstract class KotlinGradlePublishedVariantWithRuntime(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinGradleVariantWithRuntimeInternal(containingModule, fragmentName),
SingleMavenPublicationHolder by DefaultSingleMavenPublicationHolder(
SingleMavenPublishedModuleHolder by DefaultSingleMavenPublishedModuleHolder(
containingModule,
defaultModuleSuffix(containingModule, fragmentName)
) {
@@ -5,8 +5,137 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
fun <T> publishVariantWithSinglePublication(
variant: T
) where T : SingleMavenPublicationHolder, T : KotlinGradleVariant {
import org.gradle.api.Project
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.CalculatedCapability
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import javax.inject.Inject
fun VariantPublishingConfigurator.configureNativeVariantPublication(variant: KotlinNativeVariantInternal) {
val publishConfigurations = listOfNotNull(
variant.apiElementsConfigurationName,
variant.hostSpecificMetadataElementsConfigurationName // host-specific metadata may be absent
)
configurePublishing(variant, variant, publishConfigurations)
}
fun VariantPublishingConfigurator.configureSingleVariantPublication(variant: KotlinGradlePublishedVariantWithRuntime) {
val publishConfigurations = listOf(variant.apiElementsConfigurationName, variant.runtimeElementsConfigurationName)
configurePublishing(variant, variant, publishConfigurations)
}
open class VariantPublishingConfigurator @Inject constructor(
private val project: Project,
private val softwareComponentFactory: SoftwareComponentFactory
) {
companion object {
fun get(project: Project) = project.objects.newInstance(VariantPublishingConfigurator::class.java, project)
}
open fun platformComponentName(variant: KotlinGradleVariant) = variant.disambiguateName("")
open fun inferMavenScopes(variant: KotlinGradleVariant, configurationNames: Iterable<String>): Map<String, String?> =
configurationNames.associateWith { configurationName ->
when {
configurationName == variant.apiElementsConfigurationName -> "compile"
variant is KotlinGradleVariantWithRuntime && configurationName == variant.runtimeElementsConfigurationName -> "runtime"
else -> null
}
}
open fun configurePublishing(
variant: KotlinGradleVariant,
publishedModuleHolder: SingleMavenPublishedModuleHolder,
publishConfigurations: Iterable<String>
) {
val componentName = platformComponentName(variant)
val configurationsMap = inferMavenScopes(variant, publishConfigurations)
// FIXME: add the sources artifact of the variant to the publication!!!
// do that following the Gradle's guidelines on publishing sources variant along library variants, if possible
registerPlatformModulePublication(componentName, publishedModuleHolder, configurationsMap, variant.containingModule::ifMadePublic)
registerPlatformVariantsInRootModule(publishedModuleHolder, variant.containingModule, publishConfigurations)
}
/**
* Creates the [AdhocComponentWithVariants] named [componentName] for the given [publishConfigurationsWithMavenScopes].
* At the point [whenShouldRegisterPublication] creates a Maven publication named [componentName] that publishes the created component.
* Assigns the created Maven publication to the [publishedModuleHolder].
*/
protected open fun registerPlatformModulePublication(
componentName: String,
publishedModuleHolder: SingleMavenPublishedModuleHolder,
publishConfigurationsWithMavenScopes: Map<String, String?>,
whenShouldRegisterPublication: (() -> Unit) -> Unit
) {
val platformComponent = softwareComponentFactory.adhoc(componentName)
project.components.add(platformComponent)
publishConfigurationsWithMavenScopes.forEach { configurationName, mavenScopeOrNull ->
platformComponent.addVariantsFromConfiguration(project.configurations.getByName(configurationName)) { variantDetails ->
mavenScopeOrNull?.let { variantDetails.mapToMavenScope(it) }
}
}
whenShouldRegisterPublication {
project.pluginManager.withPlugin("maven-publish") {
project.extensions.getByType(PublishingExtension::class.java).apply {
publications.create(componentName, MavenPublication::class.java).apply {
(this as DefaultMavenPublication).isAlias = true
from(platformComponent)
publishedModuleHolder.assignMavenPublication(this)
artifactId = dashSeparatedName(project.name, publishedModuleHolder.defaultPublishedModuleSuffix)
}
}
}
}
}
protected open fun registerPlatformVariantsInRootModule(
publishedModuleHolder: SingleMavenPublishedModuleHolder,
kotlinModule: KotlinGradleModule,
configurationNames: Iterable<String>
) {
val platformModuleDependencyProvider = project.provider {
val coordinates = publishedModuleHolder.publishedMavenModuleCoordinates
(project.dependencies.create("${coordinates.group}:${coordinates.name}:${coordinates.version}") as ModuleDependency).apply {
if (kotlinModule.moduleClassifier != null) {
capabilities { it.requireCapability(CalculatedCapability.fromModule(kotlinModule)) }
}
}
}
val rootSoftwareComponent =
project.components
.withType(AdhocComponentWithVariants::class.java)
.getByName(rootPublicationComponentName(kotlinModule))
configurationNames.forEach { configurationName ->
fun <T : Any> copyAttribute(from: AttributeContainer, to: AttributeContainer, key: Attribute<T>) {
to.attribute(key, checkNotNull(from.getAttribute(key)))
}
val originalConfiguration = project.configurations.getByName(configurationName)
project.configurations.create(publishedConfigurationName(configurationName)).apply {
isCanBeConsumed = false
isCanBeResolved = false
setModuleCapability(this, kotlinModule)
dependencies.addLater(platformModuleDependencyProvider)
val originalAttributes = originalConfiguration.attributes
originalAttributes.keySet().forEach {
copyAttribute(originalAttributes, attributes, it)
}
rootSoftwareComponent.addVariantsFromConfiguration(this) { }
}
}
}
}