mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-24 08:31:31 +00:00
Remove KotlinMetadataTarget's KotlinTargetComponent in favour of KotlinSoftwareComponent.kt
^KT-44322 fixed
This commit is contained in:
committed by
Space
parent
9a5791ad6d
commit
bf5feb1b4a
@@ -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>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 getUsages(): Set<UsageContext> = (metadataTarget.components.single() as SoftwareComponentInternal).usages
|
||||
|
||||
override fun getVariants(): Set<SoftwareComponent> =
|
||||
kotlinTargets.minus(metadataTarget).flatMap { it.components }.toSet()
|
||||
|
||||
override fun getName(): String = name
|
||||
|
||||
override fun getVariants(): Set<SoftwareComponent> = kotlinTargets
|
||||
.filter { target -> target !is KotlinMetadataTarget }
|
||||
.flatMap { it.components }.toSet()
|
||||
|
||||
private val _usages: Set<UsageContext> by lazy {
|
||||
val metadataTarget = project.multiplatformExtension.metadata()
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user