提交 bf5feb1b 编写于 作者: S Sebastian Sellmair 提交者: Space

Remove KotlinMetadataTarget's KotlinTargetComponent in favour of KotlinSoftwareComponent.kt

^KT-44322 fixed
上级 9a5791ad
......@@ -714,16 +714,18 @@ class NewMultiplatformIT : BaseGradleIT() {
}
}
gradleBuildScript().appendText("\n" + """
gradleBuildScript().appendText(
"\n" + """
kotlin.sourceSets.all {
it.languageSettings {
languageVersion = '1.3'
apiVersion = '1.3'
}
}
""".trimIndent())
""".trimIndent()
)
listOf( "compileKotlinMetadata", "compileKotlinJvm6", "compileKotlinNodeJs").forEach {
listOf("compileKotlinMetadata", "compileKotlinJvm6", "compileKotlinNodeJs").forEach {
build(it) {
assertSuccessful()
assertTasksExecuted(":$it")
......@@ -1015,15 +1017,20 @@ class NewMultiplatformIT : BaseGradleIT() {
assertSuccessful()
val groupDir = projectDir.resolve("repo/com/example/")
val targetArtifactIdAppendices = listOf("metadata", "jvm6", "nodejs", "linux64")
val targetArtifactIdAppendices = listOf(null, "jvm6", "nodejs", "linux64")
val sourceJarSourceRoots = targetArtifactIdAppendices.associate { artifact ->
val sourcesJar = JarFile(groupDir.resolve("sample-lib-$artifact/1.0/sample-lib-$artifact-1.0-sources.jar"))
val sourceJarSourceRoots = targetArtifactIdAppendices.associateWith { artifact ->
val sourcesJarPath = if (artifact != null) "sample-lib-$artifact/1.0/sample-lib-$artifact-1.0-sources.jar"
else "sample-lib/1.0/sample-lib-1.0-sources.jar"
val sourcesJar = JarFile(groupDir.resolve(sourcesJarPath))
val sourcesDirs = sourcesJar.entries().asSequence().map { it.name.substringBefore("/") }.toSet() - "META-INF"
artifact to sourcesDirs
sourcesDirs
}
assertEquals(setOf("commonMain"), sourceJarSourceRoots["metadata"])
assertEquals(
setOf("commonMain", "jvm6Main", "linux64Main", "macos64Main", "mingw64Main", "mingw86Main", "nodeJsMain"),
sourceJarSourceRoots[null]
)
assertEquals(setOf("commonMain", "jvm6Main"), sourceJarSourceRoots["jvm6"])
assertEquals(setOf("commonMain", "nodeJsMain"), sourceJarSourceRoots["nodejs"])
assertEquals(setOf("commonMain", "linux64Main"), sourceJarSourceRoots["linux64"])
......@@ -1361,26 +1368,29 @@ class NewMultiplatformIT : BaseGradleIT() {
fun testDependenciesDsl() = with(transformProjectWithPluginsDsl("newMppDependenciesDsl")) {
val originalBuildscriptContent = gradleBuildScript("app").readText()
fun testDependencies() = testResolveAllConfigurations("app", options = defaultBuildOptions().copy(warningMode = WarningMode.Summary)) {
assertContains(">> :app:testNonTransitiveStringNotationApiDependenciesMetadata --> junit-4.12.jar")
assertEquals(
1,
(Regex.escape(">> :app:testNonTransitiveStringNotationApiDependenciesMetadata") + " .*").toRegex().findAll(output).count()
)
fun testDependencies() =
testResolveAllConfigurations("app", options = defaultBuildOptions().copy(warningMode = WarningMode.Summary)) {
assertContains(">> :app:testNonTransitiveStringNotationApiDependenciesMetadata --> junit-4.12.jar")
assertEquals(
1,
(Regex.escape(">> :app:testNonTransitiveStringNotationApiDependenciesMetadata") + " .*").toRegex().findAll(output)
.count()
)
assertContains(">> :app:testNonTransitiveDependencyNotationApiDependenciesMetadata --> kotlin-reflect-${defaultBuildOptions().kotlinVersion}.jar")
assertEquals(
1,
(Regex.escape(">> :app:testNonTransitiveStringNotationApiDependenciesMetadata") + " .*").toRegex().findAll(output).count()
)
assertContains(">> :app:testNonTransitiveDependencyNotationApiDependenciesMetadata --> kotlin-reflect-${defaultBuildOptions().kotlinVersion}.jar")
assertEquals(
1,
(Regex.escape(">> :app:testNonTransitiveStringNotationApiDependenciesMetadata") + " .*").toRegex().findAll(output)
.count()
)
assertContains(">> :app:testExplicitKotlinVersionApiDependenciesMetadata --> kotlin-reflect-1.3.0.jar")
assertContains(">> :app:testExplicitKotlinVersionImplementationDependenciesMetadata --> kotlin-reflect-1.2.71.jar")
assertContains(">> :app:testExplicitKotlinVersionCompileOnlyDependenciesMetadata --> kotlin-reflect-1.2.70.jar")
assertContains(">> :app:testExplicitKotlinVersionRuntimeOnlyDependenciesMetadata --> kotlin-reflect-1.2.60.jar")
assertContains(">> :app:testExplicitKotlinVersionApiDependenciesMetadata --> kotlin-reflect-1.3.0.jar")
assertContains(">> :app:testExplicitKotlinVersionImplementationDependenciesMetadata --> kotlin-reflect-1.2.71.jar")
assertContains(">> :app:testExplicitKotlinVersionCompileOnlyDependenciesMetadata --> kotlin-reflect-1.2.70.jar")
assertContains(">> :app:testExplicitKotlinVersionRuntimeOnlyDependenciesMetadata --> kotlin-reflect-1.2.60.jar")
assertContains(">> :app:testProjectWithConfigurationApiDependenciesMetadata --> output.txt")
}
assertContains(">> :app:testProjectWithConfigurationApiDependenciesMetadata --> output.txt")
}
testDependencies()
......
......@@ -8,12 +8,13 @@ package org.jetbrains.kotlin.gradle.dsl
import groovy.lang.Closure
import org.gradle.api.InvalidUserCodeException
import org.gradle.api.NamedDomainObjectCollection
import org.gradle.api.Project
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
open class KotlinMultiplatformExtension :
KotlinProjectExtension(),
open class KotlinMultiplatformExtension(project: Project) :
KotlinProjectExtension(project),
KotlinTargetContainerWithPresetFunctions,
KotlinTargetContainerWithJsPresetFunctions,
KotlinTargetContainerWithNativeShortcuts {
......@@ -50,7 +51,7 @@ open class KotlinMultiplatformExtension :
fun targetFromPreset(preset: KotlinTargetPreset<*>, configure: Closure<*>) = targetFromPreset(preset, preset.name, configure)
internal val rootSoftwareComponent: KotlinSoftwareComponent by lazy {
KotlinSoftwareComponentWithCoordinatesAndPublication("kotlin", targets)
KotlinSoftwareComponentWithCoordinatesAndPublication(project, "kotlin", targets)
}
}
......
......@@ -26,7 +26,7 @@ import kotlin.reflect.KClass
private const val KOTLIN_PROJECT_EXTENSION_NAME = "kotlin"
internal fun Project.createKotlinExtension(extensionClass: KClass<out KotlinProjectExtension>): KotlinProjectExtension {
val kotlinExt = extensions.create(KOTLIN_PROJECT_EXTENSION_NAME, extensionClass.java)
val kotlinExt = extensions.create(KOTLIN_PROJECT_EXTENSION_NAME, extensionClass.java, this)
DslObject(kotlinExt).extensions.create("experimental", ExperimentalExtension::class.java)
return kotlinExtension
}
......@@ -43,7 +43,7 @@ internal val Project.multiplatformExtensionOrNull: KotlinMultiplatformExtension?
internal val Project.multiplatformExtension: KotlinMultiplatformExtension
get() = extensions.getByName(KOTLIN_PROJECT_EXTENSION_NAME) as KotlinMultiplatformExtension
open class KotlinProjectExtension : KotlinSourceSetContainer {
open class KotlinProjectExtension(internal val project: Project) : KotlinSourceSetContainer {
val experimental: ExperimentalExtension
get() = DslObject(this).extensions.getByType(ExperimentalExtension::class.java)
......@@ -67,32 +67,32 @@ open class KotlinProjectExtension : KotlinSourceSetContainer {
}
}
abstract class KotlinSingleTargetExtension : KotlinProjectExtension() {
abstract class KotlinSingleTargetExtension(project: Project) : KotlinProjectExtension(project) {
abstract val target: KotlinTarget
open fun target(body: Closure<out KotlinTarget>) = ConfigureUtil.configure(body, target)
}
abstract class KotlinSingleJavaTargetExtension : KotlinSingleTargetExtension() {
abstract class KotlinSingleJavaTargetExtension(project: Project) : KotlinSingleTargetExtension(project) {
abstract override val target: KotlinWithJavaTarget<*>
}
open class KotlinJvmProjectExtension : KotlinSingleJavaTargetExtension() {
open class KotlinJvmProjectExtension(project: Project) : KotlinSingleJavaTargetExtension(project) {
override lateinit var target: KotlinWithJavaTarget<KotlinJvmOptions>
internal set
open fun target(body: KotlinWithJavaTarget<KotlinJvmOptions>.() -> Unit) = target.run(body)
}
open class Kotlin2JsProjectExtension : KotlinSingleJavaTargetExtension() {
open class Kotlin2JsProjectExtension(project: Project) : KotlinSingleJavaTargetExtension(project) {
override lateinit var target: KotlinWithJavaTarget<KotlinJsOptions>
internal set
open fun target(body: KotlinWithJavaTarget<KotlinJsOptions>.() -> Unit) = target.run(body)
}
open class KotlinJsProjectExtension :
KotlinSingleTargetExtension(),
open class KotlinJsProjectExtension(project: Project) :
KotlinSingleTargetExtension(project),
KotlinJsCompilerTypeHolder {
lateinit var irPreset: KotlinJsIrSingleTargetPreset
......@@ -224,14 +224,14 @@ open class KotlinJsProjectExtension :
}
}
open class KotlinCommonProjectExtension : KotlinSingleJavaTargetExtension() {
open class KotlinCommonProjectExtension(project: Project) : KotlinSingleJavaTargetExtension(project) {
override lateinit var target: KotlinWithJavaTarget<KotlinMultiplatformCommonOptions>
internal set
open fun target(body: KotlinWithJavaTarget<KotlinMultiplatformCommonOptions>.() -> Unit) = target.run(body)
}
open class KotlinAndroidProjectExtension : KotlinSingleTargetExtension() {
open class KotlinAndroidProjectExtension(project: Project) : KotlinSingleTargetExtension(project) {
override lateinit var target: KotlinAndroidTarget
internal set
......
......@@ -15,8 +15,6 @@ import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVaria
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import javax.inject.Inject
internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadataElements"
open class KotlinMetadataTarget @Inject constructor(project: Project) :
KotlinOnlyTarget<AbstractKotlinCompilation<*>>(project, KotlinPlatformType.common) {
......@@ -29,57 +27,11 @@ open class KotlinMetadataTarget @Inject constructor(project: Project) :
get() = super.artifactsTaskName
override val kotlinComponents: Set<KotlinTargetComponent> by lazy {
if (!project.isKotlinGranularMetadataEnabled)
super.kotlinComponents
else {
val usageContexts = mutableSetOf<DefaultKotlinUsageContext>()
// This usage value is only needed for Maven scope mapping. Don't replace it with a custom Kotlin Usage value
val javaApiUsage = project.usageByName("java-api-jars")
usageContexts += run {
val allMetadataJar = project.tasks.named(KotlinMetadataTargetConfigurator.ALL_METADATA_JAR_NAME)
val allMetadataArtifact = project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, allMetadataJar) {
it.classifier = if (project.isCompatibilityMetadataVariantEnabled) "all" else ""
}
DefaultKotlinUsageContext(
compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME),
javaApiUsage,
apiElementsConfigurationName,
overrideConfigurationArtifacts = setOf(allMetadataArtifact)
)
}
if (PropertiesProvider(project).enableCompatibilityMetadataVariant == true) {
// Ensure that consumers who expect Kotlin 1.2.x metadata package can still get one:
// publish the old metadata artifact:
usageContexts += run {
DefaultKotlinUsageContext(
compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME),
javaApiUsage,
/** this configuration is created by [KotlinMetadataTargetConfigurator.createCommonMainElementsConfiguration] */
COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME
)
}
}
val component =
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())
component.sourcesArtifacts = setOf(
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, sourcesJarTask).apply {
this as ConfigurablePublishArtifact
classifier = "sources"
}
)
setOf(component)
}
/*
Metadata Target does not have a KotlinTargetComponent on it's own.
Responsibility is shifted to the root KotlinSoftwareComponent
*/
emptySet<KotlinTargetComponent>()
}
}
\ No newline at end of file
}
......@@ -200,116 +200,6 @@ class KotlinMultiplatformPlugin(
}
}
private fun configurePublishingWithMavenPublish(project: Project) = project.pluginManager.withPlugin("maven-publish") { _ ->
val targets = project.multiplatformExtension.targets
val metadataTarget = project.multiplatformExtension.metadata()
val kotlinSoftwareComponent = project.multiplatformExtension.rootSoftwareComponent
project.extensions.configure(PublishingExtension::class.java) { publishing ->
// The root publication that references the platform specific publications as its variants:
publishing.publications.create("kotlinMultiplatform", MavenPublication::class.java).apply {
from(kotlinSoftwareComponent)
(this as MavenPublicationInternal).publishWithOriginalFileName()
kotlinSoftwareComponent.publicationDelegate = this@apply
metadataTarget.kotlinComponents.filterIsInstance<KotlinTargetComponentWithPublication>()
.single().publicationDelegate = this@apply
project.whenEvaluated {
if (!metadataTarget.publishable) return@whenEvaluated
metadataTarget.kotlinComponents
.flatMap { component -> component.sourcesArtifacts }
.forEach { sourcesArtifact -> artifact(sourcesArtifact) }
}
}
// Enforce the order of creating the publications, since the metadata publication is used in the other publications:
metadataTarget.createMavenPublications(publishing.publications)
targets
.withType(AbstractKotlinTarget::class.java).matching { it.publishable && it.name != METADATA_TARGET_NAME }
.all {
if (it is KotlinAndroidTarget || it is KotlinMetadataTarget)
// Android targets have their variants created in afterEvaluate; TODO handle this better?
// Kotlin Metadata targets rely on complete source sets hierearchy and cannot be inspected for publication earlier
project.whenEvaluated { it.createMavenPublications(publishing.publications) }
else
it.createMavenPublications(publishing.publications)
}
}
project.components.add(kotlinSoftwareComponent)
}
private fun rewritePom(
pom: MavenPom,
pomRewriter: PomDependenciesRewriter,
shouldRewritePomDependencies: Provider<Boolean>,
includeOnlySpecifiedDependencies: Provider<Set<ModuleCoordinates>>?
) {
pom.withXml { xml ->
if (shouldRewritePomDependencies.get())
pomRewriter.rewritePomMppDependenciesToActualTargetModules(xml, includeOnlySpecifiedDependencies)
}
}
private fun AbstractKotlinTarget.createMavenPublications(publications: PublicationContainer) {
components
.map { gradleComponent -> gradleComponent to kotlinComponents.single { it.name == gradleComponent.name } }
.filter { (_, kotlinComponent) -> kotlinComponent.publishable }
.forEach { (gradleComponent, kotlinComponent) ->
val componentPublication = publications.create(kotlinComponent.name, MavenPublication::class.java).apply {
// 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
val pomRewriter = PomDependenciesRewriter(project, kotlinComponent)
val shouldRewritePomDependencies =
project.provider { PropertiesProvider(project).keepMppDependenciesIntactInPoms != true }
rewritePom(
pom,
pomRewriter,
shouldRewritePomDependencies,
dependenciesForPomRewriting(this@createMavenPublications)
)
}
(kotlinComponent as? KotlinTargetComponentWithPublication)?.publicationDelegate = componentPublication
publicationConfigureActions.all { it.execute(componentPublication) }
}
}
/**
* The metadata targets need their POMs to only include the dependencies from the commonMain API configuration.
* The actual apiElements configurations of metadata targets now contain dependencies from all source sets, but, as the consumers who
* can't read Gradle module metadata won't resolve a dependency on an MPP to the granular metadata variant and won't then choose the
* right dependencies for each source set, we put only the dependencies of the legacy common variant into the POM, i.e. commonMain API.
*/
private fun dependenciesForPomRewriting(target: AbstractKotlinTarget): Provider<Set<ModuleCoordinates>>? =
if (target !is KotlinMetadataTarget || !target.project.isKotlinGranularMetadataEnabled)
null
else {
val commonMain = target.project.kotlinExtension.sourceSets.findByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
if (commonMain == null)
null
else
target.project.provider {
val project = target.project
// Only the commonMain API dependencies can be published for consumers who can't read Gradle project metadata
val commonMainApi = project.sourceSetDependencyConfigurationByScope(commonMain, KotlinDependencyScope.API_SCOPE)
val commonMainDependencies = commonMainApi.allDependencies
commonMainDependencies.map { ModuleCoordinates(it.group, it.name, it.version) }.toSet()
}
}
private fun configureSourceSets(project: Project) = with(project.multiplatformExtension) {
val production = sourceSets.create(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
......
......@@ -17,44 +17,95 @@ import org.gradle.api.component.SoftwareComponent
import org.gradle.api.internal.component.SoftwareComponentInternal
import org.gradle.api.internal.component.UsageContext
import org.gradle.api.publish.maven.MavenPublication
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.targets.metadata.COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVariantEnabled
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
abstract class KotlinSoftwareComponent(
private val project: Project,
private val name: String,
protected val kotlinTargets: Iterable<KotlinTarget>
) : SoftwareComponentInternal, ComponentWithVariants {
private val metadataTarget: KotlinMetadataTarget
get() = kotlinTargets.filterIsInstance<KotlinMetadataTarget>().single()
override fun getName(): String = name
override fun getUsages(): Set<UsageContext> = (metadataTarget.components.single() as SoftwareComponentInternal).usages
override fun getVariants(): Set<SoftwareComponent> = kotlinTargets
.filter { target -> target !is KotlinMetadataTarget }
.flatMap { it.components }.toSet()
override fun getVariants(): Set<SoftwareComponent> =
kotlinTargets.minus(metadataTarget).flatMap { it.components }.toSet()
private val _usages: Set<UsageContext> by lazy {
val metadataTarget = project.multiplatformExtension.metadata()
override fun getName(): String = name
if (!project.isKotlinGranularMetadataEnabled) {
val metadataCompilation = metadataTarget.compilations.getByName(MAIN_COMPILATION_NAME)
return@lazy metadataTarget.createUsageContexts(metadataCompilation)
}
mutableSetOf<UsageContext>().apply {
// This usage value is only needed for Maven scope mapping. Don't replace it with a custom Kotlin Usage value
val javaApiUsage = project.usageByName("java-api-jars")
val allMetadataJar = project.tasks.named(KotlinMetadataTargetConfigurator.ALL_METADATA_JAR_NAME)
val allMetadataArtifact = project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, allMetadataJar) { allMetadataArtifact ->
allMetadataArtifact.classifier = if (project.isCompatibilityMetadataVariantEnabled) "all" else ""
}
this += DefaultKotlinUsageContext(
compilation = metadataTarget.compilations.getByName(MAIN_COMPILATION_NAME),
usage = javaApiUsage,
dependencyConfigurationName = metadataTarget.apiElementsConfigurationName,
overrideConfigurationArtifacts = setOf(allMetadataArtifact)
)
if (project.isCompatibilityMetadataVariantEnabled) {
// Ensure that consumers who expect Kotlin 1.2.x metadata package can still get one:
// publish the old metadata artifact:
this += run {
DefaultKotlinUsageContext(
metadataTarget.compilations.getByName(MAIN_COMPILATION_NAME),
javaApiUsage,
/** this configuration is created by [KotlinMetadataTargetConfigurator.createCommonMainElementsConfiguration] */
COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME
)
}
}
}
}
override fun getUsages(): Set<UsageContext> {
return _usages
}
val sourcesArtifacts: Set<PublishArtifact> by lazy {
val sourcesJarTask = sourcesJarTask(project, lazy { project.kotlinExtension.sourceSets.toSet() }, null, name.toLowerCase())
val sourcesJarArtifact = project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, 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,
// which is needed for compatibility with older Gradle versions
var publicationDelegate: MavenPublication? = null
}
class KotlinSoftwareComponentWithCoordinatesAndPublication(name: String, kotlinTargets: Iterable<KotlinTarget>) :
KotlinSoftwareComponent(name, kotlinTargets), ComponentWithCoordinates {
class KotlinSoftwareComponentWithCoordinatesAndPublication(project: Project, name: String, kotlinTargets: Iterable<KotlinTarget>) :
KotlinSoftwareComponent(project, name, kotlinTargets), ComponentWithCoordinates {
override fun getCoordinates(): ModuleVersionIdentifier = getCoordinatesFromPublicationDelegateAndProject(
publicationDelegate, kotlinTargets.first().project, null
)
}
// At the moment all KN artifacts have JAVA_API usage.
// TODO: Replace it with a specific usage
object NativeUsage {
const val KOTLIN_KLIB = "kotlin-klib"
}
interface KotlinUsageContext : UsageContext {
val compilation: KotlinCompilation<*>
val dependencyConfigurationName: String
......@@ -117,4 +168,4 @@ class DefaultKotlinUsageContext(
override fun getCapabilities(): Set<Capability> = emptySet()
override fun getGlobalExcludes(): Set<ExcludeRule> = emptySet()
}
\ No newline at end of file
}
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.api.publish.PublicationContainer
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPom
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.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
internal fun configurePublishingWithMavenPublish(project: Project) = project.pluginManager.withPlugin("maven-publish") {
project.extensions.configure(PublishingExtension::class.java) { publishing ->
createRootPublication(project, publishing)
createTargetPublications(project, publishing)
}
project.components.add(project.multiplatformExtension.rootSoftwareComponent)
}
/**
* The root publication that references the platform specific publications as its variants
*/
private fun createRootPublication(project: Project, publishing: PublishingExtension) {
val kotlinSoftwareComponent = project.multiplatformExtension.rootSoftwareComponent
publishing.publications.create("kotlinMultiplatform", MavenPublication::class.java).apply {
from(kotlinSoftwareComponent)
(this as MavenPublicationInternal).publishWithOriginalFileName()
kotlinSoftwareComponent.publicationDelegate = this@apply
kotlinSoftwareComponent.sourcesArtifacts.forEach { sourceArtifact ->
artifact(sourceArtifact)
}
}
}
private fun createTargetPublications(project: Project, publishing: PublishingExtension) {
val kotlin = project.multiplatformExtension
// Enforce the order of creating the publications, since the metadata publication is used in the other publications:
kotlin.targets
.withType(AbstractKotlinTarget::class.java)
.matching { it.publishable }
.all { kotlinTarget ->
if (kotlinTarget is KotlinAndroidTarget)
// Android targets have their variants created in afterEvaluate; TODO handle this better?
project.whenEvaluated { kotlinTarget.createMavenPublications(publishing.publications) }
else
kotlinTarget.createMavenPublications(publishing.publications)
}
}
private fun AbstractKotlinTarget.createMavenPublications(publications: PublicationContainer) {
components
.map { gradleComponent -> gradleComponent to kotlinComponents.single { it.name == gradleComponent.name } }
.filter { (_, kotlinComponent) -> kotlinComponent.publishable }
.forEach { (gradleComponent, kotlinComponent) ->
val componentPublication = publications.create(kotlinComponent.name, MavenPublication::class.java).apply {
// 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
val pomRewriter = PomDependenciesRewriter(project, kotlinComponent)
val shouldRewritePomDependencies =
project.provider { PropertiesProvider(project).keepMppDependenciesIntactInPoms != true }
rewritePom(
pom,
pomRewriter,
shouldRewritePomDependencies,
dependenciesForPomRewriting(this@createMavenPublications)
)
}
(kotlinComponent as? KotlinTargetComponentWithPublication)?.publicationDelegate = componentPublication
publicationConfigureActions.all { it.execute(componentPublication) }
}
}
private fun rewritePom(
pom: MavenPom,
pomRewriter: PomDependenciesRewriter,
shouldRewritePomDependencies: Provider<Boolean>,
includeOnlySpecifiedDependencies: Provider<Set<ModuleCoordinates>>?
) {
pom.withXml { xml ->
if (shouldRewritePomDependencies.get())
pomRewriter.rewritePomMppDependenciesToActualTargetModules(xml, includeOnlySpecifiedDependencies)
}
}
/**
* The metadata targets need their POMs to only include the dependencies from the commonMain API configuration.
* The actual apiElements configurations of metadata targets now contain dependencies from all source sets, but, as the consumers who
* can't read Gradle module metadata won't resolve a dependency on an MPP to the granular metadata variant and won't then choose the
* right dependencies for each source set, we put only the dependencies of the legacy common variant into the POM, i.e. commonMain API.
*/
private fun dependenciesForPomRewriting(target: AbstractKotlinTarget): Provider<Set<ModuleCoordinates>>? =
if (target !is KotlinMetadataTarget || !target.project.isKotlinGranularMetadataEnabled)
null
else {
val commonMain = target.project.kotlinExtension.sourceSets.findByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
if (commonMain == null)
null
else
target.project.provider {
val project = target.project
// Only the commonMain API dependencies can be published for consumers who can't read Gradle project metadata
val commonMainApi = project.sourceSetDependencyConfigurationByScope(commonMain, KotlinDependencyScope.API_SCOPE)
val commonMainDependencies = commonMainApi.allDependencies
commonMainDependencies.map { ModuleCoordinates(it.group, it.name, it.version) }.toSet()
}
}
......@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadataElements"
internal const val ALL_COMPILE_METADATA_CONFIGURATION_NAME = "allSourceSetsCompileDependenciesMetadata"
internal const val ALL_RUNTIME_METADATA_CONFIGURATION_NAME = "allSourceSetsRuntimeDependenciesMetadata"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册