From 43de81e4c862389d991f3a06096f081df17988a7 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Tue, 12 Feb 2019 20:01:04 +0300 Subject: [PATCH] Fix MPP publishing with metadata on Gradle 5.2 (KT-29758) In publishing, use attribute containers of detached configuration instead of HierarchyAttributeContainer, which is rejected by Gradle for not being an AttributeContainerInternal. Using attributes of a detached configuration is a small and conservative fix; we may need to either not filter the attributes, which will lead to [ProjectLocalConfigurations.ATTRIBUTE] being published in the Gradle module metadata, which will potentially complicate our attributes schema migration, or create proper, non-detached configurations for publishing that are separated from the configurations used for project-to-project dependencies. Issue #KT-29758 Fixed --- .../plugin/mpp/HierarchyAttributeContainer.kt | 7 ++++++ .../plugin/mpp/KotlinSoftwareComponent.kt | 25 +++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/HierarchyAttributeContainer.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/HierarchyAttributeContainer.kt index f1e5a9d50a1..4bfd0f77be2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/HierarchyAttributeContainer.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/HierarchyAttributeContainer.kt @@ -20,6 +20,13 @@ import org.gradle.api.attributes.AttributeContainer import java.util.* // TODO better implementation: attribute invariants (no attrs with same name and different types allowed), thread safety? +/** An attribute container that delegates attributes lookup to the [parent] when the key matches [filterParentAttributes] and is missing + * in this container. + * + * This container should never be passed to any Gradle API, as Gradle assumes all [AttributeContainer] instances to + * implement AttributeContainerInternal. + * TODO expose Kotlin-specific API to the users, convert the user attributes to Gradle attributes internally + */ class HierarchyAttributeContainer( val parent: AttributeContainer?, val filterParentAttributes: (Attribute<*>) -> Boolean = { true } 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 ceb6a1b0059..b017e957662 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 @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project import org.gradle.api.artifacts.* +import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.AttributeContainer import org.gradle.api.attributes.Usage import org.gradle.api.capabilities.Capability @@ -85,8 +86,28 @@ class DefaultKotlinUsageContext( // TODO Gradle Java plugin does that in a different way; check whether we can improve this configuration.artifacts - override fun getAttributes(): AttributeContainer = - HierarchyAttributeContainer(configuration.outgoing.attributes) { it != ProjectLocalConfigurations.ATTRIBUTE } + override fun getAttributes(): AttributeContainer { + val configurationAttributes = configuration.attributes + + /** TODO Using attributes of a detached configuration is a small and 'conservative' fix for KT-29758, [HierarchyAttributeContainer] + * being rejected by Gradle 5.2+; we may need to either not filter the attributes, which will lead to + * [ProjectLocalConfigurations.ATTRIBUTE] being published in the Gradle module metadata, which will potentially complicate our + * attributes schema migration, or create proper, non-detached configurations for publishing that are separated from the + * configurations used for project-to-project dependencies + */ + val result = project.configurations.detachedConfiguration().attributes + + // Capture type parameter T: + fun copyAttribute(attribute: Attribute, from: AttributeContainer, to: AttributeContainer) { + to.attribute(attribute, from.getAttribute(attribute)!!) + } + + configurationAttributes.keySet() + .filter { it != ProjectLocalConfigurations.ATTRIBUTE } + .forEach { copyAttribute(it, configurationAttributes, result) } + + return result + } override fun getCapabilities(): Set = emptySet()