Simplify matching of Kotlin variant name and Gradle configuration name

Earlier, the matching was non-trivial and required the consumer to look
through all of the producer's targets to find the Kotlin variant given
the name of the configuration that Gradle chose during variant-aware
dependency resolution. This is not feasible in composite builds as we
can't look into a project model of an included build.

To fix this, simplify the matching of the Gradle configuration name and
the Kotlin variant name by just using a suffix for the published
configurations.

Namely, instead of names like `jvm-api`, use the original configuration
name `jvmApiElements` for Kotlin variant names. To avoid ambiguity with
Gradle configurations (which we might want to customize for publishing,
like by altering the attributes or the published artifacts compared to
the configuration exposed for inter-project dependencies), create
publishing configurations
This commit is contained in:
Sergey Igushkin
2020-09-28 16:53:15 +03:00
parent 16d493558e
commit a0fbf54d11
8 changed files with 72 additions and 62 deletions
@@ -452,11 +452,11 @@ class HierarchicalMppIT : BaseGradleIT() {
val jsSourceSets = setOf("commonMain", "jvmAndJsMain", "linuxAndJsMain")
return KotlinProjectStructureMetadata(
sourceSetNamesByVariantName = mapOf(
"js-api" to jsSourceSets,
"js-runtime" to jsSourceSets,
"jvm-api" to jvmSourceSets,
"jvm-runtime" to jvmSourceSets,
"linuxX64-api" to setOf("commonMain", "linuxAndJsMain")
"jsApiElements" to jsSourceSets,
"jsRuntimeElements" to jsSourceSets,
"jvmApiElements" to jvmSourceSets,
"jvmRuntimeElements" to jvmSourceSets,
"linuxX64ApiElements" to setOf("commonMain", "linuxAndJsMain")
),
sourceSetsDependsOnRelation = mapOf(
"jvmAndJsMain" to setOf("commonMain"),
@@ -978,9 +978,9 @@ class NewMultiplatformIT : BaseGradleIT() {
// but check that the module metadata contains all variants:
val gradleModuleMetadata = projectDir.resolve("repo/com/example/sample-lib/1.0/sample-lib-1.0.module").readText()
assertTrue(""""name": "linux64-api"""" in gradleModuleMetadata)
assertTrue(""""name": "mingw64-api"""" in gradleModuleMetadata)
assertTrue(""""name": "macos64-api"""" in gradleModuleMetadata)
assertTrue(""""name": "linux64ApiElements-published"""" in gradleModuleMetadata)
assertTrue(""""name": "mingw64ApiElements-published"""" in gradleModuleMetadata)
assertTrue(""""name": "macos64ApiElements-published"""" in gradleModuleMetadata)
}
}
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.PublishArtifact
@@ -34,7 +33,6 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.COMPILE
@@ -406,25 +404,27 @@ abstract class KotlinOnlyTargetConfigurator<KotlinCompilationType : KotlinCompil
jarArtifact.type = archiveType
val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
addJar(apiElementsConfiguration, jarArtifact)
// If the target adds its own artifact to this configuration until this happens, don't add another one:
addJarIfNoArtifactsPresent(apiElementsConfiguration, jarArtifact)
if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
val runtimeConfiguration = project.configurations.getByName(mainCompilation.deprecatedRuntimeConfigurationName)
val runtimeElementsConfiguration = project.configurations.getByName(target.runtimeElementsConfigurationName)
addJar(runtimeConfiguration, jarArtifact)
addJar(runtimeElementsConfiguration, jarArtifact)
// TODO Check Gradle's special split into variants for classes & resources -- do we need that too?
addJarIfNoArtifactsPresent(runtimeConfiguration, jarArtifact)
addJarIfNoArtifactsPresent(runtimeElementsConfiguration, jarArtifact)
}
}
}
}
private fun addJar(configuration: Configuration, jarArtifact: PublishArtifact) {
val publications = configuration.outgoing
private fun addJarIfNoArtifactsPresent(configuration: Configuration, jarArtifact: PublishArtifact) {
if (configuration.artifacts.isEmpty()) {
val publications = configuration.outgoing
// Configure an implicit variant
publications.artifacts.add(jarArtifact)
publications.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, archiveType)
// Configure an implicit variant
publications.artifacts.add(jarArtifact)
publications.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, archiveType)
}
}
}
@@ -20,6 +20,14 @@ internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadata
open class KotlinMetadataTarget @Inject constructor(project: Project) :
KotlinOnlyTarget<AbstractKotlinCompilation<*>>(project, KotlinPlatformType.common) {
override val artifactsTaskName: String
// The IDE import looks at this task name to determine the artifact and register the path to the artifact;
// in HMPP, since the project resolves to the all-metadata JAR, the IDE import needs to work with that JAR, too
get() = if (project.isKotlinGranularMetadataEnabled) KotlinMetadataTargetConfigurator.ALL_METADATA_JAR_NAME else super.artifactsTaskName
internal val legacyArtifactsTaskName: String
get() = super.artifactsTaskName
override val kotlinComponents: Set<KotlinTargetComponent> by lazy {
if (!project.isKotlinGranularMetadataEnabled)
super.kotlinComponents
@@ -72,11 +72,7 @@ class DefaultKotlinUsageContext(
override fun getUsage(): Usage = usage
override fun getName(): String = kotlinTarget.targetName + when (dependencyConfigurationName) {
kotlinTarget.apiElementsConfigurationName -> "-api"
kotlinTarget.runtimeElementsConfigurationName -> "-runtime"
else -> "-$dependencyConfigurationName"
}
override fun getName(): String = dependencyConfigurationName
private val configuration: Configuration
get() = project.configurations.getByName(dependencyConfigurationName)
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations
import java.io.File
internal data class SourceSetVisibilityResult(
@@ -59,16 +58,6 @@ internal class SourceSetVisibilityProvider(
val mppModuleIdentifier = ModuleIds.fromComponent(project, resolvedRootMppDependency ?: resolvedMetadataDependency)
/**
* When Gradle resolves a project dependency, as opposed to an external dependency, the variant name it returns in the resolution
* results is the name of the configuration that is chosen during variant-aware resolution, not the actual name of the variant that
* is written to the Gradle module metadata and the Kotlin project structure metadata. To fix this, get the published Kotlin
* variants of the dependency project and find among them the one that owns the configuration by the given name.
*/
val projectPublishedCompilations = resolvedToOtherProject?.let(::getPublishedPlatformCompilations)?.keys
fun platformVariantName(resolvedToVariantName: String): String =
projectPublishedCompilations?.first { it.dependencyConfigurationName == resolvedToVariantName }?.name ?: resolvedToVariantName
val firstConfigurationByVariant = mutableMapOf<String, Configuration>()
val visiblePlatformVariantNames: Set<String?> =
@@ -81,7 +70,7 @@ internal class SourceSetVisibilityProvider(
}
.mapTo(mutableSetOf()) { configuration ->
val resolvedVariant = resolvedVariantsProvider.getResolvedVariantName(mppModuleIdentifier, configuration)
?.let { platformVariantName(it) }
?.let { kotlinVariantNameFromPublishedVariantName(it) }
?: return@mapTo null
firstConfigurationByVariant.putIfAbsent(resolvedVariant, configuration)
@@ -135,6 +124,9 @@ internal class SourceSetVisibilityProvider(
}
}
private fun kotlinVariantNameFromPublishedVariantName(resolvedToVariantName: String): String =
originalVariantNameFromPublished(resolvedToVariantName) ?: resolvedToVariantName
private fun Project.resolvableConfigurationFromCompilationByScope(
compilation: KotlinCompilation<*>,
scope: KotlinDependencyScope
@@ -21,7 +21,6 @@ import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.internal.component.SoftwareComponentInternal
import org.gradle.api.internal.component.UsageContext
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.provider.Provider
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.util.ConfigureUtil
import org.gradle.util.WrapUtil
@@ -95,8 +94,9 @@ abstract class AbstractKotlinTarget(
project.whenEvaluated {
(kotlinVariant as SoftwareComponentInternal).usages.filterIsInstance<KotlinUsageContext>().forEach { kotlinUsageContext ->
val configuration = project.configurations.findByName(kotlinUsageContext.name)
?: project.configurations.create(kotlinUsageContext.name).also { configuration ->
val publishedConfigurationName = publishedConfigurationName(kotlinUsageContext.name)
val configuration = project.configurations.findByName(publishedConfigurationName)
?: project.configurations.create(publishedConfigurationName).also { configuration ->
configuration.isCanBeConsumed = false
configuration.isCanBeResolved = false
configuration.extendsFrom(project.configurations.getByName(kotlinUsageContext.dependencyConfigurationName))
@@ -219,6 +219,12 @@ abstract class AbstractKotlinTarget(
internal set
}
private val publishedConfigurationNameSuffix = "-published"
internal fun publishedConfigurationName(originalVariantName: String) = originalVariantName + publishedConfigurationNameSuffix
internal fun originalVariantNameFromPublished(publishedConfigurationName: String): String? =
publishedConfigurationName.takeIf { it.endsWith(publishedConfigurationNameSuffix) }?.removeSuffix(publishedConfigurationNameSuffix)
internal fun KotlinTarget.disambiguateName(simpleName: String) =
lowerCamelCaseName(targetName, simpleName)
@@ -83,8 +83,13 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
setupDependencyTransformationForCommonSourceSets(target)
target.project.configurations.getByName(target.apiElementsConfigurationName).attributes
.attribute(USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
target.project.configurations.getByName(target.apiElementsConfigurationName).run {
attributes.attribute(USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
/** Note: to add this artifact here is enough to avoid duplicate artifacts in this configuration: the default artifact
* won't be added (later) if there's already an artifact in the configuration, see
* [KotlinOnlyTargetConfigurator.configureArchivesAndComponent] */
target.project.artifacts.add(target.apiElementsConfigurationName, allMetadataJar)
}
if (target.project.isCompatibilityMetadataVariantEnabled) {
createCommonMainElementsConfiguration(target)
@@ -126,30 +131,33 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
}
override fun createArchiveTasks(target: KotlinMetadataTarget): TaskProvider<out Zip> {
val result = super.createArchiveTasks(target)
if (!target.project.isKotlinGranularMetadataEnabled)
return super.createArchiveTasks(target)
if (target.project.isKotlinGranularMetadataEnabled) {
target.project.locateTask<Jar>(target.artifactsTaskName)!!.configure {
if (!target.project.isCompatibilityMetadataVariantEnabled) {
it.archiveClassifier.set("commonMain")
}
it.onlyIf { target.project.isCompatibilityMetadataVariantEnabled }
val result = target.project.registerTask<Jar>(target.artifactsTaskName) {
it.group = BasePlugin.BUILD_GROUP
/** The content is added to this JAR in [KotlinMetadataTargetConfigurator.configureTarget]. */
}
result.configure { allMetadataJar ->
allMetadataJar.description = "Assembles a jar archive containing the metadata for all Kotlin source sets."
allMetadataJar.group = BasePlugin.BUILD_GROUP
allMetadataJar.archiveAppendix.set(target.name.toLowerCase())
if (target.project.isCompatibilityMetadataVariantEnabled) {
allMetadataJar.archiveClassifier.set("all")
}
}
/** This JAR is created in addition to the main one, published with a classifier, but is by default used
* for project dependencies (as the Kotlin Granular metadata is enabled across all projects in a build, this is OK).
* See also [KotlinMetadataTarget.kotlinComponents]
*/
target.project.registerTask<Jar>(ALL_METADATA_JAR_NAME) { allMetadataJar ->
allMetadataJar.description = "Assembles a jar archive containing the metadata for all Kotlin source sets."
allMetadataJar.group = BasePlugin.BUILD_GROUP
allMetadataJar.archiveAppendix.set(target.name.toLowerCase())
if (target.project.isCompatibilityMetadataVariantEnabled) {
allMetadataJar.archiveClassifier.set("all")
}
val legacyJar = target.project.registerTask<Jar>(target.legacyArtifactsTaskName)
legacyJar.configure {
it.description = "Assembles an archive containing the Kotin metadata of the commonMain source set."
if (!target.project.isCompatibilityMetadataVariantEnabled) {
it.archiveClassifier.set("commonMain")
}
it.onlyIf { target.project.isCompatibilityMetadataVariantEnabled }
it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
}
return result
@@ -499,7 +507,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
)
extendsFrom(commonMainApiConfiguration)
project.artifacts.add(name, project.tasks.getByName(target.artifactsTaskName))
project.artifacts.add(name, project.tasks.getByName(target.legacyArtifactsTaskName))
}
}