From 3fa85bf7fd6fdce52e2678134dc4ddd80a7903de Mon Sep 17 00:00:00 2001 From: Anton Lakotka Date: Tue, 29 Nov 2022 14:55:14 +0100 Subject: [PATCH] [Gradle, MPP] Publish sources as gradle variants Now when MPP library is published it will contain "sourcesElements" variant for each target and one for common code. Sources variants are published under gradle attributes that were borrowed from Java Gradle Plugin for consistency reasons. This makes it compatible with JVM tooling that rely on these attributes. ^KT-36943 Verification Pending --- .../kotlin/gradle/plugin/KotlinTarget.kt | 1 + .../gradle/plugin/KotlinTargetComponent.kt | 6 + .../gradle/plugin/KotlinTargetConfigurator.kt | 15 ++- .../gradle/plugin/mpp/AbstractKotlinTarget.kt | 48 ++++---- .../plugin/mpp/KotlinSoftwareComponent.kt | 32 +++-- .../kotlin/gradle/plugin/mpp/KotlinUsages.kt | 2 + .../kotlin/gradle/plugin/mpp/Publishing.kt | 30 +++-- .../gradle/plugin/mpp/kotlinVariants.kt | 22 +++- .../targets/android/KotlinAndroidTarget.kt | 113 ++++++++++++------ .../gradle/targets/js/KotlinJsTarget.kt | 18 ++- .../targets/native/KotlinNativeTarget.kt | 13 +- 11 files changed, 204 insertions(+), 96 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTarget.kt b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTarget.kt index 2ba2a6f4039..295104c4fce 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTarget.kt @@ -34,6 +34,7 @@ interface KotlinTarget : Named, HasAttributes { val defaultConfigurationName: String val apiElementsConfigurationName: String val runtimeElementsConfigurationName: String + val sourcesElementsConfigurationName: String val publishable: Boolean diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetComponent.kt b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetComponent.kt index 54e4e5b090a..1a52ba5d4ce 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetComponent.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetComponent.kt @@ -13,5 +13,11 @@ interface KotlinTargetComponent : SoftwareComponent { val publishable: Boolean val publishableOnCurrentHost: Boolean val defaultArtifactId: String + + @Deprecated( + message = "Sources artifacts are now published as separate variant " + + "use target.sourcesElementsConfigurationName to obtain necessary information", + replaceWith = ReplaceWith("target.sourcesElementsConfigurationName") + ) val sourcesArtifacts: Set } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt index 2f03dcb688d..1a4d18e9614 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt @@ -13,9 +13,7 @@ import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.PublishArtifact import org.gradle.api.artifacts.type.ArtifactTypeDefinition -import org.gradle.api.attributes.Attribute -import org.gradle.api.attributes.Category -import org.gradle.api.attributes.Usage +import org.gradle.api.attributes.* import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE import org.gradle.api.file.FileCollection import org.gradle.api.internal.artifacts.ArtifactAttributes @@ -200,6 +198,14 @@ abstract class AbstractKotlinTargetConfigurator } } + configurations.maybeCreate(target.sourcesElementsConfigurationName).apply { + description = "Source files of main compilation of ${target.name}." + isVisible = false + isCanBeResolved = false + isCanBeConsumed = true + configureSourcesPublicationAttributes(target) + } + if (createTestCompilation) { val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME) val compileTestsConfiguration = testCompilation.internal.configurations.deprecatedCompileConfiguration @@ -390,6 +396,9 @@ internal fun Project.usageByName(usageName: String): Usage = internal fun Project.categoryByName(categoryName: String): Category = objects.named(Category::class.java, categoryName) +internal inline fun Project.attributeValueByName(attributeValueName: String): T = + objects.named(T::class.java, attributeValueName) + fun Configuration.usesPlatformOf(target: KotlinTarget): Configuration { attributes.attribute(KotlinPlatformType.attribute, target.platformType) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/AbstractKotlinTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/AbstractKotlinTarget.kt index 5582eeb63d1..bafcd9ec090 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/AbstractKotlinTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/AbstractKotlinTarget.kt @@ -50,6 +50,9 @@ abstract class AbstractKotlinTarget( override val runtimeElementsConfigurationName: String get() = disambiguateName("runtimeElements") + override val sourcesElementsConfigurationName: String + get() = disambiguateName("sourcesElements") + override val artifactsTaskName: String get() = disambiguateName("jar") @@ -61,18 +64,24 @@ abstract class AbstractKotlinTarget( @InternalKotlinGradlePluginApi override val kotlinComponents: Set by lazy { val mainCompilation = compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) - val usageContexts = createUsageContexts(mainCompilation) + val usageContexts = createUsageContexts(mainCompilation).toMutableSet() val componentName = if (project.kotlinExtension is KotlinMultiplatformExtension) targetName else PRIMARY_SINGLE_COMPONENT_NAME - val result = createKotlinVariant(componentName, mainCompilation, usageContexts) + val sourcesArtifact = configureSourcesJarArtifact(mainCompilation, componentName, dashSeparatedName(targetName.toLowerCase())) + if (sourcesArtifact != null) { + usageContexts += DefaultKotlinUsageContext( + compilation = mainCompilation, + dependencyConfigurationName = sourcesElementsConfigurationName, + includeIntoProjectStructureMetadata = false, + includeDependenciesToMavenPublication = false, + ) + } - result.sourcesArtifacts = setOf( - sourcesJarArtifact(mainCompilation, componentName, dashSeparatedName(targetName.toLowerCase())) - ) + val result = createKotlinVariant(componentName, mainCompilation, usageContexts) setOf(result) } @@ -117,28 +126,21 @@ abstract class AbstractKotlinTarget( } } - protected fun sourcesJarArtifact( + protected fun configureSourcesJarArtifact( producingCompilation: KotlinCompilation<*>, componentName: String, artifactNameAppendix: String, - classifierPrefix: String? = null - ): PublishArtifact { - val sourcesJarTask = sourcesJarTask(producingCompilation, componentName, artifactNameAppendix) - val sourceArtifactConfigurationName = producingCompilation.disambiguateName("sourceArtifacts") + classifierPrefix: String? = null, + sourcesElementsConfigurationName: String = this.sourcesElementsConfigurationName, + ): PublishArtifact? { + // If sourcesElements configuration not found, don't create artifact. + // This can happen in pure JVM plugin where source publication is delegated to Java Gradle Plugin + project.configurations.findByName(sourcesElementsConfigurationName) ?: return null - return with(producingCompilation.target.project) { - (configurations.findByName(sourceArtifactConfigurationName) ?: run { - val configuration = configurations.create(sourceArtifactConfigurationName) { - it.isCanBeResolved = false - it.isCanBeConsumed = false - } - artifacts.add(sourceArtifactConfigurationName, sourcesJarTask) - configuration - }).artifacts.single().apply { - this as ConfigurablePublishArtifact - classifier = dashSeparatedName(classifierPrefix, "sources") - } - } + val sourcesJarTask = sourcesJarTask(producingCompilation, componentName, artifactNameAppendix) + val artifact = project.artifacts.add(sourcesElementsConfigurationName, sourcesJarTask) as ConfigurablePublishArtifact + artifact.classifier = dashSeparatedName(classifierPrefix, "sources") + return artifact } @Suppress("UNCHECKED_CAST") diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt index 18655b3c4ef..e70c89f5db8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt @@ -7,9 +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.attributes.* import org.gradle.api.capabilities.Capability import org.gradle.api.component.ComponentWithCoordinates import org.gradle.api.component.ComponentWithVariants @@ -19,12 +17,12 @@ import org.gradle.api.internal.component.UsageContext import org.gradle.api.provider.SetProperty import org.gradle.api.publish.maven.MavenPublication import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME -import org.jetbrains.kotlin.gradle.plugin.KotlinTarget -import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations -import org.jetbrains.kotlin.gradle.plugin.usageByName import org.jetbrains.kotlin.gradle.targets.metadata.* +import org.jetbrains.kotlin.gradle.targets.metadata.COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME +import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVariantEnabled +import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.utils.setProperty abstract class KotlinSoftwareComponent( @@ -35,6 +33,8 @@ abstract class KotlinSoftwareComponent( override fun getName(): String = name + private val metadataTarget get() = project.multiplatformExtension.metadata() + override fun getVariants(): Set = kotlinTargets .filter { target -> target !is KotlinMetadataTarget } .flatMap { target -> @@ -47,8 +47,6 @@ abstract class KotlinSoftwareComponent( }.toSet() private val _usages: Set by lazy { - val metadataTarget = project.multiplatformExtension.metadata() - if (!project.isKotlinGranularMetadataEnabled) { val metadataCompilation = metadataTarget.compilations.getByName(MAIN_COMPILATION_NAME) return@lazy metadataTarget.createUsageContexts(metadataCompilation) @@ -80,6 +78,14 @@ abstract class KotlinSoftwareComponent( ) } } + + configureSourcesJarArtifact() + this += DefaultKotlinUsageContext( + compilation = metadataTarget.compilations.getByName(MAIN_COMPILATION_NAME), + dependencyConfigurationName = metadataTarget.sourcesElementsConfigurationName, + includeIntoProjectStructureMetadata = false, + includeDependenciesToMavenPublication = false + ) } } @@ -87,7 +93,7 @@ abstract class KotlinSoftwareComponent( return _usages } - val sourcesArtifacts: Set by lazy { + private fun configureSourcesJarArtifact(): PublishArtifact { fun allPublishableCommonSourceSets() = getCommonSourceSetsForMetadataCompilation(project) + getHostSpecificMainSharedSourceSets(project) @@ -98,10 +104,10 @@ abstract class KotlinSoftwareComponent( lazy { allPublishableCommonSourceSets().associate { it.name to it.kotlin } }, name.toLowerCase() ) - val sourcesJarArtifact = project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, sourcesJarTask) { sourcesJarArtifact -> + + return project.artifacts.add(metadataTarget.sourcesElementsConfigurationName, sourcesJarTask) { sourcesJarArtifact -> sourcesJarArtifact.classifier = "sources" } - setOf(sourcesJarArtifact) } // This property is declared in the parent type to allow the usages to reference it without forcing the subtypes to load, @@ -214,4 +220,4 @@ class DefaultKotlinUsageContext( */ it.name != "org.gradle.jvm.environment" } -} +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt index 67ab6dae560..a4de2c6f430 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt @@ -61,6 +61,8 @@ object KotlinUsages { internal fun producerRuntimeUsage(project: Project, platformType: KotlinPlatformType) = project.usageByName( when (platformType) { + // This attribute is deprecated in Gradle and additionally to Usage attribute + // it implicitly adds `org.gradle.libraryelements=jar` in jvmPlatformTypes -> "java-runtime-jars" else -> KOTLIN_RUNTIME } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/Publishing.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/Publishing.kt index b713e338e73..3613a2cb66f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/Publishing.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/Publishing.kt @@ -6,6 +6,11 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.Bundling +import org.gradle.api.attributes.Category +import org.gradle.api.attributes.DocsType +import org.gradle.api.attributes.Usage import org.gradle.api.provider.Provider import org.gradle.api.publish.PublicationContainer import org.gradle.api.publish.PublishingExtension @@ -14,7 +19,7 @@ import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope @@ -41,9 +46,6 @@ private fun createRootPublication(project: Project, publishing: PublishingExtens from(kotlinSoftwareComponent) (this as MavenPublicationInternal).publishWithOriginalFileName() kotlinSoftwareComponent.publicationDelegate = this@apply - kotlinSoftwareComponent.sourcesArtifacts.forEach { sourceArtifact -> - artifact(sourceArtifact) - } addKotlinToolingMetadataArtifactIfNeeded(project) } @@ -82,9 +84,6 @@ private fun InternalKotlinTarget.createMavenPublications(publications: Publicati // do this in whenEvaluated since older Gradle versions seem to check the files in the variant eagerly: project.whenEvaluated { from(gradleComponent) - kotlinComponent.sourcesArtifacts.forEach { sourceArtifact -> - artifact(sourceArtifact) - } } (this as MavenPublicationInternal).publishWithOriginalFileName() artifactId = kotlinComponent.defaultArtifactId @@ -144,3 +143,20 @@ private fun dependenciesForPomRewriting(target: InternalKotlinTarget): Provider< commonMainDependencies.map { ModuleCoordinates(it.group, it.name, it.version) }.toSet() } } + +internal fun Configuration.configureSourcesPublicationAttributes(target: KotlinTarget) { + val project = target.project + + // In order to be consistent with Java Gradle Plugin, set usage attribute for sources variant + // to be either JAVA_RUNTIME (for jvm) or KOTLIN_RUNTIME (for other targets) + // the latter isn't a strong requirement since there is no tooling that consume kotlin sources through gradle variants at the moment + // so consistency with Java Gradle Plugin seemed most desirable choice. + attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(target)) + attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.attributeValueByName(Category.DOCUMENTATION)) + attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE, project.attributeValueByName(DocsType.SOURCES)) + // Bundling attribute is about component dependencies, external means that they are provided as separate components + // source variants doesn't have any dependencies (at least at the moment) so there is not much sense to use this attribute + // however for Java Gradle Plugin compatibility and in order to prevent weird Variant Resolution errors we include this attribute + attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, project.attributeValueByName(Bundling.EXTERNAL)) + usesPlatformOf(target) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt index 67c832e37db..ca627009f22 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt @@ -74,8 +74,16 @@ open class KotlinVariant( override val publishableOnCurrentHost: Boolean get() = publishable && target.publishable - override var sourcesArtifacts: Set = emptySet() - internal set + @Deprecated( + message = "Sources artifacts are now published as separate variant " + + "use target.sourcesElementsConfigurationName to obtain necessary information", + replaceWith = ReplaceWith("target.sourcesElementsConfigurationName") ) + override val sourcesArtifacts: Set get() = target + .project + .configurations + .findByName(target.sourcesElementsConfigurationName) + ?.artifacts + ?: emptySet() internal var defaultArtifactIdSuffix: String? = null @@ -102,8 +110,7 @@ class KotlinVariantWithMetadataVariant( class JointAndroidKotlinTargetComponent( override val target: KotlinAndroidTarget, private val nestedVariants: Set, - val flavorNames: List, - override val sourcesArtifacts: Set + val flavorNames: List ) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal { override fun getUsages(): Set = nestedVariants.filter { it.publishable }.flatMap { it.usages }.toSet() @@ -124,4 +131,11 @@ class JointAndroidKotlinTargetComponent( ) override var publicationDelegate: MavenPublication? = null + + @Deprecated( + message = "Sources artifacts are now published as separate variant " + + "use target.sourcesElementsConfigurationName to obtain necessary information", + replaceWith = ReplaceWith("target.sourcesElementsConfigurationName") + ) + override val sourcesArtifacts: Set = emptySet() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt index e174900854f..07da5012d00 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt @@ -11,9 +11,10 @@ import org.gradle.api.InvalidUserDataException import org.gradle.api.Named import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project -import org.gradle.api.attributes.Attribute -import org.gradle.api.attributes.Usage.JAVA_RUNTIME_JARS +import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.* import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes import org.jetbrains.kotlin.gradle.utils.dashSeparatedName import org.jetbrains.kotlin.gradle.utils.forAllAndroidVariants import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName @@ -120,33 +121,18 @@ abstract class KotlinAndroidTarget @Inject constructor( val androidVariantName = getVariantName(androidVariant) val compilation = compilations.getByName(androidVariantName) - val flavorNames = getFlavorNames(androidVariant) - val buildTypeName = getBuildTypeName(androidVariant) - - val artifactClassifier = buildTypeName.takeIf { it != "release" && publishLibraryVariantsGroupedByFlavor } + val usageContexts = createAndroidUsageContexts( + variant = androidVariant, + compilation = compilation, + isSingleBuildType = publishableVariants.filter(::isVariantPublished).map(::getBuildTypeName).distinct().size == 1, + ) createKotlinVariant( lowerCamelCaseName(compilation.target.name, *flavorGroupNameParts.toTypedArray()), compilation, - createAndroidUsageContexts( - androidVariant, - compilation, - artifactClassifier, - publishableVariants.filter(::isVariantPublished).map(::getBuildTypeName).distinct().size == 1 - ) + usageContexts, ).apply { publishable = isVariantPublished(androidVariant) - sourcesArtifacts = setOf( - sourcesJarArtifact( - compilation, compilation.disambiguateName(""), - dashSeparatedName( - compilation.target.name.toLowerCase(), - *flavorNames.map { it.toLowerCase() }.toTypedArray(), - buildTypeName.takeIf { it != "release" }?.toLowerCase() - ), - classifierPrefix = artifactClassifier - ) - ) if (!publishLibraryVariantsGroupedByFlavor) { defaultArtifactIdSuffix = @@ -163,7 +149,6 @@ abstract class KotlinAndroidTarget @Inject constructor( target = this@KotlinAndroidTarget, nestedVariants = nestedVariants, flavorNames = flavorGroupNameParts, - sourcesArtifacts = nestedVariants.filter { it.publishable }.flatMap { it.sourcesArtifacts }.toSet() ) } else { nestedVariants.single() @@ -174,9 +159,12 @@ abstract class KotlinAndroidTarget @Inject constructor( private fun AndroidProjectHandler.createAndroidUsageContexts( variant: BaseVariant, compilation: KotlinCompilation<*>, - artifactClassifier: String?, - isSingleBuildType: Boolean + isSingleBuildType: Boolean, ): Set { + val flavorNames = getFlavorNames(variant) + val buildTypeName = getBuildTypeName(variant) + val artifactClassifier = buildTypeName.takeIf { it != "release" && publishLibraryVariantsGroupedByFlavor } + val variantName = getVariantName(variant) val outputTaskOrProvider = getLibraryOutputTask(variant) ?: return emptySet() val artifact = run { @@ -193,9 +181,46 @@ abstract class KotlinAndroidTarget @Inject constructor( val apiElementsConfigurationName = lowerCamelCaseName(variantName, "apiElements") val runtimeElementsConfigurationName = lowerCamelCaseName(variantName, "runtimeElements") + val sourcesElementsConfigurationName = lowerCamelCaseName(variantName, "sourcesElements") + val sourcesElementsConfiguration = createSourcesElementsIfNeeded( + variantName, + apiElementsConfigurationName, + sourcesElementsConfigurationName + ) + configureSourcesJarArtifact( + compilation, + compilation.disambiguateName(""), + dashSeparatedName( + compilation.target.name.toLowerCase(), + *flavorNames.map { it.toLowerCase() }.toTypedArray(), + buildTypeName.takeIf { it != "release" }?.toLowerCase() + ), + classifierPrefix = artifactClassifier, + sourcesElementsConfigurationName = sourcesElementsConfigurationName + ) + + fun AttributeContainer.filterOutAndroidVariantAttributes(): AttributeContainer = + HierarchyAttributeContainer(this) { + val valueString = run { + val value = getAttribute(it) + (value as? Named)?.name ?: value.toString() + } + filterOutAndroidVariantAttribute(it) && + filterOutAndroidBuildTypeAttribute(it, valueString, isSingleBuildType) && + filterOutAndroidAgpVersionAttribute(it) + } + + val sourcesUsageContext = DefaultKotlinUsageContext( + compilation = compilation, + dependencyConfigurationName = sourcesElementsConfigurationName, + overrideConfigurationAttributes = sourcesElementsConfiguration.attributes.filterOutAndroidVariantAttributes(), + includeDependenciesToMavenPublication = false, + includeIntoProjectStructureMetadata = false + ) + return listOf( apiElementsConfigurationName to KotlinUsageContext.UsageScope.COMPILE, - runtimeElementsConfigurationName to KotlinUsageContext.UsageScope.RUNTIME + runtimeElementsConfigurationName to KotlinUsageContext.UsageScope.RUNTIME, ).mapTo(mutableSetOf()) { (dependencyConfigurationName, mavenScope) -> val configuration = project.configurations.getByName(dependencyConfigurationName) DefaultKotlinUsageContext( @@ -203,16 +228,32 @@ abstract class KotlinAndroidTarget @Inject constructor( mavenScope, dependencyConfigurationName, overrideConfigurationArtifacts = project.setProperty { listOf(artifact) }, - overrideConfigurationAttributes = HierarchyAttributeContainer(configuration.attributes) { - val valueString = run { - val value = configuration.attributes.getAttribute(it) - (value as? Named)?.name ?: value.toString() - } - filterOutAndroidVariantAttribute(it) && - filterOutAndroidBuildTypeAttribute(it, valueString, isSingleBuildType) && - filterOutAndroidAgpVersionAttribute(it) - } + overrideConfigurationAttributes = configuration.attributes.filterOutAndroidVariantAttributes() ) + } + sourcesUsageContext + } + + /** + * TODO: Ask Google about providing such configuration where they could set their attributes and control them. + * Just like as they do with apiElements or runtimeElements + */ + private fun createSourcesElementsIfNeeded( + variantName: String, + apiElementsConfigurationName: String, + sourcesElementsConfigurationName: String + ): Configuration { + val existingConfiguration = project.configurations.findByName(sourcesElementsConfigurationName) + if (existingConfiguration != null) return existingConfiguration + + val apiElementsConfiguration = project.configurations.getByName(apiElementsConfigurationName) + return project.configurations.create(sourcesElementsConfigurationName).apply { + description = "Source files of Android ${variantName}." + isVisible = false + isCanBeResolved = false + isCanBeConsumed = true + + copyAttributes(apiElementsConfiguration.attributes, attributes) + configureSourcesPublicationAttributes(this@KotlinAndroidTarget) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTarget.kt index 82310dd494e..9eb4118a8f8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTarget.kt @@ -71,20 +71,26 @@ constructor( super.kotlinComponents else { val mainCompilation = compilations.getByName(MAIN_COMPILATION_NAME) - val usageContexts = createUsageContexts(mainCompilation) + - irTarget!!.createUsageContexts(irTarget!!.compilations.getByName(MAIN_COMPILATION_NAME)) + val usageContexts = createUsageContexts(mainCompilation).toMutableSet() + + usageContexts += irTarget!!.createUsageContexts(irTarget!!.compilations.getByName(MAIN_COMPILATION_NAME)) val componentName = if (project.kotlinExtension is KotlinMultiplatformExtension) irTarget?.let { targetName.removeJsCompilerSuffix(LEGACY) } ?: targetName else PRIMARY_SINGLE_COMPONENT_NAME - val result = createKotlinVariant(componentName, mainCompilation, usageContexts) - - result.sourcesArtifacts = setOf( - sourcesJarArtifact(mainCompilation, componentName, dashSeparatedName(targetName.toLowerCase())) + configureSourcesJarArtifact(mainCompilation, componentName, dashSeparatedName(targetName.toLowerCase())) + usageContexts += DefaultKotlinUsageContext( + compilation = mainCompilation, + usageScope = KotlinUsageContext.UsageScope.RUNTIME, + dependencyConfigurationName = sourcesElementsConfigurationName, + includeIntoProjectStructureMetadata = false, + includeDependenciesToMavenPublication = false, ) + val result = createKotlinVariant(componentName, mainCompilation, usageContexts) + setOf(result) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt index adbdefc8912..fa92661c80c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt @@ -101,11 +101,16 @@ abstract class KotlinNativeTarget @Inject constructor( } } - val result = createKotlinVariant(targetName, mainCompilation, mutableUsageContexts) - - result.sourcesArtifacts = setOf( - sourcesJarArtifact(mainCompilation, targetName, dashSeparatedName(targetName.toLowerCase())) + configureSourcesJarArtifact(mainCompilation, targetName, dashSeparatedName(targetName.toLowerCase())) + val sourcesUsage = DefaultKotlinUsageContext( + compilation = mainCompilation, + dependencyConfigurationName = sourcesElementsConfigurationName, + includeIntoProjectStructureMetadata = false, + includeDependenciesToMavenPublication = false, ) + mutableUsageContexts += sourcesUsage + + val result = createKotlinVariant(targetName, mainCompilation, mutableUsageContexts) setOf(result) }