Publish MPP -metadata artifact in the root module, drop separate module

Until now, there was a separate module foo-metadata that contained the
Kotlin metadata artifacts. The reasons for this were only historical,
namely the platform modules used to depend on the metadata module and
expect it to bring the common sources to the IDE.

Now we don't really need the -metadata module, and it's now more harm
from it than good, as users never need to specify it as a dependency.

We fix this by removing the -metadata module from the default publishing
layout and putting the -metadata artifact(-s) directly to the root
module.
This commit is contained in:
Sergey Igushkin
2020-09-29 16:29:35 +03:00
parent a0fbf54d11
commit 7d1a3a137b
12 changed files with 60 additions and 42 deletions
@@ -253,7 +253,7 @@ class HierarchicalMppIT : BaseGradleIT() {
ZipFile( ZipFile(
project.projectDir.parentFile.resolve( 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 -> ).use { publishedMetadataJar ->
publishedMetadataJar.checkAllEntryNamesArePresent( publishedMetadataJar.checkAllEntryNamesArePresent(
@@ -291,7 +291,7 @@ class HierarchicalMppIT : BaseGradleIT() {
ZipFile( ZipFile(
project.projectDir.parentFile.resolve( 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 -> ).use { publishedMetadataJar ->
publishedMetadataJar.checkAllEntryNamesArePresent( publishedMetadataJar.checkAllEntryNamesArePresent(
@@ -420,14 +420,21 @@ class HierarchicalMppIT : BaseGradleIT() {
val compilerArgsLine = taskOutput.lines().single { "Kotlin compiler args:" in it } val compilerArgsLine = taskOutput.lines().single { "Kotlin compiler args:" in it }
val classpathItems = compilerArgsLine.substringAfter("-classpath").substringBefore(" -").split(File.pathSeparator) val classpathItems = compilerArgsLine.substringAfter("-classpath").substringBefore(" -").split(File.pathSeparator)
val actualClasspath = classpathItems.joinToString("\n")
shouldInclude.forEach { (module, sourceSet) -> 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) } classpathItems.any { module in it && it.contains(sourceSet, ignoreCase = true) }
} }
} }
shouldNotInclude.forEach { (module, sourceSet) -> 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) } classpathItems.none { module in it && it.contains(sourceSet, ignoreCase = true) }
} }
} }
@@ -469,7 +476,8 @@ class HierarchicalMppIT : BaseGradleIT() {
}.toSet() }.toSet()
}, },
hostSpecificSourceSets = emptySet(), hostSpecificSourceSets = emptySet(),
sourceSetBinaryLayout = sourceSetModuleDependencies.mapValues { SourceSetMetadataLayout.KLIB } sourceSetBinaryLayout = sourceSetModuleDependencies.mapValues { SourceSetMetadataLayout.KLIB },
isPublishedAsRoot = true
) )
} }
@@ -93,10 +93,10 @@ class KlibBasedMppIT : BaseGradleIT() {
checkTaskCompileClasspath( checkTaskCompileClasspath(
"compile${hostSpecificSourceSet.capitalize()}KotlinMetadata", "compile${hostSpecificSourceSet.capitalize()}KotlinMetadata",
listOf( listOf(
"published-producer-metadata-$hostSpecificSourceSet.klib", "published-producer-$hostSpecificSourceSet.klib",
"published-producer-metadata-commonMain.klib", "published-producer-commonMain.klib",
"published-dependency-metadata-$hostSpecificSourceSet.klib", "published-dependency-$hostSpecificSourceSet.klib",
"published-dependency-metadata-commonMain.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 // 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: // 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().none { it.name.startsWith(hostSpecificSourceSet) } }
assertTrue { metadataJar.entries().asSequence().any { it.name.startsWith("linuxMain") } } assertTrue { metadataJar.entries().asSequence().any { it.name.startsWith("linuxMain") } }
} }
@@ -105,7 +105,7 @@ class NewMultiplatformIT : BaseGradleIT() {
val jvmJarName = "sample-lib-jvm6/1.0/sample-lib-jvm6-1.0.jar" val jvmJarName = "sample-lib-jvm6/1.0/sample-lib-jvm6-1.0.jar"
val jsExtension = "jar" val jsExtension = "jar"
val jsJarName = "sample-lib-nodejs/1.0/sample-lib-nodejs-1.0.$jsExtension" 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 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" 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() val gradleMetadata = groupDir.resolve("sample-lib/1.0/sample-lib-1.0.module").readText()
assertFalse(gradleMetadata.contains(ProjectLocalConfigurations.ATTRIBUTE.name)) 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")) val pom = groupDir.resolve(it.replaceAfterLast('.', "pom"))
Assert.assertTrue( Assert.assertTrue(
"$pom should contain a name section.", "$pom should contain a name section.",
@@ -325,7 +325,7 @@ class NewMultiplatformIT : BaseGradleIT() {
val groupDir = projectDir.resolve("repo/com/example") val groupDir = projectDir.resolve("repo/com/example")
val jsExtension = if (jsCompilerType == LEGACY) "jar" else "klib" val jsExtension = if (jsCompilerType == LEGACY) "jar" else "klib"
val jsJarName = "sample-lib-nodejs/1.0/sample-lib-nodejs-1.0.$jsExtension" 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 { listOf(jsJarName, metadataJarName, "sample-lib/1.0/sample-lib-1.0.module").forEach {
Assert.assertTrue("$it should exist", groupDir.resolve(it).exists()) 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() val gradleMetadata = groupDir.resolve("sample-lib/1.0/sample-lib-1.0.module").readText()
assertFalse(gradleMetadata.contains(ProjectLocalConfigurations.ATTRIBUTE.name)) assertFalse(gradleMetadata.contains(ProjectLocalConfigurations.ATTRIBUTE.name))
listOf(jsJarName, metadataJarName).forEach { jsJarName.let {
val pom = groupDir.resolve(it.replaceAfterLast('.', "pom")) val pom = groupDir.resolve(it.replaceAfterLast('.', "pom"))
Assert.assertTrue( Assert.assertTrue(
"$pom should contain a name section.", "$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")) { with(Project("sample-old-style-app", gradleVersion, "new-mpp-lib-and-app")) {
setupWorkingDir() setupWorkingDir()
gradleBuildScript().appendText("\nallprojects { repositories { maven { url '${repoDir.toURI()}' } } }") 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-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:") } gradleBuildScript("app-js").modify { it.replace("com.example:sample-lib:", "com.example:sample-lib-nodejs:") }
@@ -246,7 +246,7 @@ internal class GranularMetadataTransformation(
SourceSetVisibilityProvider(project).getVisibleSourceSets( SourceSetVisibilityProvider(project).getVisibleSourceSets(
kotlinSourceSet, kotlinSourceSet,
sourceSetRequestedScopes, sourceSetRequestedScopes,
parent, module, if (projectStructureMetadata.isPublishedAsRoot) module else parent, module,
projectStructureMetadata, projectStructureMetadata,
resolvedToProject resolvedToProject
) )
@@ -65,7 +65,9 @@ open class KotlinMetadataTarget @Inject constructor(project: Project) :
} }
val component = 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 = val sourcesJarTask =
sourcesJarTask(project, lazy { project.kotlinExtension.sourceSets.toSet() }, null, targetName.toLowerCase()) sourcesJarTask(project, lazy { project.kotlinExtension.sourceSets.toSet() }, null, targetName.toLowerCase())
@@ -195,10 +195,13 @@ class KotlinMultiplatformPlugin(
project.extensions.configure(PublishingExtension::class.java) { publishing -> project.extensions.configure(PublishingExtension::class.java) { publishing ->
// The root publication that references the platform specific publications as its variants: // 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) from(kotlinSoftwareComponent)
(this as MavenPublicationInternal).publishWithOriginalFileName() (this as MavenPublicationInternal).publishWithOriginalFileName()
kotlinSoftwareComponent.publicationDelegate = this@apply kotlinSoftwareComponent.publicationDelegate = this@apply
project.multiplatformExtension.metadata {}.kotlinComponents.filterIsInstance<KotlinTargetComponentWithPublication>()
.single().publicationDelegate = this@apply
} }
// Enforce the order of creating the publications, since the metadata publication is used in the other publications: // Enforce the order of creating the publications, since the metadata publication is used in the other publications:
@@ -68,8 +68,11 @@ data class KotlinProjectStructureMetadata(
@Input @Input
val hostSpecificSourceSets: Set<String>, val hostSpecificSourceSets: Set<String>,
@get:Input
val isPublishedAsRoot: Boolean,
@Input @Input
val formatVersion: String = FORMAT_VERSION_0_3 val formatVersion: String = FORMAT_VERSION_0_3_1
) { ) {
@Suppress("UNUSED") // Gradle input @Suppress("UNUSED") // Gradle input
@get:Input @get:Input
@@ -84,6 +87,9 @@ data class KotlinProjectStructureMetadata(
// + 'hostSpecific' flag for source sets // + 'hostSpecific' flag for source sets
internal const val FORMAT_VERSION_0_3 = "0.3" 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(), hostSpecificSourceSets = getHostSpecificSourceSets(project).map { it.name }.toSet(),
sourceSetBinaryLayout = sourceSetsWithMetadataCompilations.keys.associate { sourceSet -> sourceSetBinaryLayout = sourceSetsWithMetadataCompilations.keys.associate { sourceSet ->
sourceSet.name to SourceSetMetadataLayout.chooseForProducingProject(project) sourceSet.name to SourceSetMetadataLayout.chooseForProducingProject(project)
} },
isPublishedAsRoot = true
) )
} }
@@ -137,6 +144,8 @@ internal fun <Serializer> KotlinProjectStructureMetadata.serialize(
node(ROOT_NODE_NAME) { node(ROOT_NODE_NAME) {
value(FORMAT_VERSION_NODE_NAME, formatVersion) value(FORMAT_VERSION_NODE_NAME, formatVersion)
value(PUBLISHED_AS_ROOT_NAME, isPublishedAsRoot.toString())
multiNodes(VARIANTS_NODE_NAME) { multiNodes(VARIANTS_NODE_NAME) {
sourceSetNamesByVariantName.forEach { (variantName, sourceSets) -> sourceSetNamesByVariantName.forEach { (variantName, sourceSets) ->
multiNodesItem(VARIANT_NODE_NAME) { multiNodesItem(VARIANT_NODE_NAME) {
@@ -232,6 +241,7 @@ internal fun <ParsingContext> parseKotlinSourceSetMetadata(
val formatVersion = checkNotNull(projectStructureNode.valueNamed(FORMAT_VERSION_NODE_NAME)) val formatVersion = checkNotNull(projectStructureNode.valueNamed(FORMAT_VERSION_NODE_NAME))
val variantsNode = projectStructureNode.multiObjects(VARIANTS_NODE_NAME) val variantsNode = projectStructureNode.multiObjects(VARIANTS_NODE_NAME)
val isPublishedAsRoot = projectStructureNode.valueNamed(PUBLISHED_AS_ROOT_NAME)?.toBoolean() ?: false
val sourceSetsByVariant = mutableMapOf<String, Set<String>>() val sourceSetsByVariant = mutableMapOf<String, Set<String>>()
variantsNode.forEach { variantNode -> variantsNode.forEach { variantNode ->
@@ -274,11 +284,13 @@ internal fun <ParsingContext> parseKotlinSourceSetMetadata(
sourceSetBinaryLayout, sourceSetBinaryLayout,
sourceSetModuleDependencies, sourceSetModuleDependencies,
hostSpecificSourceSets, hostSpecificSourceSets,
isPublishedAsRoot,
formatVersion formatVersion
) )
} }
private const val ROOT_NODE_NAME = "projectStructure" 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 FORMAT_VERSION_NODE_NAME = "formatVersion"
private const val VARIANTS_NODE_NAME = "variants" private const val VARIANTS_NODE_NAME = "variants"
private const val VARIANT_NODE_NAME = "variant" private const val VARIANT_NODE_NAME = "variant"
@@ -26,10 +26,13 @@ abstract class KotlinSoftwareComponent(
protected val kotlinTargets: Iterable<KotlinTarget> protected val kotlinTargets: Iterable<KotlinTarget>
) : SoftwareComponentInternal, ComponentWithVariants { ) : SoftwareComponentInternal, ComponentWithVariants {
override fun getUsages(): Set<UsageContext> = emptySet() private val metadataTarget: KotlinMetadataTarget
get() = kotlinTargets.filterIsInstance<KotlinMetadataTarget>().single()
override fun getUsages(): Set<UsageContext> = (metadataTarget.components.single() as SoftwareComponentInternal).usages
override fun getVariants(): Set<SoftwareComponent> = override fun getVariants(): Set<SoftwareComponent> =
kotlinTargets.flatMap { it.components }.toSet() kotlinTargets.minus(metadataTarget).flatMap { it.components }.toSet()
override fun getName(): String = name override fun getName(): String = name
@@ -37,8 +37,7 @@ internal class SourceSetVisibilityProvider(
* Determine which source sets of the [resolvedRootMppDependency] are visible in the [visibleFrom] source set. * 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 * 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 * [resolvedRootMppDependency] got resolved to for those compilations.
* on the 'root' module of the MPP (such as 'com.example:lib-foo', not 'com.example:lib-foo-metadata').
* *
* Once the variants are known, they are checked against the [dependencyProjectStructureMetadata], and the * 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. * source sets of the dependency are determined that are compiled for all those variants and thus should be visible here.
@@ -125,19 +125,14 @@ abstract class AbstractKotlinTarget(
adhocVariant as SoftwareComponent adhocVariant as SoftwareComponent
if (kotlinVariant is KotlinVariantWithMetadataVariant) { object : ComponentWithVariants, ComponentWithCoordinates, SoftwareComponentInternal {
object : ComponentWithVariants, ComponentWithCoordinates, SoftwareComponentInternal { override fun getCoordinates() = (kotlinVariant as? ComponentWithCoordinates)?.coordinates
override fun getCoordinates() = kotlinVariant.coordinates
override fun getVariants(): Set<out SoftwareComponent> = kotlinVariant.variants override fun getVariants(): Set<out SoftwareComponent> =
override fun getName(): String = adhocVariant.name (kotlinVariant as? KotlinVariantWithMetadataVariant)?.variants.orEmpty()
override fun getUsages(): MutableSet<out UsageContext> = (adhocVariant as SoftwareComponentInternal).usages
} override fun getName(): String = adhocVariant.name
} else { override fun getUsages(): MutableSet<out UsageContext> = (adhocVariant as SoftwareComponentInternal).usages
object : ComponentWithCoordinates, SoftwareComponentInternal {
override fun getCoordinates() = (kotlinVariant as? ComponentWithCoordinates)?.coordinates
override fun getName(): String = adhocVariant.name
override fun getUsages(): MutableSet<out UsageContext> = (adhocVariant as SoftwareComponentInternal).usages
}
} }
}.toSet() }.toSet()
} }
@@ -69,8 +69,7 @@ open class KotlinVariant(
override fun getName(): String = componentName ?: producingCompilation.target.targetName override fun getName(): String = componentName ?: producingCompilation.target.targetName
override val publishable: Boolean override var publishable: Boolean = target.publishable
get() = target.publishable
override var sourcesArtifacts: Set<PublishArtifact> = emptySet() override var sourcesArtifacts: Set<PublishArtifact> = emptySet()
internal set internal set
@@ -102,7 +101,7 @@ class JointAndroidKotlinTargetComponent(
private val nestedVariants: Set<KotlinVariant>, private val nestedVariants: Set<KotlinVariant>,
val flavorNames: List<String>, val flavorNames: List<String>,
override val sourcesArtifacts: Set<PublishArtifact> override val sourcesArtifacts: Set<PublishArtifact>
) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal { ) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal {
override fun getUsages(): Set<KotlinUsageContext> = nestedVariants.flatMap { it.usages }.toSet() override fun getUsages(): Set<KotlinUsageContext> = nestedVariants.flatMap { it.usages }.toSet()
@@ -143,8 +143,6 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
allMetadataJar.description = "Assembles a jar archive containing the metadata for all Kotlin source sets." allMetadataJar.description = "Assembles a jar archive containing the metadata for all Kotlin source sets."
allMetadataJar.group = BasePlugin.BUILD_GROUP allMetadataJar.group = BasePlugin.BUILD_GROUP
allMetadataJar.archiveAppendix.set(target.name.toLowerCase())
if (target.project.isCompatibilityMetadataVariantEnabled) { if (target.project.isCompatibilityMetadataVariantEnabled) {
allMetadataJar.archiveClassifier.set("all") allMetadataJar.archiveClassifier.set("all")
} }