From a0fbf54d11a0fca6767f6e7ee612581c0b8f1c9e Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Mon, 28 Sep 2020 16:53:15 +0300 Subject: [PATCH] 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 --- .../kotlin/gradle/HierarchicalMppIT.kt | 10 ++-- .../kotlin/gradle/NewMultiplatformIT.kt | 6 +-- .../gradle/plugin/KotlinTargetConfigurator.kt | 22 ++++---- .../gradle/plugin/mpp/KotlinMetadataTarget.kt | 8 +++ .../plugin/mpp/KotlinSoftwareComponent.kt | 6 +-- .../plugin/mpp/SourceSetVisibilityProvider.kt | 16 ++---- .../kotlin/gradle/plugin/mpp/kotlinTargets.kt | 12 +++-- .../KotlinMetadataTargetConfigurator.kt | 54 +++++++++++-------- 8 files changed, 72 insertions(+), 62 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt index 4d52b3f8a65..182e42a5d24 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt @@ -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"), diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index 14010fca230..0a83177d40f 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -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) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt index fa35af78736..3a0b61664d7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt @@ -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) { 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) + } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMetadataTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMetadataTarget.kt index 8ed308de305..445b12bd541 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMetadataTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMetadataTarget.kt @@ -20,6 +20,14 @@ internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadata open class KotlinMetadataTarget @Inject constructor(project: Project) : KotlinOnlyTarget>(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 by lazy { if (!project.isKotlinGranularMetadataEnabled) super.kotlinComponents diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt index 48c3b039a41..fe40398b5af 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt @@ -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) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt index 05f11d3b71c..9ec71cfd519 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt @@ -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() val visiblePlatformVariantNames: Set = @@ -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 diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt index 43d5e1ef66c..47d0ea3d890 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt @@ -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().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) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index 7dd98daadc3..f9764604578 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -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 { - val result = super.createArchiveTasks(target) + if (!target.project.isKotlinGranularMetadataEnabled) + return super.createArchiveTasks(target) - if (target.project.isKotlinGranularMetadataEnabled) { - target.project.locateTask(target.artifactsTaskName)!!.configure { - if (!target.project.isCompatibilityMetadataVariantEnabled) { - it.archiveClassifier.set("commonMain") - } - it.onlyIf { target.project.isCompatibilityMetadataVariantEnabled } + val result = target.project.registerTask(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(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(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)) } }