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(
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
)
}
@@ -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") } }
}
@@ -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:") }
@@ -246,7 +246,7 @@ internal class GranularMetadataTransformation(
SourceSetVisibilityProvider(project).getVisibleSourceSets(
kotlinSourceSet,
sourceSetRequestedScopes,
parent, module,
if (projectStructureMetadata.isPublishedAsRoot) module else parent, module,
projectStructureMetadata,
resolvedToProject
)
@@ -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())
@@ -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<KotlinTargetComponentWithPublication>()
.single().publicationDelegate = this@apply
}
// 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
val hostSpecificSourceSets: Set<String>,
@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 <Serializer> 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 <ParsingContext> 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<String, Set<String>>()
variantsNode.forEach { variantNode ->
@@ -274,11 +284,13 @@ internal fun <ParsingContext> 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"
@@ -26,10 +26,13 @@ abstract class KotlinSoftwareComponent(
protected val kotlinTargets: Iterable<KotlinTarget>
) : 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> =
kotlinTargets.flatMap { it.components }.toSet()
kotlinTargets.minus(metadataTarget).flatMap { it.components }.toSet()
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.
*
* 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.
@@ -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<out SoftwareComponent> = kotlinVariant.variants
override fun getName(): String = adhocVariant.name
override fun getUsages(): MutableSet<out UsageContext> = (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<out UsageContext> = (adhocVariant as SoftwareComponentInternal).usages
}
object : ComponentWithVariants, ComponentWithCoordinates, SoftwareComponentInternal {
override fun getCoordinates() = (kotlinVariant as? ComponentWithCoordinates)?.coordinates
override fun getVariants(): Set<out SoftwareComponent> =
(kotlinVariant as? KotlinVariantWithMetadataVariant)?.variants.orEmpty()
override fun getName(): String = adhocVariant.name
override fun getUsages(): MutableSet<out UsageContext> = (adhocVariant as SoftwareComponentInternal).usages
}
}.toSet()
}
@@ -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<PublishArtifact> = emptySet()
internal set
@@ -102,7 +101,7 @@ class JointAndroidKotlinTargetComponent(
private val nestedVariants: Set<KotlinVariant>,
val flavorNames: List<String>,
override val sourcesArtifacts: Set<PublishArtifact>
) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal {
) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal {
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.group = BasePlugin.BUILD_GROUP
allMetadataJar.archiveAppendix.set(target.name.toLowerCase())
if (target.project.isCompatibilityMetadataVariantEnabled) {
allMetadataJar.archiveClassifier.set("all")
}