[stdlib-mpp] Setup custom publishing, disable default publications
KT-56106, KT-53791 Co-authored-by: Anton Lakotka <anton.lakotka@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
184cbd6eb1
commit
fac620df0b
@@ -1,3 +1,5 @@
|
||||
import org.gradle.api.internal.component.SoftwareComponentInternal
|
||||
import org.gradle.api.internal.component.UsageContext
|
||||
import java.nio.file.*
|
||||
import org.gradle.kotlin.dsl.support.serviceOf
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
|
||||
@@ -5,6 +7,9 @@ import org.jetbrains.kotlin.gradle.tasks.UsesKotlinJavaToolchain
|
||||
import plugins.configureDefaultPublishing
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
|
||||
import plugins.configureKotlinPomAttributes
|
||||
|
||||
plugins {
|
||||
id("kotlin-multiplatform")
|
||||
@@ -702,4 +707,277 @@ tasks {
|
||||
}
|
||||
}
|
||||
|
||||
configureDefaultPublishing()
|
||||
|
||||
// region ==== Publishing ====
|
||||
|
||||
configureDefaultPublishing()
|
||||
|
||||
open class ComponentsFactoryAccess
|
||||
@javax.inject.Inject
|
||||
constructor(val factory: SoftwareComponentFactory)
|
||||
|
||||
val componentFactory = objects.newInstance<ComponentsFactoryAccess>().factory
|
||||
|
||||
val emptyJavadocJar by tasks.creating(org.gradle.api.tasks.bundling.Jar::class) {
|
||||
archiveClassifier.set("javadoc")
|
||||
}
|
||||
|
||||
publishing {
|
||||
val artifactBaseName = base.archivesName.get()
|
||||
configureMultiModuleMavenPublishing {
|
||||
val rootModule = module("rootModule") {
|
||||
mavenPublication {
|
||||
artifactId = artifactBaseName
|
||||
configureKotlinPomAttributes(project, "Kotlin Standard Library")
|
||||
}
|
||||
|
||||
// creates a variant from existing configuration or creates new one
|
||||
variant("jvmApiElements")
|
||||
variant("jvmRuntimeElements")
|
||||
variant("jvmSourcesElements")
|
||||
|
||||
variant("metadataApiElements")
|
||||
variant("metadataSourcesElementsFromJvm") {
|
||||
name = "metadataSourcesElements"
|
||||
configuration {
|
||||
// to avoid clash in Gradle 8+ with metadataSourcesElements configuration with the same attributes
|
||||
isCanBeConsumed = false
|
||||
}
|
||||
attributes {
|
||||
copyAttributes(from = project.configurations["metadataSourcesElements"].attributes, to = this)
|
||||
}
|
||||
artifact(tasks["sourcesJar"]) {
|
||||
classifier = "common-sources"
|
||||
}
|
||||
}
|
||||
variant("nativeApiElements") {
|
||||
attributes {
|
||||
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
|
||||
attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, objects.named("non-jvm"))
|
||||
attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API))
|
||||
attribute(KotlinPlatformType.attribute, KotlinPlatformType.native)
|
||||
}
|
||||
}
|
||||
// empty variant for wasm
|
||||
// TODO: replace with wasm target
|
||||
variant("wasmApiElements") {
|
||||
attributes {
|
||||
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
|
||||
attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, objects.named("non-jvm"))
|
||||
attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API))
|
||||
attribute(KotlinPlatformType.attribute, KotlinPlatformType.wasm)
|
||||
}
|
||||
}
|
||||
variant("wasmRuntimeElements") {
|
||||
attributes {
|
||||
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
|
||||
attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, objects.named("non-jvm"))
|
||||
attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_RUNTIME))
|
||||
attribute(KotlinPlatformType.attribute, KotlinPlatformType.wasm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: decide what should be published in kotlin-stdlib-common
|
||||
// val common = module("commonModule") {
|
||||
// mavenPublication {
|
||||
// groupId = "org.example"
|
||||
// artifactId = "sample-lib-common"
|
||||
// }
|
||||
// variant("commonMainMetadataElements") {
|
||||
// // Multiplatform KGP already added klib artifact to metadataApiElements
|
||||
// // attributes { kotlinLegacyMetadataAttributes() }
|
||||
// }
|
||||
// }
|
||||
val js = module("jsModule") {
|
||||
mavenPublication {
|
||||
artifactId = "$artifactBaseName-js"
|
||||
configureKotlinPomAttributes(project, "Kotlin Standard Library for JS")
|
||||
}
|
||||
variant("jsApiElements")
|
||||
variant("jsRuntimeElements")
|
||||
variant("jsV1ApiElements")
|
||||
variant("jsV1RuntimeElements")
|
||||
variant("jsSourcesElements")
|
||||
}
|
||||
|
||||
// Makes all variants from accompanying artifacts visible through `available-at`
|
||||
rootModule.include(js)
|
||||
}
|
||||
|
||||
publications {
|
||||
withType<MavenPublication> {
|
||||
artifact(emptyJavadocJar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun copyAttributes(from: AttributeContainer, to: AttributeContainer,) {
|
||||
// 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 from.keySet()) {
|
||||
copyOneAttribute(from, to, key)
|
||||
}
|
||||
}
|
||||
|
||||
class MultiModuleMavenPublishingConfiguration() {
|
||||
val modules = mutableMapOf<String, Module>()
|
||||
|
||||
class Module(val name: String) {
|
||||
val variants = mutableMapOf<String, Variant>()
|
||||
val includes = mutableSetOf<Module>()
|
||||
|
||||
class Variant(
|
||||
val configurationName: String
|
||||
) {
|
||||
var name: String = configurationName
|
||||
val attributesConfigurations = mutableListOf<AttributeContainer.() -> Unit>()
|
||||
fun attributes(code: AttributeContainer.() -> Unit) {
|
||||
attributesConfigurations += code
|
||||
}
|
||||
|
||||
val artifactsWithConfigurations = mutableListOf<Pair<Any, ConfigurablePublishArtifact.() -> Unit>>()
|
||||
fun artifact(file: Any, code: ConfigurablePublishArtifact.() -> Unit = {}) {
|
||||
artifactsWithConfigurations += file to code
|
||||
}
|
||||
|
||||
val configurationConfigurations = mutableListOf<Configuration.() -> Unit>()
|
||||
fun configuration(code: Configuration.() -> Unit) {
|
||||
configurationConfigurations += code
|
||||
}
|
||||
|
||||
val variantDetailsConfigurations = mutableListOf<ConfigurationVariantDetails.() -> Unit>()
|
||||
fun configureVariantDetails(code: ConfigurationVariantDetails.() -> Unit) {
|
||||
variantDetailsConfigurations += code
|
||||
}
|
||||
}
|
||||
|
||||
val mavenPublicationConfigurations = mutableListOf<MavenPublication.() -> Unit>()
|
||||
fun mavenPublication(code: MavenPublication.() -> Unit) {
|
||||
mavenPublicationConfigurations += code
|
||||
}
|
||||
|
||||
fun variant(fromConfigurationName: String, code: Variant.() -> Unit = {}): Variant {
|
||||
val variant = variants.getOrPut(fromConfigurationName) { Variant(fromConfigurationName) }
|
||||
variant.code()
|
||||
return variant
|
||||
}
|
||||
|
||||
fun include(vararg modules: Module) {
|
||||
includes.addAll(modules)
|
||||
}
|
||||
}
|
||||
|
||||
fun module(name: String, code: Module.() -> Unit): Module {
|
||||
val module = modules.getOrPut(name) { Module(name) }
|
||||
module.code()
|
||||
return module
|
||||
}
|
||||
}
|
||||
|
||||
fun configureMultiModuleMavenPublishing(code: MultiModuleMavenPublishingConfiguration.() -> Unit) {
|
||||
val publishingConfiguration = MultiModuleMavenPublishingConfiguration()
|
||||
publishingConfiguration.code()
|
||||
|
||||
val components = publishingConfiguration
|
||||
.modules
|
||||
.mapValues { (_, module) -> project.createModulePublication(module) }
|
||||
|
||||
val componentsWithExternals = publishingConfiguration
|
||||
.modules
|
||||
.filter { (_, module) -> module.includes.isNotEmpty() }
|
||||
.mapValues { (moduleName, module) ->
|
||||
val mainComponent = components[moduleName] ?: error("Component with name $moduleName wasn't created")
|
||||
val externalComponents = module.includes
|
||||
.map { components[it.name] ?: error("Component with name ${it.name} wasn't created") }
|
||||
.toSet()
|
||||
ComponentWithExternalVariants(mainComponent, externalComponents)
|
||||
}
|
||||
|
||||
// override some components wih items from componentsWithExternals
|
||||
val mergedComponents = components + componentsWithExternals
|
||||
|
||||
val publicationsContainer = publishing.publications
|
||||
for ((componentName, component) in mergedComponents) {
|
||||
publicationsContainer.create<MavenPublication>(componentName) {
|
||||
from(component)
|
||||
val module = publishingConfiguration.modules[componentName]!!
|
||||
module.mavenPublicationConfigurations.forEach { configure -> configure() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Project.createModulePublication(module: MultiModuleMavenPublishingConfiguration.Module): SoftwareComponent {
|
||||
val component = componentFactory.adhoc(module.name)
|
||||
module.variants.values.forEach { addVariant(component, it) }
|
||||
|
||||
val newNames = module.variants.map { it.key to it.value.name }.filter { it.first != it.second }.toMap()
|
||||
return if (newNames.isNotEmpty()) {
|
||||
ComponentWithRenamedVariants(newNames, component as SoftwareComponentInternal)
|
||||
} else {
|
||||
component
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.addVariant(component: AdhocComponentWithVariants, variant: MultiModuleMavenPublishingConfiguration.Module.Variant) {
|
||||
val configuration = configurations.getOrCreate(variant.configurationName)
|
||||
configuration.apply {
|
||||
isCanBeResolved = false
|
||||
isCanBeConsumed = true
|
||||
|
||||
variant.attributesConfigurations.forEach { configure -> attributes.configure() }
|
||||
}
|
||||
|
||||
for ((artifactNotation, configure) in variant.artifactsWithConfigurations) {
|
||||
artifacts.add(configuration.name, artifactNotation) {
|
||||
configure()
|
||||
}
|
||||
}
|
||||
|
||||
for (configure in variant.configurationConfigurations) {
|
||||
configuration.apply(configure)
|
||||
}
|
||||
|
||||
component.addVariantsFromConfiguration(configuration) {
|
||||
variant.variantDetailsConfigurations.forEach { configure -> configure() }
|
||||
}
|
||||
}
|
||||
|
||||
private class RenamedVariant(val newName: String, context: UsageContext) : UsageContext by context {
|
||||
override fun getName(): String = newName
|
||||
}
|
||||
|
||||
private class ComponentWithRenamedVariants(
|
||||
val newNames: Map<String, String>,
|
||||
private val base: SoftwareComponentInternal
|
||||
): SoftwareComponentInternal by base {
|
||||
|
||||
override fun getName(): String = base.name
|
||||
override fun getUsages(): Set<UsageContext> {
|
||||
return base.usages.map {
|
||||
val newName = newNames[it.name]
|
||||
if (newName != null) {
|
||||
RenamedVariant(newName, it)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
private class ComponentWithExternalVariants(
|
||||
private val mainComponent: SoftwareComponent,
|
||||
private val externalComponents: Set<SoftwareComponent>
|
||||
) : ComponentWithVariants, SoftwareComponentInternal {
|
||||
override fun getName(): String = mainComponent.name
|
||||
|
||||
override fun getUsages(): Set<UsageContext> = (mainComponent as SoftwareComponentInternal).usages
|
||||
|
||||
override fun getVariants(): Set<SoftwareComponent> = externalComponents
|
||||
}
|
||||
|
||||
// endregion
|
||||
@@ -1,2 +1,3 @@
|
||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||
kotlin.mpp.enableCompatibilityMetadataVariant=true
|
||||
kotlin.internal.mpp.createDefaultMultiplatformPublications=false
|
||||
Reference in New Issue
Block a user