From f3240757ed82c0dc98643b1114fdcf1d2bf8a63d Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Thu, 23 Nov 2023 08:19:08 +0100 Subject: [PATCH] Extract custom publishing dsl to buildsrc-compat It will be used also in kotlin-test KT-61969 --- libraries/stdlib/build.gradle.kts | 175 +-------------- .../plugins/CustomVariantPublishingDsl.kt | 199 ++++++++++++++++++ 2 files changed, 200 insertions(+), 174 deletions(-) create mode 100644 repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/plugins/CustomVariantPublishingDsl.kt diff --git a/libraries/stdlib/build.gradle.kts b/libraries/stdlib/build.gradle.kts index a17cbcd25de..28f8bd65b7d 100644 --- a/libraries/stdlib/build.gradle.kts +++ b/libraries/stdlib/build.gradle.kts @@ -1,6 +1,4 @@ @file:Suppress("UNUSED_VARIABLE", "NAME_SHADOWING") -import org.gradle.api.internal.component.SoftwareComponentInternal -import org.gradle.api.internal.component.UsageContext import org.gradle.jvm.tasks.Jar import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages @@ -13,6 +11,7 @@ import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.UsesKotlinJavaToolchain import plugins.configureDefaultPublishing import plugins.configureKotlinPomAttributes +import plugins.publishing.* import kotlin.io.path.copyTo plugins { @@ -789,11 +788,6 @@ tasks { configureDefaultPublishing() -open class ComponentsFactoryAccess -@javax.inject.Inject -constructor(val factory: SoftwareComponentFactory) - -val componentFactory = objects.newInstance().factory val emptyJavadocJar by tasks.creating(org.gradle.api.tasks.bundling.Jar::class) { archiveClassifier.set("javadoc") @@ -906,173 +900,6 @@ publishing { } } -fun copyAttributes(from: AttributeContainer, to: AttributeContainer,) { - // capture type argument T - fun copyOneAttribute(from: AttributeContainer, to: AttributeContainer, key: Attribute) { - val value = checkNotNull(from.getAttribute(key)) - to.attribute(key, value) - } - for (key in from.keySet()) { - copyOneAttribute(from, to, key) - } -} - -class MultiModuleMavenPublishingConfiguration() { - val modules = mutableMapOf() - - class Module(val name: String) { - val variants = mutableMapOf() - val includes = mutableSetOf() - - class Variant( - val configurationName: String - ) { - var name: String = configurationName - val attributesConfigurations = mutableListOf Unit>() - fun attributes(code: AttributeContainer.() -> Unit) { - attributesConfigurations += code - } - - val artifactsWithConfigurations = mutableListOf Unit>>() - fun artifact(file: Any, code: ConfigurablePublishArtifact.() -> Unit = {}) { - artifactsWithConfigurations += file to code - } - - val configurationConfigurations = mutableListOf Unit>() - fun configuration(code: Configuration.() -> Unit) { - configurationConfigurations += code - } - - val variantDetailsConfigurations = mutableListOf Unit>() - fun configureVariantDetails(code: ConfigurationVariantDetails.() -> Unit) { - variantDetailsConfigurations += code - } - } - - val mavenPublicationConfigurations = mutableListOf 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(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, - private val base: SoftwareComponentInternal -): SoftwareComponentInternal by base { - - override fun getName(): String = base.name - override fun getUsages(): Set { - 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 -) : ComponentWithVariants, SoftwareComponentInternal { - override fun getName(): String = mainComponent.name - - override fun getUsages(): Set = (mainComponent as SoftwareComponentInternal).usages - - override fun getVariants(): Set = externalComponents -} // endregion diff --git a/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/plugins/CustomVariantPublishingDsl.kt b/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/plugins/CustomVariantPublishingDsl.kt new file mode 100644 index 00000000000..07192c7cb56 --- /dev/null +++ b/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/plugins/CustomVariantPublishingDsl.kt @@ -0,0 +1,199 @@ +/* + * 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 plugins.publishing + +import getOrCreate +import org.gradle.api.Project +import org.gradle.api.artifacts.ConfigurablePublishArtifact +import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.Attribute +import org.gradle.api.attributes.AttributeContainer +import org.gradle.api.component.* +import org.gradle.api.internal.component.SoftwareComponentInternal +import org.gradle.api.internal.component.UsageContext +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.extra +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.newInstance + +private open class ComponentsFactoryAccess +@javax.inject.Inject +constructor(val factory: SoftwareComponentFactory) + +val Project.componentFactory: SoftwareComponentFactory + get() = findProperty("_componentFactory") as SoftwareComponentFactory? + ?: objects.newInstance().factory + .also { project.extra["_componentFactory"] = it } + +fun copyAttributes(from: AttributeContainer, to: AttributeContainer,) { + // capture type argument T + fun copyOneAttribute(from: AttributeContainer, to: AttributeContainer, key: Attribute) { + val value = checkNotNull(from.getAttribute(key)) + to.attribute(key, value) + } + for (key in from.keySet()) { + copyOneAttribute(from, to, key) + } +} + +class MultiModuleMavenPublishingConfiguration() { + val modules = mutableMapOf() + + class Module(val name: String) { + val variants = mutableMapOf() + val includes = mutableSetOf() + + class Variant( + val configurationName: String + ) { + var name: String = configurationName + val attributesConfigurations = mutableListOf Unit>() + fun attributes(code: AttributeContainer.() -> Unit) { + attributesConfigurations += code + } + + val artifactsWithConfigurations = mutableListOf Unit>>() + fun artifact(file: Any, code: ConfigurablePublishArtifact.() -> Unit = {}) { + artifactsWithConfigurations += file to code + } + + val configurationConfigurations = mutableListOf Unit>() + fun configuration(code: Configuration.() -> Unit) { + configurationConfigurations += code + } + + val variantDetailsConfigurations = mutableListOf Unit>() + fun configureVariantDetails(code: ConfigurationVariantDetails.() -> Unit) { + variantDetailsConfigurations += code + } + } + + val mavenPublicationConfigurations = mutableListOf 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 Project.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 = project.extensions.getByType().publications + for ((componentName, component) in mergedComponents) { + publicationsContainer.create(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, + private val base: SoftwareComponentInternal +): SoftwareComponentInternal by base { + + override fun getName(): String = base.name + override fun getUsages(): Set { + 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 +) : ComponentWithVariants, SoftwareComponentInternal { + override fun getName(): String = mainComponent.name + + override fun getUsages(): Set = (mainComponent as SoftwareComponentInternal).usages + + override fun getVariants(): Set = externalComponents +}