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 182e42a5d24..f870d6c5397 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 @@ -253,7 +253,7 @@ class HierarchicalMppIT : BaseGradleIT() { ZipFile( project.projectDir.parentFile.resolve( - "repo/com/example/foo/my-lib-foo-metadata/1.0/my-lib-foo-metadata-1.0-all.jar" + "repo/com/example/foo/my-lib-foo/1.0/my-lib-foo-1.0-all.jar" ) ).use { publishedMetadataJar -> publishedMetadataJar.checkAllEntryNamesArePresent( @@ -291,7 +291,7 @@ class HierarchicalMppIT : BaseGradleIT() { ZipFile( project.projectDir.parentFile.resolve( - "repo/com/example/bar/my-lib-bar-metadata/1.0/my-lib-bar-metadata-1.0-all.jar" + "repo/com/example/bar/my-lib-bar/1.0/my-lib-bar-1.0-all.jar" ) ).use { publishedMetadataJar -> publishedMetadataJar.checkAllEntryNamesArePresent( @@ -420,14 +420,21 @@ class HierarchicalMppIT : BaseGradleIT() { val compilerArgsLine = taskOutput.lines().single { "Kotlin compiler args:" in it } val classpathItems = compilerArgsLine.substringAfter("-classpath").substringBefore(" -").split(File.pathSeparator) + val actualClasspath = classpathItems.joinToString("\n") + shouldInclude.forEach { (module, sourceSet) -> - assertTrue("expected module '$module' source set '$sourceSet' on the classpath of task $taskPath") { + assertTrue( + "expected module '$module' source set '$sourceSet' on the classpath of task $taskPath. Actual classpath:\n$actualClasspath" + ) { classpathItems.any { module in it && it.contains(sourceSet, ignoreCase = true) } } } shouldNotInclude.forEach { (module, sourceSet) -> - assertTrue("not expected module '$module' source set '$sourceSet' on the compile classpath of task $taskPath") { + assertTrue( + "not expected module '$module' source set '$sourceSet' on the compile classpath of task $taskPath. " + + "Actual classpath:\n$actualClasspath" + ) { classpathItems.none { module in it && it.contains(sourceSet, ignoreCase = true) } } } @@ -469,7 +476,8 @@ class HierarchicalMppIT : BaseGradleIT() { }.toSet() }, hostSpecificSourceSets = emptySet(), - sourceSetBinaryLayout = sourceSetModuleDependencies.mapValues { SourceSetMetadataLayout.KLIB } + sourceSetBinaryLayout = sourceSetModuleDependencies.mapValues { SourceSetMetadataLayout.KLIB }, + isPublishedAsRoot = true ) } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KlibBasedMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KlibBasedMppIT.kt index 9c7ef7539bf..d5bbf3a42ae 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KlibBasedMppIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KlibBasedMppIT.kt @@ -93,10 +93,10 @@ class KlibBasedMppIT : BaseGradleIT() { checkTaskCompileClasspath( "compile${hostSpecificSourceSet.capitalize()}KotlinMetadata", listOf( - "published-producer-metadata-$hostSpecificSourceSet.klib", - "published-producer-metadata-commonMain.klib", - "published-dependency-metadata-$hostSpecificSourceSet.klib", - "published-dependency-metadata-commonMain.klib" + "published-producer-$hostSpecificSourceSet.klib", + "published-producer-commonMain.klib", + "published-dependency-$hostSpecificSourceSet.klib", + "published-dependency-commonMain.klib" ) ) } @@ -209,7 +209,7 @@ class KlibBasedMppIT : BaseGradleIT() { // Check that the metadata JAR doesn't contain the host-specific source set entries, but contains the shared-Native source set // that can be built on every host: - ZipFile(groupDir.resolve("$dependencyModuleName-metadata/1.0/$dependencyModuleName-metadata-1.0-all.jar")).use { metadataJar -> + ZipFile(groupDir.resolve("$dependencyModuleName/1.0/$dependencyModuleName-1.0-all.jar")).use { metadataJar -> assertTrue { metadataJar.entries().asSequence().none { it.name.startsWith(hostSpecificSourceSet) } } assertTrue { metadataJar.entries().asSequence().any { it.name.startsWith("linuxMain") } } } 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 0a83177d40f..52bd6ec380e 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 @@ -105,7 +105,7 @@ class NewMultiplatformIT : BaseGradleIT() { val jvmJarName = "sample-lib-jvm6/1.0/sample-lib-jvm6-1.0.jar" val jsExtension = "jar" val jsJarName = "sample-lib-nodejs/1.0/sample-lib-nodejs-1.0.$jsExtension" - val metadataJarName = "sample-lib-metadata/1.0/sample-lib-metadata-1.0.jar" + val metadataJarName = "sample-lib/1.0/sample-lib-1.0.jar" val wasmKlibName = "sample-lib-wasm32/1.0/sample-lib-wasm32-1.0.klib" val nativeKlibName = "sample-lib-$nativeHostTargetName/1.0/sample-lib-$nativeHostTargetName-1.0.klib" @@ -116,7 +116,7 @@ class NewMultiplatformIT : BaseGradleIT() { val gradleMetadata = groupDir.resolve("sample-lib/1.0/sample-lib-1.0.module").readText() assertFalse(gradleMetadata.contains(ProjectLocalConfigurations.ATTRIBUTE.name)) - listOf(jvmJarName, jsJarName, metadataJarName, wasmKlibName, nativeKlibName).forEach { + listOf(jvmJarName, jsJarName, wasmKlibName, nativeKlibName).forEach { val pom = groupDir.resolve(it.replaceAfterLast('.', "pom")) Assert.assertTrue( "$pom should contain a name section.", @@ -325,7 +325,7 @@ class NewMultiplatformIT : BaseGradleIT() { val groupDir = projectDir.resolve("repo/com/example") val jsExtension = if (jsCompilerType == LEGACY) "jar" else "klib" val jsJarName = "sample-lib-nodejs/1.0/sample-lib-nodejs-1.0.$jsExtension" - val metadataJarName = "sample-lib-metadata/1.0/sample-lib-metadata-1.0.jar" + val metadataJarName = "sample-lib/1.0/sample-lib-1.0.jar" listOf(jsJarName, metadataJarName, "sample-lib/1.0/sample-lib-1.0.module").forEach { Assert.assertTrue("$it should exist", groupDir.resolve(it).exists()) @@ -334,7 +334,7 @@ class NewMultiplatformIT : BaseGradleIT() { val gradleMetadata = groupDir.resolve("sample-lib/1.0/sample-lib-1.0.module").readText() assertFalse(gradleMetadata.contains(ProjectLocalConfigurations.ATTRIBUTE.name)) - listOf(jsJarName, metadataJarName).forEach { + jsJarName.let { val pom = groupDir.resolve(it.replaceAfterLast('.', "pom")) Assert.assertTrue( "$pom should contain a name section.", @@ -998,7 +998,6 @@ class NewMultiplatformIT : BaseGradleIT() { with(Project("sample-old-style-app", gradleVersion, "new-mpp-lib-and-app")) { setupWorkingDir() gradleBuildScript().appendText("\nallprojects { repositories { maven { url '${repoDir.toURI()}' } } }") - gradleBuildScript("app-common").modify { it.replace("com.example:sample-lib:", "com.example:sample-lib-metadata:") } gradleBuildScript("app-jvm").modify { it.replace("com.example:sample-lib:", "com.example:sample-lib-jvm6:") } gradleBuildScript("app-js").modify { it.replace("com.example:sample-lib:", "com.example:sample-lib-nodejs:") } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt index 006cf3e15da..b66861d9cbd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt @@ -246,7 +246,7 @@ internal class GranularMetadataTransformation( SourceSetVisibilityProvider(project).getVisibleSourceSets( kotlinSourceSet, sourceSetRequestedScopes, - parent, module, + if (projectStructureMetadata.isPublishedAsRoot) module else parent, module, projectStructureMetadata, resolvedToProject ) 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 445b12bd541..9dad926fe98 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 @@ -65,7 +65,9 @@ open class KotlinMetadataTarget @Inject constructor(project: Project) : } val component = - createKotlinVariant(targetName, compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME), usageContexts) + createKotlinVariant(targetName, compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME), usageContexts).apply { + publishable = false // this component is not published on its own, its variants are included in the 'root' module + } val sourcesJarTask = sourcesJarTask(project, lazy { project.kotlinExtension.sourceSets.toSet() }, null, targetName.toLowerCase()) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index f1a25312fb1..176fdc488f6 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -195,10 +195,13 @@ class KotlinMultiplatformPlugin( project.extensions.configure(PublishingExtension::class.java) { publishing -> // The root publication that references the platform specific publications as its variants: - val rootPublication = publishing.publications.create("kotlinMultiplatform", MavenPublication::class.java).apply { + publishing.publications.create("kotlinMultiplatform", MavenPublication::class.java).apply { from(kotlinSoftwareComponent) (this as MavenPublicationInternal).publishWithOriginalFileName() kotlinSoftwareComponent.publicationDelegate = this@apply + + project.multiplatformExtension.metadata {}.kotlinComponents.filterIsInstance() + .single().publicationDelegate = this@apply } // Enforce the order of creating the publications, since the metadata publication is used in the other publications: diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt index 50cf8d9203f..65f848b66a9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt @@ -68,8 +68,11 @@ data class KotlinProjectStructureMetadata( @Input val hostSpecificSourceSets: Set, + @get:Input + val isPublishedAsRoot: Boolean, + @Input - val formatVersion: String = FORMAT_VERSION_0_3 + val formatVersion: String = FORMAT_VERSION_0_3_1 ) { @Suppress("UNUSED") // Gradle input @get:Input @@ -84,6 +87,9 @@ data class KotlinProjectStructureMetadata( // + 'hostSpecific' flag for source sets internal const val FORMAT_VERSION_0_3 = "0.3" + + // + 'isPublishedInRootModule' top-level flag + internal const val FORMAT_VERSION_0_3_1 = "0.3.1" } } @@ -122,7 +128,8 @@ internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjec hostSpecificSourceSets = getHostSpecificSourceSets(project).map { it.name }.toSet(), sourceSetBinaryLayout = sourceSetsWithMetadataCompilations.keys.associate { sourceSet -> sourceSet.name to SourceSetMetadataLayout.chooseForProducingProject(project) - } + }, + isPublishedAsRoot = true ) } @@ -137,6 +144,8 @@ internal fun KotlinProjectStructureMetadata.serialize( node(ROOT_NODE_NAME) { value(FORMAT_VERSION_NODE_NAME, formatVersion) + value(PUBLISHED_AS_ROOT_NAME, isPublishedAsRoot.toString()) + multiNodes(VARIANTS_NODE_NAME) { sourceSetNamesByVariantName.forEach { (variantName, sourceSets) -> multiNodesItem(VARIANT_NODE_NAME) { @@ -232,6 +241,7 @@ internal fun parseKotlinSourceSetMetadata( val formatVersion = checkNotNull(projectStructureNode.valueNamed(FORMAT_VERSION_NODE_NAME)) val variantsNode = projectStructureNode.multiObjects(VARIANTS_NODE_NAME) + val isPublishedAsRoot = projectStructureNode.valueNamed(PUBLISHED_AS_ROOT_NAME)?.toBoolean() ?: false val sourceSetsByVariant = mutableMapOf>() variantsNode.forEach { variantNode -> @@ -274,11 +284,13 @@ internal fun parseKotlinSourceSetMetadata( sourceSetBinaryLayout, sourceSetModuleDependencies, hostSpecificSourceSets, + isPublishedAsRoot, formatVersion ) } private const val ROOT_NODE_NAME = "projectStructure" +private const val PUBLISHED_AS_ROOT_NAME = "isPublishedAsRoot" private const val FORMAT_VERSION_NODE_NAME = "formatVersion" private const val VARIANTS_NODE_NAME = "variants" private const val VARIANT_NODE_NAME = "variant" 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 fe40398b5af..ccfdaec5c5d 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 @@ -26,10 +26,13 @@ abstract class KotlinSoftwareComponent( protected val kotlinTargets: Iterable ) : SoftwareComponentInternal, ComponentWithVariants { - override fun getUsages(): Set = emptySet() + private val metadataTarget: KotlinMetadataTarget + get() = kotlinTargets.filterIsInstance().single() + + override fun getUsages(): Set = (metadataTarget.components.single() as SoftwareComponentInternal).usages override fun getVariants(): Set = - kotlinTargets.flatMap { it.components }.toSet() + kotlinTargets.minus(metadataTarget).flatMap { it.components }.toSet() override fun getName(): String = name 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 9ec71cfd519..38ec9ade5c2 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 @@ -37,8 +37,7 @@ internal class SourceSetVisibilityProvider( * Determine which source sets of the [resolvedRootMppDependency] are visible in the [visibleFrom] source set. * * This requires resolving dependencies of the compilations which [visibleFrom] takes part in, in order to find which variants the - * [resolvedRootMppDependency] got resolved to for those compilations. The [resolvedRootMppDependency] should therefore be the dependency - * on the 'root' module of the MPP (such as 'com.example:lib-foo', not 'com.example:lib-foo-metadata'). + * [resolvedRootMppDependency] got resolved to for those compilations. * * Once the variants are known, they are checked against the [dependencyProjectStructureMetadata], and the * source sets of the dependency are determined that are compiled for all those variants and thus should be visible here. 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 47d0ea3d890..15a1cbc1ce2 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 @@ -125,19 +125,14 @@ abstract class AbstractKotlinTarget( adhocVariant as SoftwareComponent - if (kotlinVariant is KotlinVariantWithMetadataVariant) { - object : ComponentWithVariants, ComponentWithCoordinates, SoftwareComponentInternal { - override fun getCoordinates() = kotlinVariant.coordinates - override fun getVariants(): Set = kotlinVariant.variants - override fun getName(): String = adhocVariant.name - override fun getUsages(): MutableSet = (adhocVariant as SoftwareComponentInternal).usages - } - } else { - object : ComponentWithCoordinates, SoftwareComponentInternal { - override fun getCoordinates() = (kotlinVariant as? ComponentWithCoordinates)?.coordinates - override fun getName(): String = adhocVariant.name - override fun getUsages(): MutableSet = (adhocVariant as SoftwareComponentInternal).usages - } + object : ComponentWithVariants, ComponentWithCoordinates, SoftwareComponentInternal { + override fun getCoordinates() = (kotlinVariant as? ComponentWithCoordinates)?.coordinates + + override fun getVariants(): Set = + (kotlinVariant as? KotlinVariantWithMetadataVariant)?.variants.orEmpty() + + override fun getName(): String = adhocVariant.name + override fun getUsages(): MutableSet = (adhocVariant as SoftwareComponentInternal).usages } }.toSet() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt index fd8dbe6b9d6..6722cb441e0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt @@ -69,8 +69,7 @@ open class KotlinVariant( override fun getName(): String = componentName ?: producingCompilation.target.targetName - override val publishable: Boolean - get() = target.publishable + override var publishable: Boolean = target.publishable override var sourcesArtifacts: Set = emptySet() internal set @@ -102,7 +101,7 @@ class JointAndroidKotlinTargetComponent( private val nestedVariants: Set, val flavorNames: List, override val sourcesArtifacts: Set - ) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal { +) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal { override fun getUsages(): Set = nestedVariants.flatMap { it.usages }.toSet() 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 f9764604578..d65e352ed30 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 @@ -143,8 +143,6 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : 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") }