diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleVariant.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleVariant.kt index c43d668d9fc..a972eb0afb8 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleVariant.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleVariant.kt @@ -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 diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariant.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariant.kt index e59ef51a4be..9eb56346d28 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariant.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariant.kt @@ -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) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariantFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariantFactory.kt index 4a9feffd6b8..76ab8247090 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariantFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariantFactory.kt @@ -49,6 +49,7 @@ open class KotlinNativeVariantFactory( override fun create(name: String): T = super.create(name).also { result -> + configureHostSpecificMetadata(result) configureVariantPublishing(result) } @@ -80,22 +81,10 @@ open class KotlinNativeVariantFactory( } } - 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(variant.disambiguateName("hostSpecificMetadataJar")) { jar -> jar.archiveClassifier.set("metadata") jar.archiveAppendix.set(variant.disambiguateName("")) @@ -103,7 +92,7 @@ open class KotlinNativeVariantFactory( .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() @@ -111,7 +100,8 @@ open class KotlinNativeVariantFactory( } } } - 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( 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) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariantFactories.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariantFactories.kt index 094708bcdd3..94e2271c01b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariantFactories.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariantFactories.kt @@ -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( module: KotlinGradleModule @@ -142,71 +147,10 @@ abstract class AbstractKotlinGradleRuntimePublishedVariantFactory 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): Map = + 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 + ) { + 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, + 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 + ) { + 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 copyAttribute(from: AttributeContainer, to: AttributeContainer, key: Attribute) { + 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) { } + } + } + } } \ No newline at end of file