diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index e3361fa0718..f7bb7eef15a 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -10,7 +10,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind import org.jetbrains.kotlin.gradle.plugin.mpp.UnusedSourceSetsChecker import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks -import org.jetbrains.kotlin.gradle.util.* +import org.jetbrains.kotlin.gradle.util.checkBytecodeContains +import org.jetbrains.kotlin.gradle.util.isWindows +import org.jetbrains.kotlin.gradle.util.modify +import org.jetbrains.kotlin.gradle.util.testResolveAllConfigurations import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.HostManager import org.junit.Assert @@ -603,7 +606,7 @@ class NewMultiplatformIT : BaseGradleIT() { fun testPublishWithoutGradleMetadata() { val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app") - with (libProject) { + with(libProject) { setupWorkingDir() projectDir.resolve("settings.gradle").modify { it.replace("enableFeaturePreview", "// enableFeaturePreview") } @@ -1160,8 +1163,34 @@ class NewMultiplatformIT : BaseGradleIT() { } @Test - fun testPublishMultimoduleProjectWithNoMetadata() { - val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app") + fun testPublishMultimoduleProjectWithNoMetadata() = doTestPublishMultimoduleProject(withMetadata = false) + + @Test + fun testPublishMultimoduleProjectWithMetadata() = doTestPublishMultimoduleProject(withMetadata = true) + + private fun doTestPublishMultimoduleProject(withMetadata: Boolean) { + val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app").apply { + if (withMetadata) { + setupWorkingDir() + // Make another publication that will be consumed as a module with metadata, see a similar conditional block below: + projectDir.resolve("settings.gradle").writeText("rootProject.name = 'external'; enableFeaturePreview 'GRADLE_METADATA'") + gradleBuildScript().appendText( + "\n" + """ + group = "com.external.dependency" + version = "1.2.3" + publishing { + repositories { + maven { url "file://${'$'}{rootProject.projectDir.absolutePath.replace('\\', '/')}/repo" } + } + } + """.trimIndent() + ) + build("publish") { + assertSuccessful() + gradleBuildScript().appendText("\ngroup = 'com.example'; version = '1.0'") + } + } + } val appProject = Project("sample-app", gradleVersion, "new-mpp-lib-and-app") with(libProject) { @@ -1169,7 +1198,7 @@ class NewMultiplatformIT : BaseGradleIT() { appProject.setupWorkingDir() appProject.projectDir.copyRecursively(projectDir.resolve("sample-app")) - projectDir.resolve("settings.gradle").writeText("include 'sample-app'") // also disables feature preview 'GRADLE_METADATA' + gradleSettingsScript().writeText("include 'sample-app'") // disables feature preview 'GRADLE_METADATA', resets rootProject name gradleBuildScript("sample-app").modify { it.replace("'com.example:sample-lib:1.0'", "project(':')") + "\n" + """ apply plugin: 'maven-publish' @@ -1182,6 +1211,20 @@ class NewMultiplatformIT : BaseGradleIT() { } """.trimIndent() } + if (withMetadata) { + gradleSettingsScript().appendText("\nenableFeaturePreview(\"GRADLE_METADATA\")") + // Add a dependency that is resolved with metadata: + gradleBuildScript("sample-app").appendText( + "\n" + """ + repositories { + maven { url "file://${'$'}{rootProject.projectDir.absolutePath.replace('\\', '/')}/repo" } + } + dependencies { + commonMainApi 'com.external.dependency:external:1.2.3' + } + """.trimIndent() + ) + } gradleBuildScript().appendText("\n" + """ publishing { @@ -1195,7 +1238,7 @@ class NewMultiplatformIT : BaseGradleIT() { } """.trimIndent()) - build("publish") { + build("clean", "publish") { assertSuccessful() assertFileContains( "repo/com/exampleapp/sample-app-nodejs/1.0/sample-app-nodejs-1.0.pom", @@ -1209,6 +1252,22 @@ class NewMultiplatformIT : BaseGradleIT() { "bar", "42" ) + if (withMetadata) { + // Check that the external dependency that was resolved with metadata is written to the POM as the artifactId it + // resolved to: + assertFileContains( + "repo/com/exampleapp/sample-app-jvm8/1.0/sample-app-jvm8-1.0.pom", + "com.external.dependency", + "external-jvm6", + "1.2.3" + ) + + // Check that, despite the rewritten POM, the module metadata contains the original dependency: + val moduleMetadata = projectDir.resolve("repo/com/exampleapp/sample-app-jvm8/1.0/sample-app-jvm8-1.0.module").readText() + .replace("\\s+".toRegex(), "").replace("\n", "") + assertTrue { "\"group\":\"com.example\",\"module\":\"sample-lib\"" in moduleMetadata } + assertTrue { "\"group\":\"com.external.dependency\",\"module\":\"external\"" in moduleMetadata } + } assertFileExists("repo/foo/bar/42/bar-42.jar") } } @@ -1285,10 +1344,10 @@ class NewMultiplatformIT : BaseGradleIT() { assertFileContains("build/classes/kotlin/nodeJs/main/sample-lib.js", "Override") val (compilerPluginArgsBySourceSet, compilerPluginClasspathBySourceSet) = - listOf(compilerPluginArgsRegex, compilerPluginClasspathRegex) - .map { marker -> - marker.findAll(output).associate { it.groupValues[1] to it.groupValues[2] } - } + listOf(compilerPluginArgsRegex, compilerPluginClasspathRegex) + .map { marker -> + marker.findAll(output).associate { it.groupValues[1] to it.groupValues[2] } + } // TODO once Kotlin/Native properly supports compiler plugins, expand this to all source sets: listOf("commonMain", "commonTest", "jvm6Main", "jvm6Test", "nodeJsMain", "nodeJsTest").forEach { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt index fcebc819482..68889457bb3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt @@ -12,9 +12,8 @@ import org.gradle.util.ConfigureUtil import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset import org.jetbrains.kotlin.gradle.plugin.KotlinTargetsContainerWithPresets -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.* +import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast open class KotlinMultiplatformExtension : KotlinProjectExtension(), KotlinTargetContainerWithPresetFunctions { override lateinit var presets: NamedDomainObjectCollection> @@ -44,6 +43,14 @@ open class KotlinMultiplatformExtension : KotlinProjectExtension(), KotlinTarget fun targetFromPreset(preset: KotlinTargetPreset<*>) = targetFromPreset(preset, preset.name) { } fun targetFromPreset(preset: KotlinTargetPreset<*>, name: String) = targetFromPreset(preset, name) { } fun targetFromPreset(preset: KotlinTargetPreset<*>, configure: Closure<*>) = targetFromPreset(preset, preset.name, configure) + + internal val rootSoftwareComponent: KotlinSoftwareComponent by lazy { + if (isGradleVersionAtLeast(4, 7)) { + KotlinSoftwareComponentWithCoordinatesAndPublication("kotlin", targets) + } else { + KotlinSoftwareComponent("kotlin", targets) + } + } } internal fun KotlinTarget.isProducedFromPreset(kotlinTargetPreset: KotlinTargetPreset<*>): Boolean = diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 32092b35be8..8d39b9606f2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -6,8 +6,12 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import groovy.lang.Closure +import groovy.util.Node +import groovy.util.NodeList import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.XmlProvider +import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.AttributeContainer import org.gradle.api.internal.FeaturePreviews @@ -156,7 +160,7 @@ class KotlinMultiplatformPlugin( } val targets = project.multiplatformExtension!!.targets - val kotlinSoftwareComponent = KotlinSoftwareComponent("kotlin", targets) + val kotlinSoftwareComponent = project.multiplatformExtension!!.rootSoftwareComponent project.extensions.configure(PublishingExtension::class.java) { publishing -> @@ -203,6 +207,8 @@ class KotlinMultiplatformPlugin( } (this as MavenPublicationInternal).publishWithOriginalFileName() artifactId = variant.defaultArtifactId + + pom.withXml { xml -> project.rewritePomMppDependenciesToActualTargetModules(xml, variant) } } (variant as? KotlinTargetComponentWithPublication)?.publicationDelegate = variantPublication @@ -308,3 +314,62 @@ internal fun compilationsBySourceSet(project: Project): Map().flatMap { + (it.get("dependency") as? NodeList).orEmpty() + }.filterIsInstance() + + val dependencyByNode = mutableMapOf() + + // Collect all the dependencies from the nodes: + val dependencies = dependencyNodes.map { dependencyNode -> + fun Node.getSingleChildValueOrNull(childName: String): String? = + ((get(childName) as NodeList?)?.singleOrNull() as Node?)?.text() + + val groupId = dependencyNode.getSingleChildValueOrNull("groupId") + val artifactId = dependencyNode.getSingleChildValueOrNull("artifactId") + val version = dependencyNode.getSingleChildValueOrNull("version") + (project.dependencies.module("$groupId:$artifactId:$version") as ModuleDependency) + .also { dependencyByNode[dependencyNode] = it } + }.toSet() + + // Get the dependencies mapping according to the component's UsageContexts: + val resultDependenciesForEachUsageContext = + component.usages.mapNotNull { usage -> + if (usage is KotlinUsageContext) + rewriteDependenciesToActualModuleDependencies(usage, dependencies) + // We are only interested in dependencies that are mapped to some other dependencies: + .filter { (from, to) -> Triple(from.group, from.name, from.version) != Triple(to.group, to.name, to.version) } + else null + } + + // Rewrite the dependency nodes according to the mapping: + dependencyNodes.forEach { dependencyNode -> + val moduleDependency = dependencyByNode[dependencyNode] + val mapDependencyTo = resultDependenciesForEachUsageContext.find { moduleDependency in it }?.get(moduleDependency) + + if (mapDependencyTo != null) { + + fun Node.setChildNodeByName(name: String, value: String?) { + val childNode: Node? = (get(name) as NodeList?)?.firstOrNull() as Node? + if (value != null) { + (childNode ?: appendNode(name)).setValue(value) + } else { + childNode?.let { remove(it) } + } + } + + dependencyNode.setChildNodeByName("groupId", mapDependencyTo.group) + dependencyNode.setChildNodeByName("artifactId", mapDependencyTo.name) + dependencyNode.setChildNodeByName("version", mapDependencyTo.version) + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt index 95df74a4048..7fc86818b5b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt @@ -10,15 +10,17 @@ import org.gradle.api.artifacts.* import org.gradle.api.attributes.AttributeContainer import org.gradle.api.attributes.Usage import org.gradle.api.capabilities.Capability +import org.gradle.api.component.ComponentWithCoordinates import org.gradle.api.component.ComponentWithVariants 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.* import org.jetbrains.kotlin.utils.ifEmpty -class KotlinSoftwareComponent( +open class KotlinSoftwareComponent( private val name: String, - private val kotlinTargets: Iterable + protected val kotlinTargets: Iterable ) : SoftwareComponentInternal, ComponentWithVariants { override fun getUsages(): Set = emptySet() @@ -27,6 +29,18 @@ class KotlinSoftwareComponent( kotlinTargets.flatMap { it.components }.toSet() override fun getName(): String = name + + // 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) : + KotlinSoftwareComponent(name, kotlinTargets), ComponentWithCoordinates { + + override fun getCoordinates(): ModuleVersionIdentifier = getCoordinatesFromPublicationDelegateAndProject( + publicationDelegate, kotlinTargets.first().project, null + ) } // At the moment all KN artifacts have JAVA_API usage. @@ -45,7 +59,6 @@ class DefaultKotlinUsageContext( override val compilation: KotlinCompilation<*>, private val usage: Usage, override val dependencyConfigurationName: String, - private val publishWithGradleMetadata: Boolean, override val sourcesArtifact: PublishArtifact? = null, private val overrideConfigurationArtifacts: Set? = null ) : KotlinUsageContext { @@ -65,10 +78,7 @@ class DefaultKotlinUsageContext( get() = project.configurations.getByName(dependencyConfigurationName) override fun getDependencies(): MutableSet = - if (publishWithGradleMetadata) - configuration.incoming.dependencies.withType(ModuleDependency::class.java) - else - rewriteMppDependenciesToTargetModuleDependencies(this, configuration).toMutableSet() + configuration.incoming.dependencies.withType(ModuleDependency::class.java) override fun getDependencyConstraints(): MutableSet = configuration.incoming.dependencyConstraints @@ -86,14 +96,14 @@ class DefaultKotlinUsageContext( override fun getGlobalExcludes(): Set = emptySet() } -private fun rewriteMppDependenciesToTargetModuleDependencies( +internal fun rewriteDependenciesToActualModuleDependencies( usageContext: KotlinUsageContext, - fromConfiguration: Configuration -): Set = with(usageContext.compilation.target.project) { + moduleDependencies: Set +): Map { val compilation = usageContext.compilation - val moduleDependencies = fromConfiguration.incoming.dependencies.withType(ModuleDependency::class.java).ifEmpty { return emptySet() } + val project = compilation.target.project - val targetCompileDependenciesConfiguration = project.configurations.getByName( + val targetDependenciesConfiguration = project.configurations.getByName( when (compilation) { is KotlinJvmAndroidCompilation -> { // TODO handle Android configuration names in a general way once we drop AGP < 3.0.0 @@ -112,52 +122,86 @@ private fun rewriteMppDependenciesToTargetModuleDependencies( } ) - val resolvedCompileDependencies by lazy { + val resolvedDependencies by lazy { // don't resolve if no project dependencies on MPP projects are found - targetCompileDependenciesConfiguration.resolvedConfiguration.lenientConfiguration.allModuleDependencies.associateBy { + targetDependenciesConfiguration.resolvedConfiguration.lenientConfiguration.allModuleDependencies.associateBy { Triple(it.moduleGroup, it.moduleName, it.moduleVersion) } } - moduleDependencies.map { dependency -> - when (dependency) { - !is ProjectDependency -> dependency - else -> { - val dependencyProject = dependency.dependencyProject - val dependencyProjectKotlinExtension = dependencyProject.multiplatformExtension - ?: return@map dependency + val resolvedModulesByRootModuleCoordinates = targetDependenciesConfiguration + .allDependencies.withType(ModuleDependency::class.java) + .associate { dependency -> + when (dependency) { + is ProjectDependency -> { + val dependencyProject = dependency.dependencyProject + val dependencyProjectKotlinExtension = dependencyProject.multiplatformExtension + ?: return@associate dependency to dependency - if (dependencyProjectKotlinExtension.isGradleMetadataAvailable) - return@map dependency + val resolved = resolvedDependencies[Triple(dependency.group, dependency.name, dependency.version)] + ?: return@associate dependency to dependency - val resolved = resolvedCompileDependencies[Triple(dependency.group, dependency.name, dependency.version)] - ?: return@map dependency - - val resolvedToConfiguration = resolved.configuration - - val dependencyTargetComponent: KotlinTargetComponent = run { - dependencyProjectKotlinExtension.targets.forEach { target -> - target.components.forEach { component -> - if (component.findUsageContext(resolvedToConfiguration) != null) - return@run component + val resolvedToConfiguration = resolved.configuration + val dependencyTargetComponent: KotlinTargetComponent = run { + dependencyProjectKotlinExtension.targets.forEach { target -> + target.components.forEach { component -> + if (component.findUsageContext(resolvedToConfiguration) != null) + return@run component + } } + // Failed to find a matching component: + return@associate dependency to dependency } - // Failed to find a matching component: - return@map dependency + + val targetModulePublication = (dependencyTargetComponent as? KotlinTargetComponentWithPublication)?.publicationDelegate + val rootModulePublication = dependencyProjectKotlinExtension.rootSoftwareComponent.publicationDelegate + + // During Gradle POM generation, a project dependency is already written as the root module's coordinates. In the + // dependencies mapping, map the root module to the target's module: + + val rootModule = project.dependencies.module( + listOf( + rootModulePublication?.groupId ?: dependency.group, + rootModulePublication?.artifactId ?: dependencyProject.name, + rootModulePublication?.version ?: dependency.version + ).joinToString(":") + ) as ModuleDependency + + rootModule to project.dependencies.module( + listOf( + targetModulePublication?.groupId ?: dependency.group, + targetModulePublication?.artifactId ?: dependencyTargetComponent.defaultArtifactId, + targetModulePublication?.version ?: dependency.version + ).joinToString(":") + ) as ModuleDependency } + else -> { + val resolvedDependency = resolvedDependencies[Triple(dependency.group, dependency.name, dependency.version)] + ?: return@associate dependency to dependency - val publicationDelegate = (dependencyTargetComponent as? KotlinTargetComponentWithPublication)?.publicationDelegate + if (resolvedDependency.moduleArtifacts.isEmpty() && resolvedDependency.children.size == 1) { + // This is a dependency on a module that resolved to another module; map the original dependency to the target module + val targetModule = resolvedDependency.children.single() + dependency to project.dependencies.module( + listOf( + targetModule.moduleGroup, + targetModule.moduleName, + targetModule.moduleVersion + ).joinToString(":") + ) as ModuleDependency - dependencies.module( - listOf( - publicationDelegate?.groupId ?: dependency.group, - publicationDelegate?.artifactId ?: dependencyTargetComponent.defaultArtifactId, - publicationDelegate?.version ?: dependency.version - ).joinToString(":") - ) as ModuleDependency + } else { + dependency to dependency + } + } } - } - }.toSet() + }.mapKeys { (key, _) -> Triple(key.group, key.name, key.version) } + + return moduleDependencies.associate { dependency -> + val key = Triple(dependency.group, dependency.name, dependency.version) + val value = resolvedModulesByRootModuleCoordinates[key] ?: dependency + dependency to value + } } internal fun KotlinTargetComponent.findUsageContext(configurationName: String): UsageContext? { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt index a22d179c3a9..32d43821f90 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt @@ -95,9 +95,6 @@ abstract class AbstractKotlinTarget( componentName: String, artifactNameAppendix: String ): Set { - val publishWithKotlinMetadata = (project.kotlinExtension as? KotlinMultiplatformExtension)?.isGradleMetadataAvailable - ?: true // In non-MPP project, these usage contexts do not get published anyway - val sourcesJarArtifact = sourcesJarArtifact(producingCompilation, componentName, artifactNameAppendix) // Here, `JAVA_API` and `JAVA_RUNTIME_JARS` are used intentionally as Gradle needs this for @@ -111,7 +108,6 @@ abstract class AbstractKotlinTarget( producingCompilation, project.usageByName(usageName), dependenciesConfigurationName, - publishWithKotlinMetadata, sourcesJarArtifact ) } @@ -295,9 +291,6 @@ open class KotlinAndroidTarget( classifierPrefix = artifactClassifier ) - val publishWithKotlinMetadata = (project.kotlinExtension as? KotlinMultiplatformExtension)?.isGradleMetadataAvailable - ?: true // In non-MPP project, these usage contexts do not get published anyway - val variantName = getVariantName(variant) val outputTask = getLibraryOutputTask(variant) ?: return emptySet() val artifact = run { @@ -325,7 +318,6 @@ open class KotlinAndroidTarget( compilation, project.usageByName(usageName), dependencyConfigurationName, - publishWithKotlinMetadata, sourcesJarArtifact, overrideConfigurationArtifacts = setOf(artifact) ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt index 8cd91f9e830..8387de3caae 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp +import org.gradle.api.Project import org.gradle.api.artifacts.ExcludeRule import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.artifacts.ModuleIdentifier @@ -26,30 +27,35 @@ internal interface KotlinTargetComponentWithPublication : KotlinTargetComponent var publicationDelegate: MavenPublication? } -private interface KotlinTargetComponentWithCoordinatesAndPublication : - KotlinTargetComponentWithPublication, - ComponentWithCoordinates /* Gradle 4.7+ API, don't use with older versions */ -{ - override fun getCoordinates() = object : ModuleVersionIdentifier { - private val project get() = target.project - +internal fun getCoordinatesFromPublicationDelegateAndProject( + publication: MavenPublication?, + project: Project, + target: KotlinTarget? +): ModuleVersionIdentifier = + object : ModuleVersionIdentifier { private val moduleName: String get() = - publicationDelegate?.artifactId ?: "${project.name}-${target.name.toLowerCase()}" + publication?.artifactId ?: lowerSpinalCaseName(project.name, target?.name) private val moduleGroup: String get() = - publicationDelegate?.groupId ?: project.group.toString() + publication?.groupId ?: project.group.toString() override fun getGroup() = moduleGroup override fun getName() = moduleName - override fun getVersion() = publicationDelegate?.version ?: project.version.toString() + override fun getVersion() = publication?.version ?: project.version.toString() override fun getModule(): ModuleIdentifier = object : ModuleIdentifier { override fun getGroup(): String = moduleGroup override fun getName(): String = moduleName } } + +private interface KotlinTargetComponentWithCoordinatesAndPublication : + KotlinTargetComponentWithPublication, + ComponentWithCoordinates /* Gradle 4.7+ API, don't use with older versions */ +{ + override fun getCoordinates() = getCoordinatesFromPublicationDelegateAndProject(publicationDelegate, target.project, target) } open class KotlinVariant(