MPP granular source set metadata support
This commit is contained in:
+318
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.internals.parseKotlinSourceSetMetadataFromXml
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME
|
||||||
|
import org.jetbrains.kotlin.gradle.util.modify
|
||||||
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class HierarchicalMppIT : BaseGradleIT() {
|
||||||
|
companion object {
|
||||||
|
private val gradleVersion = GradleVersionRequired.AtLeast("5.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPublishedModules() {
|
||||||
|
Project("third-party-lib", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||||
|
setupWorkingDir()
|
||||||
|
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||||
|
build("publish") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Project("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||||
|
setupWorkingDir()
|
||||||
|
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||||
|
build("publish") {
|
||||||
|
checkMyLibFoo(this, subprojectPrefix = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Project("my-lib-bar", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||||
|
setupWorkingDir()
|
||||||
|
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||||
|
build("publish") {
|
||||||
|
checkMyLibBar(this, subprojectPrefix = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Project("my-app", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||||
|
setupWorkingDir()
|
||||||
|
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||||
|
build("assemble") {
|
||||||
|
checkMyApp(this, subprojectPrefix = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testProjectDependencies() {
|
||||||
|
Project("third-party-lib", gradleVersion, "hierarchical-mpp-project-dependency").run {
|
||||||
|
setupWorkingDir()
|
||||||
|
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||||
|
build("publish") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with(Project("hierarchical-mpp-project-dependency", gradleVersion)) {
|
||||||
|
setupWorkingDir()
|
||||||
|
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||||
|
|
||||||
|
build("publish", "assemble") {
|
||||||
|
checkMyLibFoo(this, subprojectPrefix = "my-lib-foo")
|
||||||
|
checkMyLibBar(this, subprojectPrefix = "my-lib-bar")
|
||||||
|
checkMyApp(this, subprojectPrefix = "my-app")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkMyLibFoo(compiledProject: CompiledProject, subprojectPrefix: String? = null) = with(compiledProject) {
|
||||||
|
val taskPrefix = subprojectPrefix?.let { ":$it" }.orEmpty()
|
||||||
|
val directoryPrefix = subprojectPrefix?.let { "$it/" }.orEmpty()
|
||||||
|
|
||||||
|
assertSuccessful()
|
||||||
|
assertTasksExecuted(expectedTasks(subprojectPrefix))
|
||||||
|
|
||||||
|
ZipFile(
|
||||||
|
project.projectDir.parentFile.resolve(
|
||||||
|
"repo/com/example/foo/my-lib-foo-metadata/1.0/my-lib-foo-metadata-1.0-all.jar"
|
||||||
|
)
|
||||||
|
).use { publishedMetadataJar ->
|
||||||
|
publishedMetadataJar.checkAllEntryNamesArePresent(
|
||||||
|
"META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME",
|
||||||
|
|
||||||
|
"commonMain/META-INF/my-lib-foo.kotlin_module",
|
||||||
|
"commonMain/com/example/foo/FooKt.kotlin_metadata",
|
||||||
|
|
||||||
|
"jvmAndJsMain/META-INF/my-lib-foo_jvmAndJsMain.kotlin_module",
|
||||||
|
"jvmAndJsMain/com/example/foo/FooJvmAndJsKt.kotlin_metadata",
|
||||||
|
|
||||||
|
"linuxAndJsMain/META-INF/my-lib-foo_linuxAndJsMain.kotlin_module",
|
||||||
|
"linuxAndJsMain/com/example/foo/FooLinuxAndJsKt.kotlin_metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
val parsedProjectStructureMetadata: KotlinProjectStructureMetadata = publishedMetadataJar.getProjectStructureMetadata()
|
||||||
|
|
||||||
|
val expectedProjectStructureMetadata = expectedProjectStructureMetadata(
|
||||||
|
sourceSetModuleDependencies = mapOf(
|
||||||
|
"jvmAndJsMain" to setOf("com.example.thirdparty" to "third-party-lib"),
|
||||||
|
"linuxAndJsMain" to emptySet(),
|
||||||
|
"commonMain" to emptySet()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(expectedProjectStructureMetadata, parsedProjectStructureMetadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkMyLibBar(compiledProject: CompiledProject, subprojectPrefix: String?) = with(compiledProject) {
|
||||||
|
val taskPrefix = subprojectPrefix?.let { ":$it" }.orEmpty()
|
||||||
|
|
||||||
|
assertSuccessful()
|
||||||
|
assertTasksExecuted(expectedTasks(subprojectPrefix))
|
||||||
|
|
||||||
|
ZipFile(
|
||||||
|
project.projectDir.parentFile.resolve(
|
||||||
|
"repo/com/example/bar/my-lib-bar-metadata/1.0/my-lib-bar-metadata-1.0-all.jar"
|
||||||
|
)
|
||||||
|
).use { publishedMetadataJar ->
|
||||||
|
publishedMetadataJar.checkAllEntryNamesArePresent(
|
||||||
|
"META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME",
|
||||||
|
|
||||||
|
"commonMain/META-INF/my-lib-bar.kotlin_module",
|
||||||
|
"commonMain/com/example/bar/BarKt.kotlin_metadata",
|
||||||
|
|
||||||
|
"jvmAndJsMain/META-INF/my-lib-bar_jvmAndJsMain.kotlin_module",
|
||||||
|
"jvmAndJsMain/com/example/bar/BarJvmAndJsKt.kotlin_metadata",
|
||||||
|
|
||||||
|
"linuxAndJsMain/META-INF/my-lib-bar_linuxAndJsMain.kotlin_module",
|
||||||
|
"linuxAndJsMain/com/example/bar/BarLinuxAndJsKt.kotlin_metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
val parsedProjectStructureMetadata: KotlinProjectStructureMetadata = publishedMetadataJar.getProjectStructureMetadata()
|
||||||
|
|
||||||
|
val expectedProjectStructureMetadata = expectedProjectStructureMetadata(
|
||||||
|
sourceSetModuleDependencies = mapOf(
|
||||||
|
"jvmAndJsMain" to setOf(),
|
||||||
|
"linuxAndJsMain" to emptySet(),
|
||||||
|
"commonMain" to setOf("com.example.foo" to "my-lib-foo")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(expectedProjectStructureMetadata, parsedProjectStructureMetadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNamesOnCompileClasspath(
|
||||||
|
"$taskPrefix:compileKotlinMetadata",
|
||||||
|
shouldInclude = listOf(
|
||||||
|
"my-lib-foo" to "main"
|
||||||
|
),
|
||||||
|
shouldNotInclude = listOf(
|
||||||
|
"my-lib-foo" to "jvmAndJsMain",
|
||||||
|
"my-lib-foo" to "linuxAndJsMain",
|
||||||
|
"third-party-lib-metadata-1.0" to ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
checkNamesOnCompileClasspath(
|
||||||
|
"$taskPrefix:compileJvmAndJsMainKotlinMetadata",
|
||||||
|
shouldInclude = listOf(
|
||||||
|
"my-lib-foo" to "main",
|
||||||
|
"my-lib-foo" to "jvmAndJsMain",
|
||||||
|
"third-party-lib-metadata-1.0" to ""
|
||||||
|
),
|
||||||
|
shouldNotInclude = listOf(
|
||||||
|
"my-lib-foo" to "linuxAndJsMain"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
checkNamesOnCompileClasspath(
|
||||||
|
"$taskPrefix:compileLinuxAndJsMainKotlinMetadata",
|
||||||
|
shouldInclude = listOf(
|
||||||
|
"my-lib-foo" to "linuxAndJsMain",
|
||||||
|
"my-lib-foo" to "main"
|
||||||
|
),
|
||||||
|
shouldNotInclude = listOf(
|
||||||
|
"my-lib-foo" to "jvmAndJsMain",
|
||||||
|
"third-party-lib-metadata-1.0" to ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkMyApp(compiledProject: CompiledProject, subprojectPrefix: String?) = with(compiledProject) {
|
||||||
|
val taskPrefix = subprojectPrefix?.let { ":$it" }.orEmpty()
|
||||||
|
|
||||||
|
assertSuccessful()
|
||||||
|
assertTasksExecuted(expectedTasks(subprojectPrefix))
|
||||||
|
|
||||||
|
checkNamesOnCompileClasspath(
|
||||||
|
"$taskPrefix:compileKotlinMetadata",
|
||||||
|
shouldInclude = listOf(
|
||||||
|
"my-lib-bar" to "main",
|
||||||
|
"my-lib-foo" to "main"
|
||||||
|
),
|
||||||
|
shouldNotInclude = listOf(
|
||||||
|
"my-lib-bar" to "jvmAndJsMain",
|
||||||
|
"my-lib-bar" to "linuxAndJsMain",
|
||||||
|
"my-lib-foo" to "jvmAndJsMain",
|
||||||
|
"my-lib-foo" to "linuxAndJsMain",
|
||||||
|
"third-party-lib-metadata-1.0" to ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
checkNamesOnCompileClasspath(
|
||||||
|
"$taskPrefix:compileJvmAndJsMainKotlinMetadata",
|
||||||
|
shouldInclude = listOf(
|
||||||
|
"my-lib-bar" to "main",
|
||||||
|
"my-lib-bar" to "jvmAndJsMain",
|
||||||
|
"my-lib-foo" to "main",
|
||||||
|
"my-lib-foo" to "jvmAndJsMain",
|
||||||
|
"third-party-lib-metadata-1.0" to ""
|
||||||
|
),
|
||||||
|
shouldNotInclude = listOf(
|
||||||
|
"my-lib-bar" to "linuxAndJsMain",
|
||||||
|
"my-lib-foo" to "linuxAndJsMain"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
checkNamesOnCompileClasspath(
|
||||||
|
"$taskPrefix:compileLinuxAndJsMainKotlinMetadata",
|
||||||
|
shouldInclude = listOf(
|
||||||
|
"my-lib-bar" to "main",
|
||||||
|
"my-lib-bar" to "linuxAndJsMain",
|
||||||
|
"my-lib-foo" to "main",
|
||||||
|
"my-lib-foo" to "linuxAndJsMain"
|
||||||
|
),
|
||||||
|
shouldNotInclude = listOf(
|
||||||
|
"my-lib-bar" to "jvmAndJsMain",
|
||||||
|
"my-lib-foo" to "jvmAndJsMain",
|
||||||
|
"third-party-lib-metadata-1.0" to ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
checkNamesOnCompileClasspath("$taskPrefix:compileLinuxAndJsMainKotlinMetadata")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CompiledProject.checkNamesOnCompileClasspath(
|
||||||
|
taskPath: String,
|
||||||
|
shouldInclude: Iterable<Pair<String, String>> = emptyList(),
|
||||||
|
shouldNotInclude: Iterable<Pair<String, String>> = emptyList()
|
||||||
|
) {
|
||||||
|
val taskOutput = getOutputForTask(taskPath.removePrefix(":"))
|
||||||
|
val compilerArgsLine = taskOutput.lines().single { "Kotlin compiler args:" in it }
|
||||||
|
val classpathItems = compilerArgsLine.substringAfter("-classpath").substringBefore(" -").split(File.pathSeparator)
|
||||||
|
|
||||||
|
shouldInclude.forEach { (module, sourceSet) ->
|
||||||
|
assertTrue("expected module '$module' source set '$sourceSet' on the classpath of task $taskPath") {
|
||||||
|
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") {
|
||||||
|
classpathItems.none { module in it && it.contains(sourceSet, ignoreCase = true) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun expectedTasks(subprojectPrefix: String?) = listOf(
|
||||||
|
"generateProjectStructureMetadata",
|
||||||
|
"transformCommonMainDependenciesMetadata",
|
||||||
|
"transformJvmAndJsMainDependenciesMetadata",
|
||||||
|
"transformLinuxAndJsMainDependenciesMetadata",
|
||||||
|
"compileKotlinMetadata",
|
||||||
|
"compileJvmAndJsMainKotlinMetadata",
|
||||||
|
"compileLinuxAndJsMainKotlinMetadata"
|
||||||
|
).map { subprojectPrefix?.let { ":$it" }.orEmpty() + ":" + it }
|
||||||
|
|
||||||
|
// the projects used in these tests are similar and only the dependencies differ:
|
||||||
|
private fun expectedProjectStructureMetadata(
|
||||||
|
sourceSetModuleDependencies: Map<String, Set<Pair<String, String>>>
|
||||||
|
): KotlinProjectStructureMetadata {
|
||||||
|
|
||||||
|
val jvmSourceSets = setOf("commonMain", "jvmAndJsMain")
|
||||||
|
val jsSourceSets = setOf("commonMain", "jvmAndJsMain", "linuxAndJsMain")
|
||||||
|
return KotlinProjectStructureMetadata(
|
||||||
|
sourceSetNamesByVariantName = mapOf(
|
||||||
|
"js-api" to jsSourceSets,
|
||||||
|
"js-runtime" to jsSourceSets,
|
||||||
|
"jvm-api" to jvmSourceSets,
|
||||||
|
"jvm-runtime" to jvmSourceSets,
|
||||||
|
"linuxX64-api" to setOf("commonMain", "linuxAndJsMain")
|
||||||
|
),
|
||||||
|
sourceSetsDependsOnRelation = mapOf(
|
||||||
|
"jvmAndJsMain" to setOf("commonMain"),
|
||||||
|
"linuxAndJsMain" to setOf("commonMain"),
|
||||||
|
"commonMain" to emptySet()
|
||||||
|
),
|
||||||
|
sourceSetModuleDependencies = sourceSetModuleDependencies
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ZipFile.checkAllEntryNamesArePresent(vararg expectedEntryNames: String) {
|
||||||
|
val entryNames = entries().asSequence().map { it.name }.toSet()
|
||||||
|
val entryNamesString = entryNames.joinToString()
|
||||||
|
expectedEntryNames.forEach {
|
||||||
|
assertTrue("expecting entry $it in entry names $entryNamesString") { it in entryNames }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ZipFile.getProjectStructureMetadata(): KotlinProjectStructureMetadata {
|
||||||
|
val documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||||
|
val document = getInputStream(getEntry("META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME"))
|
||||||
|
.use { inputStream -> documentBuilder.parse(inputStream) }
|
||||||
|
return checkNotNull(parseKotlinSourceSetMetadataFromXml(document))
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform").version("<pluginMarkerVersion>").apply(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
maven("$rootDir/../repo")
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.example.app"
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
linuxX64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api(project(":my-lib-bar"))
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
import com.example.bar.*
|
||||||
|
|
||||||
|
fun appCommon() {
|
||||||
|
foo()
|
||||||
|
fooCommon()
|
||||||
|
bar()
|
||||||
|
barCommon()
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.bar
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.foo.foo
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class AppTest {
|
||||||
|
@Test
|
||||||
|
fun testApp() {
|
||||||
|
appCommon()
|
||||||
|
assertEquals(foo(), fooCommon())
|
||||||
|
assertEquals(bar(), barCommon())
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
// fooLinuxAndJs() // unresolved
|
||||||
|
// barJvmAndJs // unresolved
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
import com.example.bar.*
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
|
||||||
|
fun appJvmAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooJvmAndJs()
|
||||||
|
// fooLinuxAndJs() //unresolved
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barJvmAndJs()
|
||||||
|
// barLinuxAndJs() // unresolved
|
||||||
|
|
||||||
|
thirdPartyFun()
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.bar.barJvmAndJs
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooJvmAndJs
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
|
||||||
|
fun testAppJvmAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooJvmAndJs()
|
||||||
|
// fooLinuxAndJs() //unresolved
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barJvmAndJs()
|
||||||
|
// barLinuxAndJs() // unresolved
|
||||||
|
|
||||||
|
thirdPartyFun()
|
||||||
|
|
||||||
|
appJvmAndJs()
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.bar.barJvmAndJs
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooJvmAndJs
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
import com.example.thirdparty.thirdPartyJvmFun
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
thirdPartyFun()
|
||||||
|
thirdPartyJvmFun()
|
||||||
|
|
||||||
|
fooCommon()
|
||||||
|
fooJvmAndJs()
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barJvmAndJs()
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.bar.barLinuxAndJs
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooLinuxAndJs
|
||||||
|
|
||||||
|
fun appLinuxAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooLinuxAndJs()
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barLinuxAndJs()
|
||||||
|
// barJvmAndJs() // unresolved
|
||||||
|
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.bar.barLinuxAndJs
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooLinuxAndJs
|
||||||
|
|
||||||
|
fun testAppLinuxAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooLinuxAndJs()
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barLinuxAndJs()
|
||||||
|
// barJvmAndJs() // unresolved
|
||||||
|
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
|
||||||
|
appLinuxAndJs()
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
|
||||||
|
fun appLinux() {
|
||||||
|
fooLinuxAndJs()
|
||||||
|
barLinuxAndJs()
|
||||||
|
}
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform")
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.example.bar"
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
linuxX64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api(project(":my-lib-foo"))
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven("$rootDir/../repo")
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
|
||||||
|
expect fun bar(): String
|
||||||
|
|
||||||
|
fun barCommon(): String {
|
||||||
|
foo()
|
||||||
|
// thirdPartyFun() //unresolved
|
||||||
|
return fooCommon()
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.foo
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class BarTest {
|
||||||
|
@Test
|
||||||
|
fun testBar() {
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
// fooLinuxAndJs() // unresolved
|
||||||
|
assertEquals(foo(), fooCommon())
|
||||||
|
assertEquals(bar(), barCommon())
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
|
||||||
|
actual fun bar(): String = barJvmAndJs()
|
||||||
|
|
||||||
|
fun barJvmAndJs(): String {
|
||||||
|
thirdPartyFun()
|
||||||
|
fooCommon()
|
||||||
|
// fooLinuxAndJs() //unresolved
|
||||||
|
return fooJvmAndJs()
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.foo
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class BarJvmAndJsTest {
|
||||||
|
@Test
|
||||||
|
fun testBarJvmAndJs() {
|
||||||
|
// barLinuxAndJs() // unresolved
|
||||||
|
assertEquals(foo(), barJvmAndJs())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testThirdParty() {
|
||||||
|
thirdPartyFun()
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
|
||||||
|
fun barLinuxAndJs(): String {
|
||||||
|
fooCommon()
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
return fooLinuxAndJs()
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooLinuxAndJs
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
class BarLinuxAndJsTest {
|
||||||
|
@Test
|
||||||
|
fun testBarLinuxAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooLinuxAndJs()
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
barLinuxAndJs()
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
|
||||||
|
actual fun bar(): String {
|
||||||
|
fooCommon()
|
||||||
|
fooLinuxAndJs()
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
return barLinuxAndJs()
|
||||||
|
}
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform")
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.example.foo"
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
// Add a target that the third-party-lib does not have:
|
||||||
|
linuxX64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
dependencies {
|
||||||
|
// Add the third-party-lib dependency only to these two platforms,
|
||||||
|
// as an API dependency, so that it is seen as transitive:
|
||||||
|
api("com.example.thirdparty:third-party-lib:1.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven("$rootDir/../repo")
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
expect fun foo(): String
|
||||||
|
|
||||||
|
fun fooCommon() = "foo"
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class FooTest {
|
||||||
|
@Test
|
||||||
|
fun testFoo() {
|
||||||
|
assertEquals(foo(), fooCommon())
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
|
||||||
|
actual fun foo() = fooJvmAndJs()
|
||||||
|
|
||||||
|
fun fooJvmAndJs(): String {
|
||||||
|
thirdPartyFun()
|
||||||
|
return fooCommon()
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class FooJvmAndJsTest {
|
||||||
|
@Test
|
||||||
|
fun testFooJvmAndJs() {
|
||||||
|
assertEquals(fooJvmAndJs(), foo())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testThirdParty() {
|
||||||
|
thirdPartyFun()
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
fun fooLinuxAndJs() = fooCommon()
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
class FooLinuxAndJsTest {
|
||||||
|
@Test
|
||||||
|
fun testFooJvmAndJs() {
|
||||||
|
assertEquals(foo(), fooCommon())
|
||||||
|
fooLinuxAndJs()
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
actual fun foo() = fooLinuxAndJs()
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "mpp-granular-metadata-demo"
|
||||||
|
|
||||||
|
include("my-lib-foo", "my-lib-bar", "my-app")
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.example.thirdparty"
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jvm().compilations["main"].defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jvm().compilations["test"].defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js().compilations["main"].defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js().compilations["test"].defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven("../repo")
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "third-party-lib"
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package com.example.thirdparty
|
||||||
|
|
||||||
|
expect fun thirdPartyFun(): String
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.thirdparty
|
||||||
|
|
||||||
|
actual fun thirdPartyFun(): String = "thirdPartyFun @ js"
|
||||||
|
|
||||||
|
fun thirdPartyJsFun() { }
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.thirdparty
|
||||||
|
|
||||||
|
actual fun thirdPartyFun(): String = "thirdPartyFun @ jvm"
|
||||||
|
|
||||||
|
fun thirdPartyJvmFun() { }
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
maven("../repo")
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.example.app"
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
linuxX64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api("com.example.bar:my-lib-bar:1.0")
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "my-app"
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
import com.example.bar.*
|
||||||
|
|
||||||
|
fun appCommon() {
|
||||||
|
foo()
|
||||||
|
fooCommon()
|
||||||
|
bar()
|
||||||
|
barCommon()
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.bar
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.foo.foo
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class AppTest {
|
||||||
|
@Test
|
||||||
|
fun testApp() {
|
||||||
|
appCommon()
|
||||||
|
assertEquals(foo(), fooCommon())
|
||||||
|
assertEquals(bar(), barCommon())
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
// fooLinuxAndJs() // unresolved
|
||||||
|
// barJvmAndJs // unresolved
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
import com.example.bar.*
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
|
||||||
|
fun appJvmAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooJvmAndJs()
|
||||||
|
// fooLinuxAndJs() //unresolved
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barJvmAndJs()
|
||||||
|
// barLinuxAndJs() // unresolved
|
||||||
|
|
||||||
|
thirdPartyFun()
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.bar.barJvmAndJs
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooJvmAndJs
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
|
||||||
|
fun testAppJvmAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooJvmAndJs()
|
||||||
|
// fooLinuxAndJs() //unresolved
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barJvmAndJs()
|
||||||
|
// barLinuxAndJs() // unresolved
|
||||||
|
|
||||||
|
thirdPartyFun()
|
||||||
|
|
||||||
|
appJvmAndJs()
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.bar.barJvmAndJs
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooJvmAndJs
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
import com.example.thirdparty.thirdPartyJvmFun
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
thirdPartyFun()
|
||||||
|
thirdPartyJvmFun()
|
||||||
|
|
||||||
|
fooCommon()
|
||||||
|
fooJvmAndJs()
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barJvmAndJs()
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.bar.barLinuxAndJs
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooLinuxAndJs
|
||||||
|
|
||||||
|
fun appLinuxAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooLinuxAndJs()
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barLinuxAndJs()
|
||||||
|
// barJvmAndJs() // unresolved
|
||||||
|
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import com.example.bar.barCommon
|
||||||
|
import com.example.bar.barLinuxAndJs
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooLinuxAndJs
|
||||||
|
|
||||||
|
fun testAppLinuxAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooLinuxAndJs()
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
|
||||||
|
barCommon()
|
||||||
|
barLinuxAndJs()
|
||||||
|
// barJvmAndJs() // unresolved
|
||||||
|
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
|
||||||
|
appLinuxAndJs()
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
|
||||||
|
fun appLinux() {
|
||||||
|
fooLinuxAndJs()
|
||||||
|
barLinuxAndJs()
|
||||||
|
}
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
maven("../repo")
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.example.bar"
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
linuxX64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
api("com.example.foo:my-lib-foo:1.0")
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven("../repo")
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "my-lib-bar"
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
|
||||||
|
expect fun bar(): String
|
||||||
|
|
||||||
|
fun barCommon(): String {
|
||||||
|
foo()
|
||||||
|
// thirdPartyFun() //unresolved
|
||||||
|
return fooCommon()
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.foo
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class BarTest {
|
||||||
|
@Test
|
||||||
|
fun testBar() {
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
// fooLinuxAndJs() // unresolved
|
||||||
|
assertEquals(foo(), fooCommon())
|
||||||
|
assertEquals(bar(), barCommon())
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
|
||||||
|
actual fun bar(): String = barJvmAndJs()
|
||||||
|
|
||||||
|
fun barJvmAndJs(): String {
|
||||||
|
thirdPartyFun()
|
||||||
|
fooCommon()
|
||||||
|
// fooLinuxAndJs() //unresolved
|
||||||
|
return fooJvmAndJs()
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.foo
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class BarJvmAndJsTest {
|
||||||
|
@Test
|
||||||
|
fun testBarJvmAndJs() {
|
||||||
|
// barLinuxAndJs() // unresolved
|
||||||
|
assertEquals(foo(), barJvmAndJs())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testThirdParty() {
|
||||||
|
thirdPartyFun()
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
|
||||||
|
fun barLinuxAndJs(): String {
|
||||||
|
fooCommon()
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
return fooLinuxAndJs()
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.fooCommon
|
||||||
|
import com.example.foo.fooLinuxAndJs
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
class BarLinuxAndJsTest {
|
||||||
|
@Test
|
||||||
|
fun testBarLinuxAndJs() {
|
||||||
|
fooCommon()
|
||||||
|
fooLinuxAndJs()
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
// thirdPartyFun() // unresolved
|
||||||
|
barLinuxAndJs()
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.example.bar
|
||||||
|
|
||||||
|
import com.example.foo.*
|
||||||
|
|
||||||
|
actual fun bar(): String {
|
||||||
|
fooCommon()
|
||||||
|
fooLinuxAndJs()
|
||||||
|
// fooJvmAndJs() // unresolved
|
||||||
|
return barLinuxAndJs()
|
||||||
|
}
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
maven("../repo")
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.example.foo"
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
// Add a target that the third-party-lib does not have:
|
||||||
|
linuxX64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
dependencies {
|
||||||
|
// Add the third-party-lib dependency only to these two platforms,
|
||||||
|
// as an API dependency, so that it is seen as transitive:
|
||||||
|
api("com.example.thirdparty:third-party-lib:1.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
val linuxAndJsTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvm().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsMain)
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
js().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(jvmAndJsTest)
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["main"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
linuxX64().compilations["test"].defaultSourceSet {
|
||||||
|
dependsOn(linuxAndJsTest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven("../repo")
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "my-lib-foo"
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
expect fun foo(): String
|
||||||
|
|
||||||
|
fun fooCommon() = "foo"
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class FooTest {
|
||||||
|
@Test
|
||||||
|
fun testFoo() {
|
||||||
|
assertEquals(foo(), fooCommon())
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
|
||||||
|
actual fun foo() = fooJvmAndJs()
|
||||||
|
|
||||||
|
fun fooJvmAndJs(): String {
|
||||||
|
thirdPartyFun()
|
||||||
|
return fooCommon()
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
import com.example.thirdparty.thirdPartyFun
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class FooJvmAndJsTest {
|
||||||
|
@Test
|
||||||
|
fun testFooJvmAndJs() {
|
||||||
|
assertEquals(fooJvmAndJs(), foo())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testThirdParty() {
|
||||||
|
thirdPartyFun()
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
fun fooLinuxAndJs() = fooCommon()
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
class FooLinuxAndJsTest {
|
||||||
|
@Test
|
||||||
|
fun testFooJvmAndJs() {
|
||||||
|
assertEquals(foo(), fooCommon())
|
||||||
|
fooLinuxAndJs()
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package com.example.foo
|
||||||
|
|
||||||
|
actual fun foo() = fooLinuxAndJs()
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.example.thirdparty"
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
js()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jvm().compilations["main"].defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jvm().compilations["test"].defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js().compilations["main"].defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js().compilations["test"].defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-js"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven("../repo")
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "third-party-lib"
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package com.example.thirdparty
|
||||||
|
|
||||||
|
expect fun thirdPartyFun(): String
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.thirdparty
|
||||||
|
|
||||||
|
actual fun thirdPartyFun(): String = "thirdPartyFun @ js"
|
||||||
|
|
||||||
|
fun thirdPartyJsFun() { }
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.thirdparty
|
||||||
|
|
||||||
|
actual fun thirdPartyFun(): String = "thirdPartyFun @ jvm"
|
||||||
|
|
||||||
|
fun thirdPartyJvmFun() { }
|
||||||
+1
-1
@@ -86,7 +86,7 @@ abstract class KotlinBasePluginWrapper(
|
|||||||
|
|
||||||
private fun setupAttributeMatchingStrategy(project: Project) = with(project.dependencies.attributesSchema) {
|
private fun setupAttributeMatchingStrategy(project: Project) = with(project.dependencies.attributesSchema) {
|
||||||
KotlinPlatformType.setupAttributesMatchingStrategy(this)
|
KotlinPlatformType.setupAttributesMatchingStrategy(this)
|
||||||
KotlinUsages.setupAttributesMatchingStrategy(this)
|
KotlinUsages.setupAttributesMatchingStrategy(project, this)
|
||||||
ProjectLocalConfigurations.setupAttributesMatchingStrategy(this)
|
ProjectLocalConfigurations.setupAttributesMatchingStrategy(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -88,6 +88,9 @@ internal class PropertiesProvider(private val project: Project) {
|
|||||||
val setJvmTargetFromAndroidCompileOptions: Boolean?
|
val setJvmTargetFromAndroidCompileOptions: Boolean?
|
||||||
get() = booleanProperty("kotlin.setJvmTargetFromAndroidCompileOptions")
|
get() = booleanProperty("kotlin.setJvmTargetFromAndroidCompileOptions")
|
||||||
|
|
||||||
|
val enableGranularSourceSetsMetadata: Boolean?
|
||||||
|
get() = booleanProperty("kotlin.mpp.enableGranularSourceSetsMetadata")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables parallel tasks execution within a project with Workers API.
|
* Enables parallel tasks execution within a project with Workers API.
|
||||||
* Does not enable using actual worker proccesses
|
* Does not enable using actual worker proccesses
|
||||||
|
|||||||
+22
-19
@@ -22,6 +22,7 @@ import org.gradle.api.tasks.Delete
|
|||||||
import org.gradle.api.tasks.bundling.Jar
|
import org.gradle.api.tasks.bundling.Jar
|
||||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||||
import org.gradle.language.jvm.tasks.ProcessResources
|
import org.gradle.language.jvm.tasks.ProcessResources
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
|
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
|
||||||
@@ -54,31 +55,28 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
|
|||||||
cleanTask.delete(kotlinCompilation.output.allOutputs)
|
cleanTask.delete(kotlinCompilation.output.allOutputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun setupCompilationDependencyFiles(project: Project, compilation: KotlinCompilation<KotlinCommonOptions>) {
|
||||||
|
compilation.compileDependencyFiles = project.configurations.maybeCreate(compilation.compileDependencyConfigurationName)
|
||||||
|
if (compilation is KotlinCompilationToRunnableFiles) {
|
||||||
|
compilation.runtimeDependencyFiles = project.configurations.maybeCreate(compilation.runtimeDependencyConfigurationName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected open fun configureCompilations(platformTarget: KotlinTargetType) {
|
protected open fun configureCompilations(platformTarget: KotlinTargetType) {
|
||||||
val project = platformTarget.project
|
val project = platformTarget.project
|
||||||
val main = platformTarget.compilations.create(KotlinCompilation.MAIN_COMPILATION_NAME)
|
val main = platformTarget.compilations.create(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||||
|
|
||||||
platformTarget.compilations.all {
|
platformTarget.compilations.all {
|
||||||
project.registerOutputsForStaleOutputCleanup(it)
|
project.registerOutputsForStaleOutputCleanup(it)
|
||||||
it.compileDependencyFiles = project.configurations.maybeCreate(it.compileDependencyConfigurationName)
|
setupCompilationDependencyFiles(project, it)
|
||||||
if (it is KotlinCompilationToRunnableFiles) {
|
|
||||||
it.runtimeDependencyFiles = project.configurations.maybeCreate(it.runtimeDependencyConfigurationName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (createTestCompilation) {
|
if (createTestCompilation) {
|
||||||
platformTarget.compilations.create(KotlinCompilation.TEST_COMPILATION_NAME).apply {
|
platformTarget.compilations.create(KotlinCompilation.TEST_COMPILATION_NAME).apply {
|
||||||
compileDependencyFiles = project.files(
|
compileDependencyFiles += main.output.allOutputs
|
||||||
main.output.allOutputs,
|
|
||||||
project.configurations.maybeCreate(compileDependencyConfigurationName)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (this is KotlinCompilationToRunnableFiles) {
|
if (this is KotlinCompilationToRunnableFiles) {
|
||||||
runtimeDependencyFiles = project.files(
|
runtimeDependencyFiles += project.files(output.allOutputs, main.output.allOutputs)
|
||||||
output.allOutputs,
|
|
||||||
main.output.allOutputs,
|
|
||||||
project.configurations.maybeCreate(runtimeDependencyConfigurationName)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,17 +326,21 @@ abstract class KotlinTargetConfigurator<KotlinCompilationType : KotlinCompilatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The implementations are expected to create a [Jar] task under the name [KotlinTarget.artifactsTaskName] of the [target]. */
|
||||||
|
protected open fun createJarTasks(target: KotlinOnlyTarget<KotlinCompilationType>) {
|
||||||
|
val result = target.project.tasks.create(target.artifactsTaskName, Jar::class.java)
|
||||||
|
result.description = "Assembles a jar archive containing the main classes."
|
||||||
|
result.group = BasePlugin.BUILD_GROUP
|
||||||
|
result.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
|
||||||
|
}
|
||||||
|
|
||||||
override fun configureArchivesAndComponent(target: KotlinOnlyTarget<KotlinCompilationType>) {
|
override fun configureArchivesAndComponent(target: KotlinOnlyTarget<KotlinCompilationType>) {
|
||||||
val project = target.project
|
val project = target.project
|
||||||
|
|
||||||
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||||
|
|
||||||
val jar = project.tasks.create(target.artifactsTaskName, Jar::class.java)
|
createJarTasks(target)
|
||||||
jar.description = "Assembles a jar archive containing the main classes."
|
val jar = project.tasks.getByName(target.artifactsTaskName) as Jar
|
||||||
jar.group = BasePlugin.BUILD_GROUP
|
|
||||||
jar.from(mainCompilation.output.allOutputs)
|
|
||||||
|
|
||||||
val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
|
|
||||||
|
|
||||||
target.disambiguationClassifier?.let { jar.appendix = it.toLowerCase() }
|
target.disambiguationClassifier?.let { jar.appendix = it.toLowerCase() }
|
||||||
|
|
||||||
@@ -349,6 +351,7 @@ abstract class KotlinTargetConfigurator<KotlinCompilationType : KotlinCompilatio
|
|||||||
jarArtifact.builtBy(jar)
|
jarArtifact.builtBy(jar)
|
||||||
jarArtifact.type = ArtifactTypeDefinition.JAR_TYPE
|
jarArtifact.type = ArtifactTypeDefinition.JAR_TYPE
|
||||||
|
|
||||||
|
val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
|
||||||
addJar(apiElementsConfiguration, jarArtifact)
|
addJar(apiElementsConfiguration, jarArtifact)
|
||||||
|
|
||||||
if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
|
if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.DefaultTask
|
||||||
|
import org.gradle.api.tasks.Internal
|
||||||
|
import org.gradle.api.tasks.Nested
|
||||||
|
import org.gradle.api.tasks.OutputFile
|
||||||
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import java.io.File
|
||||||
|
import javax.xml.transform.OutputKeys
|
||||||
|
import javax.xml.transform.TransformerFactory
|
||||||
|
import javax.xml.transform.dom.DOMSource
|
||||||
|
import javax.xml.transform.stream.StreamResult
|
||||||
|
|
||||||
|
open class GenerateProjectStructureMetadata : DefaultTask() {
|
||||||
|
@get:Internal
|
||||||
|
internal lateinit var lazyKotlinProjectStructureMetadata: Lazy<KotlinProjectStructureMetadata>
|
||||||
|
|
||||||
|
@get:Nested
|
||||||
|
internal val kotlinProjectStructureMetadata: KotlinProjectStructureMetadata
|
||||||
|
get() = lazyKotlinProjectStructureMetadata.value
|
||||||
|
|
||||||
|
@get:OutputFile
|
||||||
|
val resultXmlFile: File
|
||||||
|
get() = project.buildDir.resolve("kotlinProjectStructureMetadata/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME")
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun generateMetadataXml() {
|
||||||
|
resultXmlFile.parentFile.mkdirs()
|
||||||
|
|
||||||
|
val document = kotlinProjectStructureMetadata.toXmlDocument()
|
||||||
|
|
||||||
|
TransformerFactory.newInstance().newTransformer().apply {
|
||||||
|
setOutputProperty(OutputKeys.INDENT, "yes")
|
||||||
|
setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4")
|
||||||
|
}.transform(DOMSource(document), StreamResult(resultXmlFile))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME = "kotlin-project-structure-metadata.xml"
|
||||||
+375
@@ -0,0 +1,375 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.artifacts.*
|
||||||
|
import org.gradle.api.file.FileCollection
|
||||||
|
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.sources.KotlinDependencyScope
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
|
||||||
|
internal sealed class MetadataDependencyResolution(
|
||||||
|
val dependency: ResolvedDependency,
|
||||||
|
val projectDependency: ProjectDependency?
|
||||||
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
val verb = when (this) {
|
||||||
|
is KeepOriginalDependency -> "keep"
|
||||||
|
is ExcludeAsUnrequested -> "exclude"
|
||||||
|
is ChooseVisibleSourceSets -> "choose"
|
||||||
|
}
|
||||||
|
return "$verb, dependency = $dependency"
|
||||||
|
}
|
||||||
|
|
||||||
|
class KeepOriginalDependency(
|
||||||
|
dependency: ResolvedDependency,
|
||||||
|
projectDependency: ProjectDependency?
|
||||||
|
) : MetadataDependencyResolution(dependency, projectDependency)
|
||||||
|
|
||||||
|
class ExcludeAsUnrequested(
|
||||||
|
dependency: ResolvedDependency,
|
||||||
|
projectDependency: ProjectDependency?
|
||||||
|
) : MetadataDependencyResolution(dependency, projectDependency)
|
||||||
|
|
||||||
|
abstract class ChooseVisibleSourceSets(
|
||||||
|
dependency: ResolvedDependency,
|
||||||
|
projectDependency: ProjectDependency?,
|
||||||
|
val projectStructureMetadata: KotlinProjectStructureMetadata,
|
||||||
|
val allVisibleSourceSetNames: Set<String>,
|
||||||
|
val visibleSourceSetNamesExcludingDependsOn: Set<String>,
|
||||||
|
val visibleTransitiveDependencies: Set<ResolvedDependency>
|
||||||
|
) : MetadataDependencyResolution(dependency, projectDependency) {
|
||||||
|
/** Returns the mapping of source set names to files which should be used as the [dependency] parts representing the source sets.
|
||||||
|
* If any temporary files need to be created, their paths are built from the [baseDir].
|
||||||
|
* If [doProcessFiles] is true, these temporary files are actually re-created during the call,
|
||||||
|
* otherwise only their paths are returned, while the files might be missing.
|
||||||
|
*/
|
||||||
|
abstract fun getMetadataFilesBySourceSet(baseDir: File, doProcessFiles: Boolean): Map<String, FileCollection>
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
super.toString() + ", sourceSets = " + allVisibleSourceSetNames.joinToString(", ", "[", "]") {
|
||||||
|
(if (it in visibleSourceSetNamesExcludingDependsOn) "*" else "") + it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private typealias ModuleId = Pair<String?, String> // group ID, artifact ID
|
||||||
|
|
||||||
|
private val ResolvedDependency.moduleId: ModuleId
|
||||||
|
get() = moduleGroup to moduleName
|
||||||
|
|
||||||
|
internal class GranularMetadataTransformation(
|
||||||
|
val project: Project,
|
||||||
|
val kotlinSourceSet: KotlinSourceSet,
|
||||||
|
/** A list of scopes that the dependencies from [kotlinSourceSet] are treated as requested dependencies. */
|
||||||
|
val sourceSetRequestedScopes: List<KotlinDependencyScope>,
|
||||||
|
/** A configuration that holds the dependencies of the appropriate scope for all Kotlin source sets in the project */
|
||||||
|
val allSourceSetsConfigurations: Iterable<Configuration>
|
||||||
|
) {
|
||||||
|
val metadataDependencyResolutions: Iterable<MetadataDependencyResolution> by lazy { doTransform() }
|
||||||
|
|
||||||
|
// Keep parents of each dependency, too. We need a dependency's parent when it's an MPP's metadata module dependency:
|
||||||
|
// in this case, the parent is the MPP's root module.
|
||||||
|
private data class ResolvedDependencyWithParent(
|
||||||
|
val dependency: ResolvedDependency,
|
||||||
|
val parent: ResolvedDependency?
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun collectProjectDependencies(
|
||||||
|
requestedDependencies: Iterable<ProjectDependency>,
|
||||||
|
resolvedDependencies: Iterable<ResolvedDependency>
|
||||||
|
): Map<ModuleId, ProjectDependency> {
|
||||||
|
val result = mutableMapOf<ModuleId, ProjectDependency>()
|
||||||
|
|
||||||
|
val resolvedDependenciesMap: Map<ModuleId, ResolvedDependency> = resolvedDependencies.associateBy { it.moduleId }
|
||||||
|
|
||||||
|
fun visitProjectDependency(projectDependency: ProjectDependency) {
|
||||||
|
val moduleId = projectDependency.group to projectDependency.name
|
||||||
|
|
||||||
|
if (moduleId in result) return
|
||||||
|
result[moduleId] = projectDependency
|
||||||
|
|
||||||
|
val resolvedDependency = resolvedDependenciesMap[moduleId] ?: return
|
||||||
|
|
||||||
|
projectDependency.dependencyProject.configurations.getByName(resolvedDependency.configuration)
|
||||||
|
.allDependencies
|
||||||
|
.withType(ProjectDependency::class.java)
|
||||||
|
.forEach(::visitProjectDependency)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestedDependencies.forEach(::visitProjectDependency)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRequestedDependencies(kotlinSourceSet: KotlinSourceSet): Set<Dependency> {
|
||||||
|
val hierarchy = kotlinSourceSet.getSourceSetHierarchy().toMutableSet()
|
||||||
|
|
||||||
|
// This is an ad-hoc mechanism for exposing the commonMain dependencies to test source sets as well:
|
||||||
|
// TODO once a general production-test visibility mechanism is implemented, replace this workaround with the general solution
|
||||||
|
if (hierarchy.any { it.name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME }) {
|
||||||
|
hierarchy += project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME).getSourceSetHierarchy()
|
||||||
|
}
|
||||||
|
|
||||||
|
return hierarchy.flatMapTo(mutableSetOf()) { sourceSet ->
|
||||||
|
sourceSetRequestedScopes.flatMap { scope ->
|
||||||
|
project.sourceSetDependencyConfigurationByScope(sourceSet, scope).allDependencies
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doTransform(): Iterable<MetadataDependencyResolution> {
|
||||||
|
val result = mutableListOf<MetadataDependencyResolution>()
|
||||||
|
|
||||||
|
val resolvedDependenciesFromAllSourceSets = allSourceSetsConfigurations.map { it.resolvedConfiguration.lenientConfiguration }
|
||||||
|
|
||||||
|
val visitedDependencies = mutableSetOf<ResolvedDependency>()
|
||||||
|
|
||||||
|
val directRequestedDependencies = getRequestedDependencies(kotlinSourceSet)
|
||||||
|
|
||||||
|
val directRequestedModules: Set<ModuleId> = directRequestedDependencies.mapTo(mutableSetOf()) { it.group to it.name }
|
||||||
|
|
||||||
|
val allModuleDependencies = resolvedDependenciesFromAllSourceSets.flatMapTo(mutableSetOf()) { it.allModuleDependencies }
|
||||||
|
|
||||||
|
val knownProjectDependencies = collectProjectDependencies(
|
||||||
|
directRequestedDependencies.filterIsInstance<ProjectDependency>(),
|
||||||
|
allModuleDependencies
|
||||||
|
)
|
||||||
|
|
||||||
|
val resolvedDependencyQueue: Queue<ResolvedDependencyWithParent> = ArrayDeque<ResolvedDependencyWithParent>().apply {
|
||||||
|
addAll(
|
||||||
|
resolvedDependenciesFromAllSourceSets.flatMap { it.firstLevelModuleDependencies }
|
||||||
|
.filter { it.moduleId in directRequestedModules }
|
||||||
|
.map { ResolvedDependencyWithParent(it, null) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
while (resolvedDependencyQueue.isNotEmpty()) {
|
||||||
|
val (resolvedDependency, parent: ResolvedDependency?) = resolvedDependencyQueue.poll()
|
||||||
|
|
||||||
|
val projectDependency: ProjectDependency? = knownProjectDependencies[resolvedDependency.moduleId]
|
||||||
|
|
||||||
|
visitedDependencies.add(resolvedDependency)
|
||||||
|
|
||||||
|
val dependencyResult = processDependency(resolvedDependency, parent, projectDependency)
|
||||||
|
result.add(dependencyResult)
|
||||||
|
|
||||||
|
val transitiveDependenciesToVisit = when (dependencyResult) {
|
||||||
|
is MetadataDependencyResolution.KeepOriginalDependency -> resolvedDependency.children
|
||||||
|
is MetadataDependencyResolution.ChooseVisibleSourceSets -> dependencyResult.visibleTransitiveDependencies
|
||||||
|
is MetadataDependencyResolution.ExcludeAsUnrequested -> error("a visited dependency is erroneously considered unrequested")
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedDependencyQueue.addAll(
|
||||||
|
transitiveDependenciesToVisit.filter { it !in visitedDependencies }
|
||||||
|
.map { ResolvedDependencyWithParent(it, resolvedDependency) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
allModuleDependencies.forEach { resolvedDependency ->
|
||||||
|
if (resolvedDependency !in visitedDependencies) {
|
||||||
|
result.add(
|
||||||
|
MetadataDependencyResolution.ExcludeAsUnrequested(
|
||||||
|
resolvedDependency,
|
||||||
|
knownProjectDependencies[resolvedDependency.moduleGroup to resolvedDependency.moduleName]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the [module] is an MPP metadata module, we extract [KotlinProjectStructureMetadata] and do the following:
|
||||||
|
*
|
||||||
|
* * get the [KotlinProjectStructureMetadata] from the dependency (either deserialize from the artifact or build from the project)
|
||||||
|
*
|
||||||
|
* * determine the set *S* of source sets that should be seen in the [kotlinSourceSet] by finding which variants the [parent]
|
||||||
|
* dependency got resolved for the compilations where [kotlinSourceSet] participates:
|
||||||
|
*
|
||||||
|
* * transform the single Kotlin metadata artifact into a set of Kotlin metadata artifacts for the particular source sets in
|
||||||
|
* *S* and add the results as [MetadataDependencyResolution.ChooseVisibleSourceSets]
|
||||||
|
*
|
||||||
|
* * based on the project structure metadata, determine which of the module's dependencies are requested by the
|
||||||
|
* source sets in *S*, then consider only these transitive dependencies, ignore the others;
|
||||||
|
*/
|
||||||
|
private fun processDependency(
|
||||||
|
module: ResolvedDependency,
|
||||||
|
parent: ResolvedDependency?,
|
||||||
|
projectDependency: ProjectDependency?
|
||||||
|
): MetadataDependencyResolution {
|
||||||
|
|
||||||
|
val mppDependencyMetadataExtractor = when {
|
||||||
|
projectDependency != null -> ProjectMppDependencyMetadataExtractor(project, module, projectDependency.dependencyProject)
|
||||||
|
parent != null -> JarArtifactMppDependencyMetadataExtractor(project, module)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
val projectStructureMetadata = mppDependencyMetadataExtractor?.getProjectStructureMetadata()
|
||||||
|
|
||||||
|
if (projectStructureMetadata == null) {
|
||||||
|
return MetadataDependencyResolution.KeepOriginalDependency(module, projectDependency)
|
||||||
|
}
|
||||||
|
|
||||||
|
val (allVisibleSourceSets, visibleByParents) =
|
||||||
|
SourceSetVisibilityProvider(project).getVisibleSourceSets(
|
||||||
|
kotlinSourceSet,
|
||||||
|
sourceSetRequestedScopes,
|
||||||
|
parent ?: module,
|
||||||
|
projectStructureMetadata,
|
||||||
|
projectDependency?.dependencyProject
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keep only the transitive dependencies requested by the visible source sets:
|
||||||
|
// Visit the transitive dependencies visible by parents, too (i.e. allVisibleSourceSets), as this source set might get a more
|
||||||
|
// concrete view on them:
|
||||||
|
val requestedTransitiveDependencies: Set<ModuleId> =
|
||||||
|
mutableSetOf<ModuleId>().apply {
|
||||||
|
projectStructureMetadata.sourceSetModuleDependencies
|
||||||
|
.filterKeys { it in allVisibleSourceSets }
|
||||||
|
.forEach { addAll(it.value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val transitiveDependenciesToVisit = module.children.filterTo(mutableSetOf()) {
|
||||||
|
(it.moduleId) in requestedTransitiveDependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
val visibleSourceSetsExcludingDependsOn = allVisibleSourceSets.filterTo(mutableSetOf()) { it !in visibleByParents }
|
||||||
|
|
||||||
|
return object : MetadataDependencyResolution.ChooseVisibleSourceSets(
|
||||||
|
module,
|
||||||
|
projectDependency,
|
||||||
|
projectStructureMetadata,
|
||||||
|
allVisibleSourceSets,
|
||||||
|
visibleSourceSetsExcludingDependsOn,
|
||||||
|
transitiveDependenciesToVisit
|
||||||
|
) {
|
||||||
|
override fun getMetadataFilesBySourceSet(baseDir: File, doProcessFiles: Boolean): Map<String, FileCollection> =
|
||||||
|
mppDependencyMetadataExtractor.getVisibleSourceSetsMetadata(visibleSourceSetsExcludingDependsOn, baseDir, doProcessFiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract class MppDependencyMetadataExtractor(val project: Project, val dependency: ResolvedDependency) {
|
||||||
|
abstract fun getProjectStructureMetadata(): KotlinProjectStructureMetadata?
|
||||||
|
abstract fun getVisibleSourceSetsMetadata(
|
||||||
|
visibleSourceSetNames: Set<String>,
|
||||||
|
baseDir: File,
|
||||||
|
doProcessFiles: Boolean
|
||||||
|
): Map<String, FileCollection>
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProjectMppDependencyMetadataExtractor(
|
||||||
|
project: Project,
|
||||||
|
dependency: ResolvedDependency,
|
||||||
|
private val dependencyProject: Project
|
||||||
|
) : MppDependencyMetadataExtractor(project, dependency) {
|
||||||
|
override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? =
|
||||||
|
buildKotlinProjectStructureMetadata(dependencyProject)
|
||||||
|
|
||||||
|
override fun getVisibleSourceSetsMetadata(
|
||||||
|
visibleSourceSetNames: Set<String>,
|
||||||
|
baseDir: File,
|
||||||
|
doProcessFiles: Boolean
|
||||||
|
): Map<String, FileCollection> =
|
||||||
|
dependencyProject.multiplatformExtension.targets.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME).compilations
|
||||||
|
.filter { it.defaultSourceSet.name in visibleSourceSetNames }
|
||||||
|
.associate { it.defaultSourceSet.name to it.output.classesDirs }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JarArtifactMppDependencyMetadataExtractor(
|
||||||
|
project: Project,
|
||||||
|
dependency: ResolvedDependency
|
||||||
|
) : MppDependencyMetadataExtractor(project, dependency) {
|
||||||
|
|
||||||
|
private val artifact: ResolvedArtifact?
|
||||||
|
get() = dependency.moduleArtifacts.singleOrNull { it.extension == "jar" }
|
||||||
|
|
||||||
|
override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? {
|
||||||
|
val artifactFile = artifact?.file ?: return null
|
||||||
|
|
||||||
|
return ZipFile(artifactFile).use { zip ->
|
||||||
|
val metadata = zip.getEntry("META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME")
|
||||||
|
?: return null
|
||||||
|
|
||||||
|
val metadataXmlDocument = zip.getInputStream(metadata).use { inputStream ->
|
||||||
|
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
parseKotlinSourceSetMetadataFromXml(metadataXmlDocument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVisibleSourceSetsMetadata(
|
||||||
|
visibleSourceSetNames: Set<String>,
|
||||||
|
baseDir: File,
|
||||||
|
doProcessFiles: Boolean
|
||||||
|
): Map<String, FileCollection> {
|
||||||
|
val jarArtifact = artifact ?: return emptyMap()
|
||||||
|
val artifactFile = jarArtifact.file
|
||||||
|
val moduleId = jarArtifact.moduleVersion.id
|
||||||
|
|
||||||
|
return extractSourceSetMetadataFromJar(moduleId, visibleSourceSetNames, artifactFile, baseDir, doProcessFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractSourceSetMetadataFromJar(
|
||||||
|
module: ModuleVersionIdentifier,
|
||||||
|
chooseSourceSetsByNames: Set<String>,
|
||||||
|
artifactJar: File,
|
||||||
|
baseDir: File,
|
||||||
|
doProcessFiles: Boolean
|
||||||
|
): Map<String, FileCollection> {
|
||||||
|
val moduleString = "${module.group}-${module.name}-${module.version}"
|
||||||
|
val transformedModuleRoot = run { baseDir.resolve(moduleString).also { it.mkdirs() } }
|
||||||
|
|
||||||
|
val resultFiles = mutableMapOf<String, FileCollection>()
|
||||||
|
|
||||||
|
ZipFile(artifactJar).use { zip ->
|
||||||
|
val entriesBySourceSet = zip.entries().asSequence()
|
||||||
|
.groupBy { it.name.substringBefore("/") }
|
||||||
|
.filterKeys { it in chooseSourceSetsByNames }
|
||||||
|
|
||||||
|
entriesBySourceSet.forEach { (sourceSetName, entries) ->
|
||||||
|
// TODO: once IJ supports non-JAR metadata dependencies, extraact to a directory, not a JAR
|
||||||
|
// Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed
|
||||||
|
val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.jar")
|
||||||
|
|
||||||
|
resultFiles[sourceSetName] = project.files(extractToJarFile)
|
||||||
|
|
||||||
|
if (doProcessFiles) {
|
||||||
|
ZipOutputStream(extractToJarFile.outputStream()).use { resultZipOutput ->
|
||||||
|
for (entry in entries) {
|
||||||
|
if (entry.isDirectory)
|
||||||
|
continue
|
||||||
|
|
||||||
|
// Drop the source set name from the entry path
|
||||||
|
val resultEntry = ZipEntry(entry.name.substringAfter("/"))
|
||||||
|
|
||||||
|
zip.getInputStream(entry).use { inputStream ->
|
||||||
|
resultZipOutput.putNextEntry(resultEntry)
|
||||||
|
inputStream.copyTo(resultZipOutput)
|
||||||
|
resultZipOutput.closeEntry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultFiles
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-5
@@ -19,11 +19,13 @@ class KotlinCommonCompilation(
|
|||||||
override val compileKotlinTask: KotlinCompileCommon
|
override val compileKotlinTask: KotlinCompileCommon
|
||||||
get() = super.compileKotlinTask as KotlinCompileCommon
|
get() = super.compileKotlinTask as KotlinCompileCommon
|
||||||
|
|
||||||
// TODO once we properly compile metadata for each source set, the default source sets will likely become just the source sets
|
private val commonSourceSetName by lazy {
|
||||||
// which are transformed to metadata
|
when (compilationName) {
|
||||||
private val commonSourceSetName = when (compilationName) {
|
// Historically, a metadata target has a main compilation. We keep using it to compile just the commonMain source set:
|
||||||
KotlinCompilation.MAIN_COMPILATION_NAME -> KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME
|
KotlinCompilation.MAIN_COMPILATION_NAME -> KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME
|
||||||
else -> error("Custom metadata compilations are not supported yet")
|
// All other common source sets are compiled by compilations named according to the source sets:
|
||||||
|
else -> compilationName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val defaultSourceSet: KotlinSourceSet
|
override val defaultSourceSet: KotlinSourceSet
|
||||||
|
|||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.artifacts.ConfigurablePublishArtifact
|
||||||
|
import org.gradle.api.artifacts.Dependency
|
||||||
|
import org.gradle.api.attributes.Usage.JAVA_API
|
||||||
|
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
||||||
|
|
||||||
|
internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadataElements"
|
||||||
|
|
||||||
|
open class KotlinMetadataTarget(project: Project) : KotlinOnlyTarget<KotlinCommonCompilation>(project, KotlinPlatformType.common) {
|
||||||
|
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(if (isGradleVersionAtLeast(5, 3)) "java-api-jars" else JAVA_API)
|
||||||
|
|
||||||
|
usageContexts += run {
|
||||||
|
val allMetadataJar = project.tasks.getByName(KotlinMetadataTargetConfigurator.ALL_METADATA_JAR_NAME)
|
||||||
|
val allMetadataArtifact = project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, allMetadataJar) { it.classifier = "all" }
|
||||||
|
|
||||||
|
DefaultKotlinUsageContext(
|
||||||
|
compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME),
|
||||||
|
javaApiUsage,
|
||||||
|
apiElementsConfigurationName,
|
||||||
|
overrideConfigurationArtifacts = setOf(allMetadataArtifact)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that consumers who expect Kotlin 1.2.x metadata package can still get one: publish the old metadata artifact as well:
|
||||||
|
usageContexts += run {
|
||||||
|
project.configurations.create(COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME).apply {
|
||||||
|
isCanBeConsumed = false
|
||||||
|
isCanBeResolved = false
|
||||||
|
usesPlatformOf(this@KotlinMetadataTarget)
|
||||||
|
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(this@KotlinMetadataTarget)) // 'kotlin-api' usage
|
||||||
|
|
||||||
|
val commonMainApiConfiguration = project.sourceSetDependencyConfigurationByScope(
|
||||||
|
project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME),
|
||||||
|
KotlinDependencyScope.API_SCOPE
|
||||||
|
)
|
||||||
|
extendsFrom(commonMainApiConfiguration)
|
||||||
|
|
||||||
|
project.artifacts.add(name, project.tasks.getByName(artifactsTaskName))
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultKotlinUsageContext(
|
||||||
|
compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME),
|
||||||
|
javaApiUsage,
|
||||||
|
COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val component =
|
||||||
|
createKotlinVariant(targetName, compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME), usageContexts)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
-20
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
|
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
|
||||||
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
|
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
||||||
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
|
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
|
||||||
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
|
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
|
||||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||||
@@ -98,12 +99,12 @@ class KotlinMultiplatformPlugin(
|
|||||||
private fun setupCompilerPluginOptions(project: Project) {
|
private fun setupCompilerPluginOptions(project: Project) {
|
||||||
// common source sets use the compiler options from the metadata compilation:
|
// common source sets use the compiler options from the metadata compilation:
|
||||||
val metadataCompilation =
|
val metadataCompilation =
|
||||||
project.multiplatformExtension.targets
|
project.multiplatformExtension.metadata().compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||||
.getByName(METADATA_TARGET_NAME)
|
|
||||||
.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
|
||||||
|
|
||||||
val primaryCompilationsBySourceSet by lazy { // don't evaluate eagerly: Android targets are not created at this point
|
val primaryCompilationsBySourceSet by lazy { // don't evaluate eagerly: Android targets are not created at this point
|
||||||
val allCompilationsForSourceSets = compilationsBySourceSet(project)
|
val allCompilationsForSourceSets = CompilationSourceSetUtil.compilationsBySourceSets(project).mapValues { (_, compilations) ->
|
||||||
|
compilations.filter { it.target.platformType != KotlinPlatformType.common }
|
||||||
|
}
|
||||||
|
|
||||||
allCompilationsForSourceSets.mapValues { (_, compilations) -> // choose one primary compilation
|
allCompilationsForSourceSets.mapValues { (_, compilations) -> // choose one primary compilation
|
||||||
when (compilations.size) {
|
when (compilations.size) {
|
||||||
@@ -175,8 +176,9 @@ class KotlinMultiplatformPlugin(
|
|||||||
targets
|
targets
|
||||||
.withType(AbstractKotlinTarget::class.java).matching { it.publishable && it.name != METADATA_TARGET_NAME }
|
.withType(AbstractKotlinTarget::class.java).matching { it.publishable && it.name != METADATA_TARGET_NAME }
|
||||||
.all {
|
.all {
|
||||||
if (it is KotlinAndroidTarget)
|
if (it is KotlinAndroidTarget || it is KotlinMetadataTarget)
|
||||||
// Android targets have their variants created in afterEvaluate; TODO handle this better?
|
// 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) }
|
project.whenEvaluated { it.createMavenPublications(publishing.publications) }
|
||||||
else
|
else
|
||||||
it.createMavenPublications(publishing.publications)
|
it.createMavenPublications(publishing.publications)
|
||||||
@@ -204,7 +206,9 @@ class KotlinMultiplatformPlugin(
|
|||||||
|
|
||||||
pom.withXml { xml ->
|
pom.withXml { xml ->
|
||||||
if (PropertiesProvider(project).keepMppDependenciesIntactInPoms != true)
|
if (PropertiesProvider(project).keepMppDependenciesIntactInPoms != true)
|
||||||
project.rewritePomMppDependenciesToActualTargetModules(xml, kotlinComponent)
|
project.rewritePomMppDependenciesToActualTargetModules(xml, kotlinComponent) { id ->
|
||||||
|
filterMetadataDependencies(this@createMavenPublications, id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +217,25 @@ class KotlinMultiplatformPlugin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 filterMetadataDependencies(target: AbstractKotlinTarget, groupNameVersion: Triple<String?, String, String?>): Boolean {
|
||||||
|
if (target !is KotlinMetadataTarget || !target.project.isKotlinGranularMetadataEnabled) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val (group, name, _) = groupNameVersion
|
||||||
|
|
||||||
|
val project = target.project
|
||||||
|
val metadataApiLegacyElements = project.configurations.getByName(COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME)
|
||||||
|
|
||||||
|
return metadataApiLegacyElements.allDependencies.any { it.group == group && it.name == name }
|
||||||
|
}
|
||||||
|
|
||||||
private fun configureSourceSets(project: Project) = with(project.multiplatformExtension) {
|
private fun configureSourceSets(project: Project) = with(project.multiplatformExtension) {
|
||||||
val production = sourceSets.create(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
|
val production = sourceSets.create(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
|
||||||
val test = sourceSets.create(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME)
|
val test = sourceSets.create(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME)
|
||||||
@@ -286,8 +309,15 @@ internal fun applyUserDefinedAttributes(target: AbstractKotlinTarget) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: String?, artifactNameAppendix: String): Jar {
|
internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: String?, artifactNameAppendix: String): Jar =
|
||||||
val project = compilation.target.project
|
sourcesJarTask(compilation.target.project, lazy { compilation.allKotlinSourceSets }, componentName, artifactNameAppendix)
|
||||||
|
|
||||||
|
internal fun sourcesJarTask(
|
||||||
|
project: Project,
|
||||||
|
sourceSets: Lazy<Set<KotlinSourceSet>>,
|
||||||
|
componentName: String?,
|
||||||
|
artifactNameAppendix: String
|
||||||
|
): Jar {
|
||||||
val taskName = lowerCamelCaseName(componentName, "sourcesJar")
|
val taskName = lowerCamelCaseName(componentName, "sourcesJar")
|
||||||
|
|
||||||
(project.tasks.findByName(taskName) as? Jar)?.let { return it }
|
(project.tasks.findByName(taskName) as? Jar)?.let { return it }
|
||||||
@@ -298,7 +328,7 @@ internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: St
|
|||||||
}
|
}
|
||||||
|
|
||||||
project.whenEvaluated {
|
project.whenEvaluated {
|
||||||
compilation.allKotlinSourceSets.forEach { sourceSet ->
|
sourceSets.value.forEach { sourceSet ->
|
||||||
result.from(sourceSet.kotlin) { copySpec ->
|
result.from(sourceSet.kotlin) { copySpec ->
|
||||||
copySpec.into(sourceSet.name)
|
copySpec.into(sourceSet.name)
|
||||||
}
|
}
|
||||||
@@ -307,14 +337,3 @@ internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: St
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun compilationsBySourceSet(project: Project): Map<KotlinSourceSet, Set<KotlinCompilation<*>>> =
|
|
||||||
HashMap<KotlinSourceSet, MutableSet<KotlinCompilation<*>>>().also { result ->
|
|
||||||
for (target in project.multiplatformExtension.targets) {
|
|
||||||
for (compilation in target.compilations) {
|
|
||||||
for (sourceSet in compilation.allKotlinSourceSets) {
|
|
||||||
result.getOrPut(sourceSet) { mutableSetOf() }.add(compilation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+130
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.tasks.Input
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations
|
||||||
|
import org.w3c.dom.Document
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import org.w3c.dom.Node
|
||||||
|
import org.w3c.dom.NodeList
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
|
||||||
|
data class KotlinProjectStructureMetadata(
|
||||||
|
@Input
|
||||||
|
val sourceSetNamesByVariantName: Map<String, Set<String>>,
|
||||||
|
|
||||||
|
@Input
|
||||||
|
val sourceSetsDependsOnRelation: Map<String, Set<String>>,
|
||||||
|
|
||||||
|
@Input
|
||||||
|
val sourceSetModuleDependencies: Map<String, Set<Pair<String, String>>>
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjectStructureMetadata? {
|
||||||
|
val sourceSetsWithMetadataCompilations =
|
||||||
|
project.multiplatformExtensionOrNull?.targets?.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME)?.compilations?.associate {
|
||||||
|
it.defaultSourceSet to it
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
val publishedVariantsNamesWithCompilation = getPublishedPlatformCompilations(project).mapKeys { it.key.name }
|
||||||
|
|
||||||
|
return KotlinProjectStructureMetadata(
|
||||||
|
sourceSetNamesByVariantName = publishedVariantsNamesWithCompilation.mapValues { (_, compilation) ->
|
||||||
|
compilation.allKotlinSourceSets.filter { it in sourceSetsWithMetadataCompilations }.map { it.name }.toSet()
|
||||||
|
},
|
||||||
|
sourceSetsDependsOnRelation = sourceSetsWithMetadataCompilations.keys.associate { sourceSet ->
|
||||||
|
sourceSet.name to sourceSet.dependsOn.filter { it in sourceSetsWithMetadataCompilations }.map { it.name }.toSet()
|
||||||
|
},
|
||||||
|
sourceSetModuleDependencies = sourceSetsWithMetadataCompilations.keys.associate { sourceSet ->
|
||||||
|
sourceSet.name to project.configurations.getByName(sourceSet.apiConfigurationName).allDependencies.map {
|
||||||
|
it.group.orEmpty() to it.name
|
||||||
|
}.toSet()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KotlinProjectStructureMetadata.toXmlDocument(): Document {
|
||||||
|
val document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().apply {
|
||||||
|
fun Node.node(name: String, action: Element.() -> Unit) = appendChild(createElement(name).apply(action))
|
||||||
|
fun Node.textNode(name: String, value: String) =
|
||||||
|
appendChild(createElement(name).apply { appendChild(createTextNode(value)) })
|
||||||
|
|
||||||
|
node("projectStructure") {
|
||||||
|
node("variants") {
|
||||||
|
sourceSetNamesByVariantName.forEach { (variantName, sourceSets) ->
|
||||||
|
node("variant") {
|
||||||
|
textNode("name", variantName)
|
||||||
|
sourceSets.forEach { sourceSetName -> textNode("sourceSet", sourceSetName) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node("sourceSets") {
|
||||||
|
val keys = sourceSetsDependsOnRelation.keys + sourceSetModuleDependencies.keys
|
||||||
|
for (sourceSet in keys) {
|
||||||
|
node("sourceSet") {
|
||||||
|
textNode("name", sourceSet)
|
||||||
|
sourceSetsDependsOnRelation[sourceSet].orEmpty().forEach { dependsOn ->
|
||||||
|
textNode("dependsOn", dependsOn)
|
||||||
|
}
|
||||||
|
sourceSetModuleDependencies[sourceSet].orEmpty().forEach { moduleDependency ->
|
||||||
|
textNode("moduleDependency", moduleDependency.first + ":" + moduleDependency.second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return document
|
||||||
|
}
|
||||||
|
|
||||||
|
private val NodeList.elements: Iterable<Element> get() = (0 until length).map { this@elements.item(it) }.filterIsInstance<Element>()
|
||||||
|
|
||||||
|
internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProjectStructureMetadata? {
|
||||||
|
val projectStructureNode = document.getElementsByTagName("projectStructure").elements.single()
|
||||||
|
|
||||||
|
val variantsNode = projectStructureNode.getElementsByTagName("variants").item(0) ?: return null
|
||||||
|
|
||||||
|
val sourceSetsByVariant = mutableMapOf<String, Set<String>>()
|
||||||
|
|
||||||
|
variantsNode.childNodes.elements.filter { it.tagName == "variant" }.forEach { variantNode ->
|
||||||
|
val variantName = variantNode.getElementsByTagName("name").elements.single().textContent
|
||||||
|
val sourceSets = variantNode.childNodes.elements.filter { it.tagName == "sourceSet" }.mapTo(mutableSetOf()) { it.textContent }
|
||||||
|
|
||||||
|
sourceSetsByVariant[variantName] = sourceSets
|
||||||
|
}
|
||||||
|
|
||||||
|
val sourceSetDependsOnRelation = mutableMapOf<String, Set<String>>()
|
||||||
|
val sourceSetModuleDependencies = mutableMapOf<String, Set<Pair<String, String>>>()
|
||||||
|
|
||||||
|
val sourceSetsNode = projectStructureNode.getElementsByTagName("sourceSets").item(0) ?: return null
|
||||||
|
|
||||||
|
sourceSetsNode.childNodes.elements.filter { it.tagName == "sourceSet" }.forEach { sourceSetNode ->
|
||||||
|
val sourceSetName = sourceSetNode.getElementsByTagName("name").elements.single().textContent
|
||||||
|
|
||||||
|
val dependsOn = mutableSetOf<String>()
|
||||||
|
val moduleDependencies = mutableSetOf<Pair<String, String>>()
|
||||||
|
|
||||||
|
sourceSetNode.childNodes.elements.forEach {
|
||||||
|
when (it.tagName) {
|
||||||
|
"dependsOn" -> dependsOn.add(it.textContent)
|
||||||
|
"moduleDependency" -> moduleDependencies.add(it.textContent.split(":").let { (first, second) -> first to second })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSetDependsOnRelation[sourceSetName] = dependsOn
|
||||||
|
sourceSetModuleDependencies[sourceSetName] = moduleDependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
return KotlinProjectStructureMetadata(
|
||||||
|
sourceSetsByVariant,
|
||||||
|
sourceSetDependsOnRelation,
|
||||||
|
sourceSetModuleDependencies
|
||||||
|
)
|
||||||
|
}
|
||||||
+3
-2
@@ -61,7 +61,8 @@ class DefaultKotlinUsageContext(
|
|||||||
override val compilation: KotlinCompilation<*>,
|
override val compilation: KotlinCompilation<*>,
|
||||||
private val usage: Usage,
|
private val usage: Usage,
|
||||||
override val dependencyConfigurationName: String,
|
override val dependencyConfigurationName: String,
|
||||||
private val overrideConfigurationArtifacts: Set<PublishArtifact>? = null
|
private val overrideConfigurationArtifacts: Set<PublishArtifact>? = null,
|
||||||
|
private val filterConfigurationAttributes: (Attribute<*>) -> Boolean = { true }
|
||||||
) : KotlinUsageContext {
|
) : KotlinUsageContext {
|
||||||
|
|
||||||
private val kotlinTarget: KotlinTarget get() = compilation.target
|
private val kotlinTarget: KotlinTarget get() = compilation.target
|
||||||
@@ -106,7 +107,7 @@ class DefaultKotlinUsageContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
configurationAttributes.keySet()
|
configurationAttributes.keySet()
|
||||||
.filter { it != ProjectLocalConfigurations.ATTRIBUTE }
|
.filter { filterConfigurationAttributes(it) && it != ProjectLocalConfigurations.ATTRIBUTE }
|
||||||
.forEach { copyAttribute(it, configurationAttributes, result) }
|
.forEach { copyAttribute(it, configurationAttributes, result) }
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
+38
-2
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.attributes.*
|
import org.gradle.api.attributes.*
|
||||||
import org.gradle.api.attributes.Usage.*
|
import org.gradle.api.attributes.Usage.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
@@ -12,11 +13,14 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.androidJvm
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||||
import org.jetbrains.kotlin.gradle.plugin.usageByName
|
import org.jetbrains.kotlin.gradle.plugin.usageByName
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
||||||
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
||||||
|
|
||||||
object KotlinUsages {
|
object KotlinUsages {
|
||||||
const val KOTLIN_API = "kotlin-api"
|
const val KOTLIN_API = "kotlin-api"
|
||||||
const val KOTLIN_RUNTIME = "kotlin-runtime"
|
const val KOTLIN_RUNTIME = "kotlin-runtime"
|
||||||
|
const val KOTLIN_METADATA = "kotlin-metadata"
|
||||||
|
|
||||||
val values = setOf(KOTLIN_API, KOTLIN_RUNTIME)
|
val values = setOf(KOTLIN_API, KOTLIN_RUNTIME)
|
||||||
|
|
||||||
private val jvmPlatformTypes: Set<KotlinPlatformType> = setOf(jvm, androidJvm)
|
private val jvmPlatformTypes: Set<KotlinPlatformType> = setOf(jvm, androidJvm)
|
||||||
@@ -63,6 +67,33 @@ object KotlinUsages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val javaUsagesForKotlinMetadataConsumers = listOf("java-api-jars", JAVA_API, JAVA_RUNTIME_JARS, JAVA_RUNTIME)
|
||||||
|
|
||||||
|
private class KotlinMetadataCompatibility : AttributeCompatibilityRule<Usage> {
|
||||||
|
override fun execute(details: CompatibilityCheckDetails<Usage>) = with(details) {
|
||||||
|
// ensure that a consumer that requests 'kotlin-metadata' can also consumer 'kotlin-api' artifacts or the
|
||||||
|
// 'java-*' ones (these are how Gradle represents a module that is published with no Gradle module metadata)
|
||||||
|
if (
|
||||||
|
consumerValue?.name == KOTLIN_METADATA &&
|
||||||
|
(producerValue?.name == KOTLIN_API || producerValue?.name in javaUsagesForKotlinMetadataConsumers)
|
||||||
|
) {
|
||||||
|
compatible()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class KotlinMetadataDisambiguation : AttributeDisambiguationRule<Usage> {
|
||||||
|
override fun execute(details: MultipleCandidatesDetails<Usage>) = details.run {
|
||||||
|
if (consumerValue?.name == KOTLIN_METADATA) {
|
||||||
|
// Prefer Kotlin metadata, but if there's no such variant then accept 'kotlin-api' or the Java usages
|
||||||
|
// (see the compatibility rule):
|
||||||
|
val acceptedProducerValues = listOf(KOTLIN_METADATA, KOTLIN_API, *javaUsagesForKotlinMetadataConsumers.toTypedArray())
|
||||||
|
val candidatesMap = candidateValues.associateBy { it.name }
|
||||||
|
acceptedProducerValues.firstOrNull { it in candidatesMap }?.let { closestMatch(candidatesMap.getValue(it)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class KotlinUsagesDisambiguation : AttributeDisambiguationRule<Usage> {
|
private class KotlinUsagesDisambiguation : AttributeDisambiguationRule<Usage> {
|
||||||
override fun execute(details: MultipleCandidatesDetails<Usage?>) = with(details) {
|
override fun execute(details: MultipleCandidatesDetails<Usage?>) = with(details) {
|
||||||
val candidateNames = candidateValues.map { it?.name }.toSet()
|
val candidateNames = candidateValues.map { it?.name }.toSet()
|
||||||
@@ -96,10 +127,15 @@ object KotlinUsages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun setupAttributesMatchingStrategy(attributesSchema: AttributesSchema) {
|
internal fun setupAttributesMatchingStrategy(project: Project, attributesSchema: AttributesSchema) {
|
||||||
attributesSchema.attribute(Usage.USAGE_ATTRIBUTE) { strategy ->
|
attributesSchema.attribute(USAGE_ATTRIBUTE) { strategy ->
|
||||||
strategy.compatibilityRules.add(KotlinJavaRuntimeJarsCompatibility::class.java)
|
strategy.compatibilityRules.add(KotlinJavaRuntimeJarsCompatibility::class.java)
|
||||||
strategy.disambiguationRules.add(KotlinUsagesDisambiguation::class.java)
|
strategy.disambiguationRules.add(KotlinUsagesDisambiguation::class.java)
|
||||||
|
|
||||||
|
if (project.isKotlinGranularMetadataEnabled) {
|
||||||
|
strategy.compatibilityRules.add(KotlinMetadataCompatibility::class.java)
|
||||||
|
strategy.disambiguationRules.add(KotlinMetadataDisambiguation::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.artifacts.Configuration
|
||||||
|
import org.gradle.api.artifacts.ResolvedDependency
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations
|
||||||
|
|
||||||
|
internal data class DependencySourceSetVisibilityResult(
|
||||||
|
val sourceSetsVisibleByThisSourceSet: Set<String>,
|
||||||
|
val sourceSetsVisibleThroughDependsOn: Set<String>
|
||||||
|
)
|
||||||
|
|
||||||
|
internal class SourceSetVisibilityProvider(
|
||||||
|
private val project: Project
|
||||||
|
) {
|
||||||
|
fun getVisibleSourceSets(
|
||||||
|
visibleFrom: KotlinSourceSet,
|
||||||
|
dependencyScopes: Iterable<KotlinDependencyScope>,
|
||||||
|
mppDependency: ResolvedDependency,
|
||||||
|
dependencyProjectStructureMetadata: KotlinProjectStructureMetadata,
|
||||||
|
otherProject: Project?
|
||||||
|
): DependencySourceSetVisibilityResult {
|
||||||
|
val visibleByThisSourceSet =
|
||||||
|
getVisibleSourceSetsImpl(visibleFrom, dependencyScopes, mppDependency, dependencyProjectStructureMetadata, otherProject)
|
||||||
|
|
||||||
|
val visibleByParents = visibleFrom.dependsOn
|
||||||
|
.flatMapTo(mutableSetOf()) {
|
||||||
|
getVisibleSourceSetsImpl(it, dependencyScopes, mppDependency, dependencyProjectStructureMetadata, otherProject)
|
||||||
|
}
|
||||||
|
|
||||||
|
return DependencySourceSetVisibilityResult(visibleByThisSourceSet, visibleByParents)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
private fun getVisibleSourceSetsImpl(
|
||||||
|
visibleFrom: KotlinSourceSet,
|
||||||
|
dependencyScopes: Iterable<KotlinDependencyScope>,
|
||||||
|
mppDependency: ResolvedDependency,
|
||||||
|
dependencyProjectMetadata: KotlinProjectStructureMetadata,
|
||||||
|
otherProject: Project?
|
||||||
|
): Set<String> {
|
||||||
|
val compilations = CompilationSourceSetUtil.compilationsBySourceSets(project).getValue(visibleFrom)
|
||||||
|
|
||||||
|
var visiblePlatformVariantNames: Set<String> =
|
||||||
|
compilations
|
||||||
|
.filter { it.target.platformType != KotlinPlatformType.common }
|
||||||
|
.flatMapTo(mutableSetOf()) { compilation ->
|
||||||
|
val configurations = dependencyScopes.mapNotNullTo(mutableSetOf()) { scope ->
|
||||||
|
project.resolvableConfigurationFromCompilationByScope(compilation, scope)
|
||||||
|
}
|
||||||
|
configurations.mapNotNull { configuration ->
|
||||||
|
// Resolve the configuration but don't trigger artifacts download, only download component metadata:
|
||||||
|
configuration.incoming.resolutionResult.allComponents
|
||||||
|
.find {
|
||||||
|
it.moduleVersion?.group == mppDependency.moduleGroup && it.moduleVersion?.name == mppDependency.moduleName
|
||||||
|
}
|
||||||
|
?.variant?.displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visiblePlatformVariantNames.isEmpty()) {
|
||||||
|
return emptySet()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherProject != null) {
|
||||||
|
val publishedVariants = getPublishedPlatformCompilations(otherProject).keys
|
||||||
|
|
||||||
|
visiblePlatformVariantNames = visiblePlatformVariantNames.mapTo(mutableSetOf()) { configurationName ->
|
||||||
|
publishedVariants.first { it.dependencyConfigurationName == configurationName }.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencyProjectMetadata.sourceSetNamesByVariantName
|
||||||
|
.filterKeys { it in visiblePlatformVariantNames }
|
||||||
|
.values.let { if (it.isEmpty()) emptySet() else it.reduce { acc, item -> acc intersect item } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Project.resolvableConfigurationFromCompilationByScope(
|
||||||
|
compilation: KotlinCompilation<*>,
|
||||||
|
scope: KotlinDependencyScope
|
||||||
|
): Configuration? {
|
||||||
|
val configurationName = when (scope) {
|
||||||
|
KotlinDependencyScope.API_SCOPE, KotlinDependencyScope.IMPLEMENTATION_SCOPE, KotlinDependencyScope.COMPILE_ONLY_SCOPE -> compilation.compileDependencyConfigurationName
|
||||||
|
|
||||||
|
KotlinDependencyScope.RUNTIME_ONLY_SCOPE ->
|
||||||
|
(compilation as? KotlinCompilationToRunnableFiles<*>)?.runtimeDependencyConfigurationName
|
||||||
|
?: return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return project.configurations.getByName(configurationName)
|
||||||
|
}
|
||||||
|
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.DefaultTask
|
||||||
|
import org.gradle.api.file.FileCollection
|
||||||
|
import org.gradle.api.tasks.*
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.API_SCOPE
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.IMPLEMENTATION_SCOPE
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.ALL_COMPILE_METADATA_CONFIGURATION_NAME
|
||||||
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
open class TransformKotlinGranularMetadata
|
||||||
|
@Inject constructor(
|
||||||
|
@get:Internal
|
||||||
|
val kotlinSourceSet: KotlinSourceSet
|
||||||
|
) : DefaultTask() {
|
||||||
|
|
||||||
|
@get:OutputDirectory
|
||||||
|
val outputsDir: File = project.buildDir.resolve("kotlinSourceSetMetadata/${kotlinSourceSet.name}")
|
||||||
|
|
||||||
|
@Suppress("unused") // Gradle input
|
||||||
|
@get:InputFiles
|
||||||
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
internal val allSourceSetsMetadataConfiguration = project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME)
|
||||||
|
|
||||||
|
private val participatingSourceSets: Set<KotlinSourceSet>
|
||||||
|
get() = transformation.kotlinSourceSet.getSourceSetHierarchy().toMutableSet().apply {
|
||||||
|
if (any { it.name == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME })
|
||||||
|
add(project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("unused") // Gradle input
|
||||||
|
@get:Input
|
||||||
|
internal val inputSourceSetsAndCompilations: Map<String, Iterable<String>>
|
||||||
|
get() {
|
||||||
|
val sourceSets = participatingSourceSets
|
||||||
|
return CompilationSourceSetUtil.compilationsBySourceSets(project)
|
||||||
|
.filterKeys { it in sourceSets }
|
||||||
|
.entries.associate { (sourceSet, compilations) ->
|
||||||
|
sourceSet.name to compilations.map { it.name }.sorted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val participatingCompilations: Iterable<KotlinCompilation<*>>
|
||||||
|
get() {
|
||||||
|
val sourceSets = participatingSourceSets
|
||||||
|
return CompilationSourceSetUtil.compilationsBySourceSets(project).filterKeys { it in sourceSets }.values.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("unused") // Gradle input
|
||||||
|
@get:Input
|
||||||
|
internal val inputCompilationDependencies: Map<String, Set<List<String?>>>
|
||||||
|
get() = participatingCompilations.associate {
|
||||||
|
it.name to project.configurations.getByName(it.compileDependencyConfigurationName)
|
||||||
|
.allDependencies.map { listOf(it.group, it.name, it.version) }.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val transformation =
|
||||||
|
GranularMetadataTransformation(
|
||||||
|
project,
|
||||||
|
kotlinSourceSet,
|
||||||
|
listOf(API_SCOPE, IMPLEMENTATION_SCOPE),
|
||||||
|
listOf(project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME))
|
||||||
|
)
|
||||||
|
|
||||||
|
@get:Internal
|
||||||
|
internal val metadataDependencyResolutions: Iterable<MetadataDependencyResolution>
|
||||||
|
get() = transformation.metadataDependencyResolutions
|
||||||
|
|
||||||
|
@get:Internal
|
||||||
|
internal val filesByResolution: Map<out MetadataDependencyResolution, FileCollection>
|
||||||
|
get() = metadataDependencyResolutions.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
|
||||||
|
.associate { it to project.files(it.getMetadataFilesBySourceSet(outputsDir, doProcessFiles = false).values) }
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun transformMetadata() {
|
||||||
|
if (outputsDir.isDirectory) {
|
||||||
|
outputsDir.deleteRecursively()
|
||||||
|
}
|
||||||
|
outputsDir.mkdirs()
|
||||||
|
|
||||||
|
metadataDependencyResolutions
|
||||||
|
.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
|
||||||
|
.forEach { it.getMetadataFilesBySourceSet(outputsDir, doProcessFiles = true) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -37,7 +37,7 @@ object UnusedSourceSetsChecker {
|
|||||||
fun checkSourceSets(project: Project) {
|
fun checkSourceSets(project: Project) {
|
||||||
// TODO once Android compilations are configured eagerly, move this to afterEvaluate { ... } instead of taskGraph.whenReady { ... }
|
// TODO once Android compilations are configured eagerly, move this to afterEvaluate { ... } instead of taskGraph.whenReady { ... }
|
||||||
project.gradle.taskGraph.whenReady { _ ->
|
project.gradle.taskGraph.whenReady { _ ->
|
||||||
val compilationsBySourceSet = compilationsBySourceSet(project)
|
val compilationsBySourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project)
|
||||||
val unusedSourceSets = project.kotlinExtension.sourceSets.filter {
|
val unusedSourceSets = project.kotlinExtension.sourceSets.filter {
|
||||||
compilationsBySourceSet[it]?.isEmpty() ?: true
|
compilationsBySourceSet[it]?.isEmpty() ?: true
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-35
@@ -10,10 +10,7 @@ import org.gradle.api.Project
|
|||||||
import org.gradle.api.attributes.AttributeContainer
|
import org.gradle.api.attributes.AttributeContainer
|
||||||
import org.gradle.api.file.FileCollection
|
import org.gradle.api.file.FileCollection
|
||||||
import org.gradle.util.ConfigureUtil
|
import org.gradle.util.ConfigureUtil
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
import org.jetbrains.kotlin.gradle.dsl.*
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
|
import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
|
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
|
||||||
@@ -77,13 +74,13 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
|
|||||||
Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$name") })
|
Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$name") })
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
|
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
|
||||||
fun AbstractKotlinCompile<*>.configureAction() {
|
fun AbstractKotlinCompile<*>.configureAction() {
|
||||||
source(sourceSet.kotlin)
|
source(sourceSet.kotlin)
|
||||||
sourceFilesExtensions(sourceSet.customSourceFilesExtensions)
|
sourceFilesExtensions(sourceSet.customSourceFilesExtensions)
|
||||||
if (addAsCommonSources) {
|
commonSourceSet += project.files(Callable {
|
||||||
commonSourceSet += sourceSet.kotlin
|
if (addAsCommonSources.value) sourceSet.kotlin else emptyList<Any>()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note! Invocation of withType-all results in preliminary task instantiation.
|
// Note! Invocation of withType-all results in preliminary task instantiation.
|
||||||
@@ -103,42 +100,50 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun source(sourceSet: KotlinSourceSet) {
|
internal fun addExactSourceSetsEagerly(sourceSets: Set<KotlinSourceSet>) {
|
||||||
if (kotlinSourceSets.add(sourceSet)) {
|
with(target.project) {
|
||||||
//TODO possibly issue with forced instantiation
|
//TODO possibly issue with forced instantiation
|
||||||
target.project.whenEvaluated {
|
sourceSets.forEach { sourceSet ->
|
||||||
sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
|
addSourcesToCompileTask(
|
||||||
val isCommonSource =
|
sourceSet,
|
||||||
CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet.name) ?: false
|
addAsCommonSources = lazy {
|
||||||
|
CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project).contains(sourceSet.name)
|
||||||
addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource)
|
|
||||||
|
|
||||||
// Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
|
|
||||||
// old Java & Android projects:
|
|
||||||
addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
|
|
||||||
addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
|
|
||||||
addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
|
|
||||||
|
|
||||||
if (this@AbstractKotlinCompilation is KotlinCompilationToRunnableFiles<*>) {
|
|
||||||
addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if (sourceSet.name != defaultSourceSetName) {
|
// Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
|
||||||
kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
|
// old Java & Android projects:
|
||||||
// Temporary solution for checking consistency across source sets participating in a compilation that may
|
addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
|
||||||
// not be interconnected with the dependsOn relation: check the settings as if the default source set of
|
addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
|
||||||
// the compilation depends on the one added to the compilation:
|
addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
|
||||||
defaultSourceSetLanguageSettingsChecker.runAllChecks(
|
|
||||||
defaultSourceSet,
|
if (this@AbstractKotlinCompilation is KotlinCompilationToRunnableFiles<*>) {
|
||||||
sourceSet
|
addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
if (sourceSet.name != defaultSourceSetName) {
|
||||||
|
kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
|
||||||
|
// Temporary solution for checking consistency across source sets participating in a compilation that may
|
||||||
|
// not be interconnected with the dependsOn relation: check the settings as if the default source set of
|
||||||
|
// the compilation depends on the one added to the compilation:
|
||||||
|
defaultSourceSetLanguageSettingsChecker.runAllChecks(
|
||||||
|
defaultSourceSet,
|
||||||
|
sourceSet
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final override fun source(sourceSet: KotlinSourceSet) {
|
||||||
|
if (kotlinSourceSets.add(sourceSet)) {
|
||||||
|
target.project.whenEvaluated {
|
||||||
|
addExactSourceSetsEagerly(sourceSet.getSourceSetHierarchy())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val compileDependencyConfigurationName: String
|
override val compileDependencyConfigurationName: String
|
||||||
get() = lowerCamelCaseName(
|
get() = lowerCamelCaseName(
|
||||||
target.disambiguationClassifier,
|
target.disambiguationClassifier,
|
||||||
|
|||||||
+3
-2
@@ -118,12 +118,13 @@ abstract class AbstractKotlinTarget(
|
|||||||
configuration.dependencyConstraints.addAll(kotlinUsageContext.dependencyConstraints)
|
configuration.dependencyConstraints.addAll(kotlinUsageContext.dependencyConstraints)
|
||||||
configuration.artifacts.addAll(kotlinUsageContext.artifacts)
|
configuration.artifacts.addAll(kotlinUsageContext.artifacts)
|
||||||
|
|
||||||
kotlinUsageContext.attributes.keySet().forEach {
|
val attributes = kotlinUsageContext.attributes
|
||||||
|
attributes.keySet().forEach {
|
||||||
// capture type parameter T
|
// capture type parameter T
|
||||||
fun <T> copyAttribute(key: Attribute<T>, from: AttributeContainer, to: AttributeContainer) {
|
fun <T> copyAttribute(key: Attribute<T>, from: AttributeContainer, to: AttributeContainer) {
|
||||||
to.attribute(key, from.getAttribute(key)!!)
|
to.attribute(key, from.getAttribute(key)!!)
|
||||||
}
|
}
|
||||||
copyAttribute(it, kotlinUsageContext.attributes, configuration.attributes)
|
copyAttribute(it, attributes, configuration.attributes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -64,7 +64,7 @@ open class KotlinVariant(
|
|||||||
final override val target: KotlinTarget
|
final override val target: KotlinTarget
|
||||||
get() = producingCompilation.target
|
get() = producingCompilation.target
|
||||||
|
|
||||||
override fun getUsages(): Set<UsageContext> = usages
|
override fun getUsages(): Set<KotlinUsageContext> = usages
|
||||||
|
|
||||||
override fun getName(): String = componentName ?: producingCompilation.target.targetName
|
override fun getName(): String = componentName ?: producingCompilation.target.targetName
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ class KotlinVariantWithMetadataDependency(
|
|||||||
val originalUsages: Set<DefaultKotlinUsageContext>,
|
val originalUsages: Set<DefaultKotlinUsageContext>,
|
||||||
private val metadataTarget: AbstractKotlinTarget
|
private val metadataTarget: AbstractKotlinTarget
|
||||||
) : KotlinVariantWithCoordinates(producingCompilation, originalUsages) {
|
) : KotlinVariantWithCoordinates(producingCompilation, originalUsages) {
|
||||||
override fun getUsages(): Set<UsageContext> = originalUsages.mapTo(mutableSetOf()) { usageContext ->
|
override fun getUsages(): Set<KotlinUsageContext> = originalUsages.mapTo(mutableSetOf()) { usageContext ->
|
||||||
KotlinUsageContextWithAdditionalDependencies(usageContext, setOf(metadataDependency()))
|
KotlinUsageContextWithAdditionalDependencies(usageContext, setOf(metadataDependency()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ class JointAndroidKotlinTargetComponent(
|
|||||||
override val sourcesArtifacts: Set<PublishArtifact>
|
override val sourcesArtifacts: Set<PublishArtifact>
|
||||||
) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal {
|
) : KotlinTargetComponentWithCoordinatesAndPublication, SoftwareComponentInternal {
|
||||||
|
|
||||||
override fun getUsages(): Set<UsageContext> = nestedVariants.flatMap { it.usages }.toSet()
|
override fun getUsages(): Set<KotlinUsageContext> = nestedVariants.flatMap { it.usages }.toSet()
|
||||||
|
|
||||||
override fun getName(): String = lowerCamelCaseName(target.targetName, *flavorNames.toTypedArray())
|
override fun getName(): String = lowerCamelCaseName(target.targetName, *flavorNames.toTypedArray())
|
||||||
|
|
||||||
|
|||||||
+14
-5
@@ -20,15 +20,15 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinTargetComponent
|
|||||||
|
|
||||||
internal fun Project.rewritePomMppDependenciesToActualTargetModules(
|
internal fun Project.rewritePomMppDependenciesToActualTargetModules(
|
||||||
pomXml: XmlProvider,
|
pomXml: XmlProvider,
|
||||||
component: KotlinTargetComponent
|
component: KotlinTargetComponent,
|
||||||
|
filterDependencies: (groupNameVersion: Triple<String?, String, String?>) -> Boolean = { true }
|
||||||
) {
|
) {
|
||||||
if (component !is SoftwareComponentInternal)
|
if (component !is SoftwareComponentInternal)
|
||||||
return
|
return
|
||||||
|
|
||||||
val dependenciesNodeList = pomXml.asNode().get("dependencies") as NodeList
|
val dependenciesNode = (pomXml.asNode().get("dependencies") as NodeList).filterIsInstance<Node>().singleOrNull() ?: return
|
||||||
val dependencyNodes = dependenciesNodeList.filterIsInstance<Node>().flatMap {
|
|
||||||
(it.get("dependency") as? NodeList).orEmpty()
|
val dependencyNodes = (dependenciesNode.get("dependency") as? NodeList).orEmpty().filterIsInstance<Node>()
|
||||||
}.filterIsInstance<Node>()
|
|
||||||
|
|
||||||
val dependencyByNode = mutableMapOf<Node, ModuleDependency>()
|
val dependencyByNode = mutableMapOf<Node, ModuleDependency>()
|
||||||
|
|
||||||
@@ -57,6 +57,15 @@ internal fun Project.rewritePomMppDependenciesToActualTargetModules(
|
|||||||
// Rewrite the dependency nodes according to the mapping:
|
// Rewrite the dependency nodes according to the mapping:
|
||||||
dependencyNodes.forEach { dependencyNode ->
|
dependencyNodes.forEach { dependencyNode ->
|
||||||
val moduleDependency = dependencyByNode[dependencyNode]
|
val moduleDependency = dependencyByNode[dependencyNode]
|
||||||
|
|
||||||
|
if (moduleDependency != null) {
|
||||||
|
val groupNameVersion = Triple(moduleDependency.group, moduleDependency.name, moduleDependency.version)
|
||||||
|
if (!filterDependencies(groupNameVersion)) {
|
||||||
|
dependenciesNode.remove(dependencyNode)
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val mapDependencyTo = resultDependenciesForEachUsageContext.find { moduleDependency in it }?.get(moduleDependency)
|
val mapDependencyTo = resultDependenciesForEachUsageContext.find { moduleDependency in it }?.get(moduleDependency)
|
||||||
|
|
||||||
if (mapDependencyTo != null) {
|
if (mapDependencyTo != null) {
|
||||||
|
|||||||
+8
-1
@@ -17,8 +17,12 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
|
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinDependencyHandler
|
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinDependencyHandler
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.GranularMetadataTransformation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution
|
||||||
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
||||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||||
|
import java.io.File
|
||||||
import java.lang.reflect.Constructor
|
import java.lang.reflect.Constructor
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -112,9 +116,11 @@ class DefaultKotlinSourceSet(
|
|||||||
override fun addCustomSourceFilesExtensions(extensions: List<String>) {
|
override fun addCustomSourceFilesExtensions(extensions: List<String>) {
|
||||||
explicitlyAddedCustomSourceFilesExtensions.addAll(extensions)
|
explicitlyAddedCustomSourceFilesExtensions.addAll(extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val dependencyTransformations: MutableMap<KotlinDependencyScope, GranularMetadataTransformation> = mutableMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinSourceSet.checkForCircularDependencies(): Unit {
|
private fun KotlinSourceSet.checkForCircularDependencies() {
|
||||||
// If adding an edge creates a cycle, than the source node of the edge belongs to the cycle, so run DFS from that node
|
// If adding an edge creates a cycle, than the source node of the edge belongs to the cycle, so run DFS from that node
|
||||||
// to check whether it became reachable from itself
|
// to check whether it became reachable from itself
|
||||||
val visited = hashSetOf<KotlinSourceSet>()
|
val visited = hashSetOf<KotlinSourceSet>()
|
||||||
@@ -148,6 +154,7 @@ internal fun KotlinSourceSet.disambiguateName(simpleName: String): String {
|
|||||||
|
|
||||||
private fun createDefaultSourceDirectorySet(project: Project, name: String?, resolver: FileResolver?): SourceDirectorySet {
|
private fun createDefaultSourceDirectorySet(project: Project, name: String?, resolver: FileResolver?): SourceDirectorySet {
|
||||||
if (isGradleVersionAtLeast(5, 0)) {
|
if (isGradleVersionAtLeast(5, 0)) {
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
val objects = project.objects
|
val objects = project.objects
|
||||||
val sourceDirectorySetMethod = objects.javaClass.methods.single { it.name == "sourceDirectorySet" && it.parameterCount == 2 }
|
val sourceDirectorySetMethod = objects.javaClass.methods.single { it.name == "sourceDirectorySet" && it.parameterCount == 2 }
|
||||||
return sourceDirectorySetMethod(objects, name, name) as SourceDirectorySet
|
return sourceDirectorySetMethod(objects, name, name) as SourceDirectorySet
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.sources
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.Configuration
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.*
|
||||||
|
|
||||||
|
internal enum class KotlinDependencyScope(val scopeName: String) {
|
||||||
|
API_SCOPE("api"),
|
||||||
|
IMPLEMENTATION_SCOPE("implementation"),
|
||||||
|
COMPILE_ONLY_SCOPE("compileOnly"),
|
||||||
|
RUNTIME_ONLY_SCOPE("runtimeOnly")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Project.sourceSetDependencyConfigurationByScope(sourceSet: KotlinSourceSet, scope: KotlinDependencyScope): Configuration =
|
||||||
|
project.configurations.getByName(
|
||||||
|
when (scope) {
|
||||||
|
API_SCOPE -> sourceSet.apiConfigurationName
|
||||||
|
IMPLEMENTATION_SCOPE -> sourceSet.implementationConfigurationName
|
||||||
|
COMPILE_ONLY_SCOPE -> sourceSet.compileOnlyConfigurationName
|
||||||
|
RUNTIME_ONLY_SCOPE -> sourceSet.runtimeOnlyConfigurationName
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun Project.sourceSetMetadataConfigurationByScope(sourceSet: KotlinSourceSet, scope: KotlinDependencyScope): Configuration =
|
||||||
|
project.configurations.getByName(
|
||||||
|
when (scope) {
|
||||||
|
API_SCOPE -> sourceSet.apiMetadataConfigurationName
|
||||||
|
IMPLEMENTATION_SCOPE -> sourceSet.implementationMetadataConfigurationName
|
||||||
|
COMPILE_ONLY_SCOPE -> sourceSet.compileOnlyMetadataConfigurationName
|
||||||
|
RUNTIME_ONLY_SCOPE -> sourceSet.runtimeOnlyMetadataConfigurationName
|
||||||
|
}
|
||||||
|
)
|
||||||
+5
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
|
||||||
import org.jetbrains.kotlin.gradle.plugin.usageByName
|
import org.jetbrains.kotlin.gradle.plugin.usageByName
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal abstract class KotlinSourceSetFactory<T : KotlinSourceSet> internal constructor(
|
internal abstract class KotlinSourceSetFactory<T : KotlinSourceSet> internal constructor(
|
||||||
@@ -78,6 +79,10 @@ internal class DefaultKotlinSourceSetFactory(
|
|||||||
isVisible = false
|
isVisible = false
|
||||||
isCanBeConsumed = false
|
isCanBeConsumed = false
|
||||||
extendsFrom(project.configurations.maybeCreate(configurationName))
|
extendsFrom(project.configurations.maybeCreate(configurationName))
|
||||||
|
|
||||||
|
if (project.isKotlinGranularMetadataEnabled) {
|
||||||
|
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+329
-4
@@ -5,11 +5,31 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.metadata
|
package org.jetbrains.kotlin.gradle.targets.metadata
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCommonSourceSetProcessor
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetProcessor
|
import org.gradle.api.artifacts.Configuration
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetConfigurator
|
import org.gradle.api.attributes.Usage
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
|
import org.gradle.api.file.FileCollection
|
||||||
|
import org.gradle.api.internal.component.SoftwareComponentInternal
|
||||||
|
import org.gradle.api.plugins.BasePlugin
|
||||||
|
import org.gradle.api.tasks.bundling.Jar
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||||
|
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.mpp.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.*
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.Callable
|
||||||
|
|
||||||
|
internal const val ALL_COMPILE_METADATA_CONFIGURATION_NAME = "allSourceSetsCompileDependenciesMetadata"
|
||||||
|
internal const val ALL_RUNTIME_METADATA_CONFIGURATION_NAME = "allSourceSetsRuntimeDependenciesMetadata"
|
||||||
|
|
||||||
|
internal val Project.isKotlinGranularMetadataEnabled: Boolean
|
||||||
|
get() = PropertiesProvider(rootProject).enableGranularSourceSetsMetadata == true
|
||||||
|
|
||||||
class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
|
class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
|
||||||
KotlinTargetConfigurator<KotlinCommonCompilation>(
|
KotlinTargetConfigurator<KotlinCommonCompilation>(
|
||||||
@@ -18,8 +38,313 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
|
|||||||
kotlinPluginVersion = kotlinPluginVersion
|
kotlinPluginVersion = kotlinPluginVersion
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
internal const val ALL_METADATA_JAR_NAME = "allMetadataJar"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val KotlinOnlyTarget<KotlinCommonCompilation>.apiElementsConfiguration: Configuration
|
||||||
|
get() = project.configurations.getByName(apiElementsConfigurationName)
|
||||||
|
|
||||||
|
override fun configureTarget(target: KotlinOnlyTarget<KotlinCommonCompilation>) {
|
||||||
|
super.configureTarget(target)
|
||||||
|
|
||||||
|
if (target.project.isKotlinGranularMetadataEnabled) {
|
||||||
|
target as KotlinMetadataTarget
|
||||||
|
|
||||||
|
createMergedAllSourceSetsConfigurations(target)
|
||||||
|
|
||||||
|
val allMetadataJar = target.project.tasks.getByName(ALL_METADATA_JAR_NAME) as Jar
|
||||||
|
createMetadataCompilationsForCommonSourceSets(target, allMetadataJar)
|
||||||
|
|
||||||
|
setupDependencyTransformationForCommonSourceSets(target)
|
||||||
|
|
||||||
|
target.project.configurations.getByName(target.apiElementsConfigurationName).attributes
|
||||||
|
.attribute(Usage.USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupCompilationDependencyFiles(project: Project, compilation: KotlinCompilation<KotlinCommonOptions>) {
|
||||||
|
/** See [createTransformedMetadataClasspath] and its usage. */
|
||||||
|
if (project.isKotlinGranularMetadataEnabled)
|
||||||
|
compilation.compileDependencyFiles = project.files()
|
||||||
|
else
|
||||||
|
super.setupCompilationDependencyFiles(project, compilation)
|
||||||
|
}
|
||||||
|
|
||||||
override fun buildCompilationProcessor(compilation: KotlinCommonCompilation): KotlinSourceSetProcessor<*> {
|
override fun buildCompilationProcessor(compilation: KotlinCommonCompilation): KotlinSourceSetProcessor<*> {
|
||||||
val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
|
val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
|
||||||
return KotlinCommonSourceSetProcessor(compilation.target.project, compilation, tasksProvider, kotlinPluginVersion)
|
return KotlinCommonSourceSetProcessor(compilation.target.project, compilation, tasksProvider, kotlinPluginVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun createJarTasks(target: KotlinOnlyTarget<KotlinCommonCompilation>) {
|
||||||
|
super.createJarTasks(target)
|
||||||
|
|
||||||
|
if (target.project.isKotlinGranularMetadataEnabled) {
|
||||||
|
/** This JAR is created in addition to the main one, published with a classifier, but is by default used
|
||||||
|
* for project dependencies (as the Kotlin Granular metadata is enabled across all projects in a build, this is OK).
|
||||||
|
* See also [KotlinMetadataTarget.kotlinComponents]
|
||||||
|
*/
|
||||||
|
target.project.tasks.create(ALL_METADATA_JAR_NAME, Jar::class.java).apply {
|
||||||
|
description = "Assembles a jar archive containing the metadata for all Kotlin source sets."
|
||||||
|
group = BasePlugin.BUILD_GROUP
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
if (isGradleVersionAtLeast(5, 2)) {
|
||||||
|
archiveAppendix.convention(target.name.toLowerCase())
|
||||||
|
archiveClassifier.set("all")
|
||||||
|
} else {
|
||||||
|
appendix = target.name.toLowerCase()
|
||||||
|
classifier = "all"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun transformGranularMetadataTaskName(sourceSet: KotlinSourceSet) =
|
||||||
|
lowerCamelCaseName("transform", sourceSet.name, "DependenciesMetadata")
|
||||||
|
|
||||||
|
private fun setupDependencyTransformationForCommonSourceSets(target: KotlinMetadataTarget) {
|
||||||
|
target.project.kotlinExtension.sourceSets.all {
|
||||||
|
setupDependencyTransformationForSourceSet(target.project, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMetadataCompilationsForCommonSourceSets(
|
||||||
|
target: KotlinMetadataTarget,
|
||||||
|
allMetadataJar: Jar
|
||||||
|
) = target.project.whenEvaluated {
|
||||||
|
// Do this after all targets are configured by the user build script
|
||||||
|
|
||||||
|
val publishedCommonSourceSets: Set<KotlinSourceSet> = getPublishedCommonSourceSets(project)
|
||||||
|
|
||||||
|
val sourceSetsWithMetadataCompilations: Map<KotlinSourceSet, KotlinCommonCompilation> =
|
||||||
|
publishedCommonSourceSets.associate { sourceSet ->
|
||||||
|
sourceSet to configureMetadataCompilation(target, sourceSet, allMetadataJar)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSetsWithMetadataCompilations.forEach { (sourceSet, metadataCompilation) ->
|
||||||
|
val compileMetadataTransformationTasksForHierarchy = mutableSetOf<TransformKotlinGranularMetadata>()
|
||||||
|
|
||||||
|
// Adjust metadata compilation to support source set hierarchies, i.e. use both the outputs of dependsOn source set compilation
|
||||||
|
// and their dependencies metadata transformed for compilation:
|
||||||
|
sourceSet.getSourceSetHierarchy().forEach { hierarchySourceSet ->
|
||||||
|
if (hierarchySourceSet != sourceSet) {
|
||||||
|
val dependencyCompilation = sourceSetsWithMetadataCompilations.getValue(hierarchySourceSet as DefaultKotlinSourceSet)
|
||||||
|
metadataCompilation.compileDependencyFiles += dependencyCompilation.output.classesDirs.filter { it.exists() }
|
||||||
|
}
|
||||||
|
|
||||||
|
project.tasks.withType(TransformKotlinGranularMetadata::class.java)
|
||||||
|
.findByName(transformGranularMetadataTaskName(hierarchySourceSet))
|
||||||
|
?.let(compileMetadataTransformationTasksForHierarchy::add)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadataCompilation.compileDependencyFiles += createTransformedMetadataClasspath(
|
||||||
|
project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME),
|
||||||
|
project,
|
||||||
|
compileMetadataTransformationTasksForHierarchy
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val generateMetadata =
|
||||||
|
createGenerateProjectStructureMetadataTask()
|
||||||
|
|
||||||
|
allMetadataJar.from(project.files(Callable { generateMetadata.resultXmlFile }).builtBy(generateMetadata)) { spec ->
|
||||||
|
spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_FILE_NAME }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMergedAllSourceSetsConfigurations(target: KotlinMetadataTarget): Unit = with(target.project) {
|
||||||
|
listOf(ALL_COMPILE_METADATA_CONFIGURATION_NAME, ALL_RUNTIME_METADATA_CONFIGURATION_NAME).forEach { configurationName ->
|
||||||
|
project.configurations.create(configurationName).apply {
|
||||||
|
isCanBeConsumed = false
|
||||||
|
isCanBeResolved = true
|
||||||
|
|
||||||
|
usesPlatformOf(target)
|
||||||
|
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun configureMetadataCompilation(
|
||||||
|
target: KotlinMetadataTarget,
|
||||||
|
sourceSet: KotlinSourceSet,
|
||||||
|
allMetadataJar: Jar
|
||||||
|
): KotlinCommonCompilation {
|
||||||
|
val project = target.project
|
||||||
|
|
||||||
|
// With the metadata target, we publish all API dependencies of all the published source sets together:
|
||||||
|
target.apiElementsConfiguration.extendsFrom(project.configurations.getByName(sourceSet.apiConfigurationName))
|
||||||
|
|
||||||
|
val metadataCompilation = when (sourceSet.name) {
|
||||||
|
// Historically, we already had a 'main' compilation in metadata targets; TODO consider removing it instead
|
||||||
|
KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME -> target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||||
|
else -> target.compilations.create(lowerCamelCaseName(sourceSet.name)) { compilation ->
|
||||||
|
compilation.addExactSourceSetsEagerly(setOf(sourceSet))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.addExtendsFromRelation(metadataCompilation.compileDependencyConfigurationName, ALL_COMPILE_METADATA_CONFIGURATION_NAME)
|
||||||
|
|
||||||
|
allMetadataJar.from(metadataCompilation.output.allOutputs) { spec ->
|
||||||
|
spec.into(metadataCompilation.defaultSourceSet.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
project.tasks.create(
|
||||||
|
transformGranularMetadataTaskName(sourceSet),
|
||||||
|
TransformKotlinGranularMetadata::class.java,
|
||||||
|
sourceSet
|
||||||
|
)
|
||||||
|
|
||||||
|
return metadataCompilation
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupDependencyTransformationForSourceSet(
|
||||||
|
project: Project,
|
||||||
|
sourceSet: KotlinSourceSet
|
||||||
|
) {
|
||||||
|
KotlinDependencyScope.values().forEach { scope ->
|
||||||
|
val allMetadataConfigurations = mutableListOf<Configuration>().apply {
|
||||||
|
if (scope != KotlinDependencyScope.COMPILE_ONLY_SCOPE)
|
||||||
|
add(project.configurations.getByName(ALL_RUNTIME_METADATA_CONFIGURATION_NAME))
|
||||||
|
if (scope != KotlinDependencyScope.RUNTIME_ONLY_SCOPE)
|
||||||
|
add(project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME))
|
||||||
|
}
|
||||||
|
|
||||||
|
val granularMetadataTransformation = GranularMetadataTransformation(
|
||||||
|
project,
|
||||||
|
sourceSet,
|
||||||
|
listOf(scope),
|
||||||
|
allMetadataConfigurations
|
||||||
|
)
|
||||||
|
|
||||||
|
(sourceSet as DefaultKotlinSourceSet).dependencyTransformations[scope] = granularMetadataTransformation
|
||||||
|
|
||||||
|
val sourceSetMetadataConfigurationByScope = project.sourceSetMetadataConfigurationByScope(sourceSet, scope)
|
||||||
|
|
||||||
|
granularMetadataTransformation.applyToConfiguration(sourceSetMetadataConfigurationByScope)
|
||||||
|
|
||||||
|
val sourceSetDependencyConfigurationByScope = project.sourceSetDependencyConfigurationByScope(sourceSet, scope)
|
||||||
|
|
||||||
|
// All source set dependencies except for compileOnly take part and agree in versions with all other runtime dependencies:
|
||||||
|
if (scope != KotlinDependencyScope.COMPILE_ONLY_SCOPE) {
|
||||||
|
project.addExtendsFromRelation(
|
||||||
|
ALL_RUNTIME_METADATA_CONFIGURATION_NAME,
|
||||||
|
sourceSetDependencyConfigurationByScope.name
|
||||||
|
)
|
||||||
|
project.addExtendsFromRelation(
|
||||||
|
sourceSetMetadataConfigurationByScope.name,
|
||||||
|
ALL_RUNTIME_METADATA_CONFIGURATION_NAME
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// All source set dependencies except for runtimeOnly take part and agree in versions with all other compile dependencies:
|
||||||
|
if (scope != KotlinDependencyScope.RUNTIME_ONLY_SCOPE) {
|
||||||
|
project.addExtendsFromRelation(
|
||||||
|
ALL_COMPILE_METADATA_CONFIGURATION_NAME,
|
||||||
|
sourceSetDependencyConfigurationByScope.name
|
||||||
|
)
|
||||||
|
project.addExtendsFromRelation(
|
||||||
|
sourceSetMetadataConfigurationByScope.name,
|
||||||
|
ALL_COMPILE_METADATA_CONFIGURATION_NAME
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure that the [configuration] excludes the dependencies that are classified by this [GranularMetadataTransformation] as
|
||||||
|
* [MetadataDependencyResolution.ExcludeAsUnrequested], and uses exactly the same versions as were resolved for the requested
|
||||||
|
* dependencies during the transformation. */
|
||||||
|
private fun GranularMetadataTransformation.applyToConfiguration(configuration: Configuration) {
|
||||||
|
// Run this action immediately before the configuration first takes part in dependency resolution:
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
configuration.withDependencies {
|
||||||
|
val (unrequested, requested) = metadataDependencyResolutions
|
||||||
|
.partition { it is MetadataDependencyResolution.ExcludeAsUnrequested }
|
||||||
|
|
||||||
|
unrequested.forEach { configuration.exclude(mapOf("group" to it.dependency.moduleGroup, "module" to it.dependency.moduleName)) }
|
||||||
|
|
||||||
|
requested.forEach {
|
||||||
|
val notation = listOf(it.dependency.moduleGroup, it.dependency.moduleName, it.dependency.moduleVersion).joinToString(":")
|
||||||
|
configuration.resolutionStrategy.force(notation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTransformedMetadataClasspath(
|
||||||
|
fromFiles: Iterable<File>,
|
||||||
|
project: Project,
|
||||||
|
granularMetadataTransformationTasks: Set<TransformKotlinGranularMetadata>
|
||||||
|
): FileCollection {
|
||||||
|
return project.files(Callable {
|
||||||
|
val resolutionsByArtifactFile = granularMetadataTransformationTasks
|
||||||
|
.flatMap { it.metadataDependencyResolutions }
|
||||||
|
.groupBy { it.dependency }
|
||||||
|
.filterKeys { it.moduleArtifacts.size == 1 } // TODO do we have modules that resolve to more than one artifact? use sets?
|
||||||
|
.mapKeys { (dependency, _) -> dependency.moduleArtifacts.single().file }
|
||||||
|
|
||||||
|
val transformedFiles = granularMetadataTransformationTasks.flatMap { it.filesByResolution.toList() }.toMap()
|
||||||
|
|
||||||
|
mutableSetOf<Any /* File | FileCollection */>().apply {
|
||||||
|
fromFiles.forEach { file ->
|
||||||
|
val resolutions = resolutionsByArtifactFile[file]
|
||||||
|
if (resolutions == null) {
|
||||||
|
add(file)
|
||||||
|
} else {
|
||||||
|
val chooseVisibleSourceSets =
|
||||||
|
resolutions.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
|
||||||
|
|
||||||
|
if (chooseVisibleSourceSets.isNotEmpty()) {
|
||||||
|
add(chooseVisibleSourceSets.map { transformedFiles.getValue(it) })
|
||||||
|
} else if (resolutions.any { it is MetadataDependencyResolution.KeepOriginalDependency }) {
|
||||||
|
add(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).builtBy(granularMetadataTransformationTasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPublishedCommonSourceSets(project: Project): Set<KotlinSourceSet> {
|
||||||
|
val compilationsBySourceSet: Map<KotlinSourceSet, Set<KotlinCompilation<*>>> =
|
||||||
|
CompilationSourceSetUtil.compilationsBySourceSets(project)
|
||||||
|
|
||||||
|
// For now, we will only compile metadata from source sets used by multiple platforms
|
||||||
|
// TODO once the compiler is able to analyze common code with platform-specific features and dependencies, lift this restriction
|
||||||
|
val sourceSetsUsedInMultipleTargets = compilationsBySourceSet.filterValues { compilations ->
|
||||||
|
compilations.map { it.target.platformType }.distinct().size > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't want to publish source set metadata from source sets that don't participate in any compilation that is published,
|
||||||
|
// such as test or benchmark sources; find all published compilations:
|
||||||
|
val publishedCompilations = getPublishedPlatformCompilations(project).values
|
||||||
|
|
||||||
|
return sourceSetsUsedInMultipleTargets
|
||||||
|
.filterValues { compilations -> compilations.any { it in publishedCompilations } }
|
||||||
|
.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.createGenerateProjectStructureMetadataTask(): GenerateProjectStructureMetadata =
|
||||||
|
tasks.create("generateProjectStructureMetadata", GenerateProjectStructureMetadata::class.java) { task ->
|
||||||
|
task.lazyKotlinProjectStructureMetadata = lazy { checkNotNull(buildKotlinProjectStructureMetadata(project)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun getPublishedPlatformCompilations(project: Project): Map<KotlinUsageContext, KotlinCompilation<*>> {
|
||||||
|
val result = mutableMapOf<KotlinUsageContext, KotlinCompilation<*>>()
|
||||||
|
|
||||||
|
project.multiplatformExtension.targets.withType(AbstractKotlinTarget::class.java).forEach { target ->
|
||||||
|
if (target.platformType == KotlinPlatformType.common)
|
||||||
|
return@forEach
|
||||||
|
|
||||||
|
target.kotlinComponents
|
||||||
|
.filterIsInstance<SoftwareComponentInternal>()
|
||||||
|
.forEach { component ->
|
||||||
|
component.usages
|
||||||
|
.filterIsInstance<KotlinUsageContext>()
|
||||||
|
.forEach { usage -> result[usage] = usage.compilation }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
+2
-2
@@ -23,8 +23,6 @@ class KotlinMetadataTargetPreset(
|
|||||||
project,
|
project,
|
||||||
kotlinPluginVersion
|
kotlinPluginVersion
|
||||||
) {
|
) {
|
||||||
override fun instantiateTarget() = KotlinOnlyTarget<KotlinCommonCompilation>(project, KotlinPlatformType.common)
|
|
||||||
|
|
||||||
override fun getName(): String = PRESET_NAME
|
override fun getName(): String = PRESET_NAME
|
||||||
|
|
||||||
override fun createCompilationFactory(
|
override fun createCompilationFactory(
|
||||||
@@ -42,6 +40,8 @@ class KotlinMetadataTargetPreset(
|
|||||||
override fun createKotlinTargetConfigurator(): KotlinTargetConfigurator<KotlinCommonCompilation> =
|
override fun createKotlinTargetConfigurator(): KotlinTargetConfigurator<KotlinCommonCompilation> =
|
||||||
KotlinMetadataTargetConfigurator(kotlinPluginVersion)
|
KotlinMetadataTargetConfigurator(kotlinPluginVersion)
|
||||||
|
|
||||||
|
override fun instantiateTarget(): KotlinOnlyTarget<KotlinCommonCompilation> = KotlinMetadataTarget(project)
|
||||||
|
|
||||||
override fun createTarget(name: String): KotlinOnlyTarget<KotlinCommonCompilation> =
|
override fun createTarget(name: String): KotlinOnlyTarget<KotlinCommonCompilation> =
|
||||||
super.createTarget(name).apply {
|
super.createTarget(name).apply {
|
||||||
val mainCompilation = compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
val mainCompilation = compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||||
|
|||||||
+5
-5
@@ -10,6 +10,7 @@ import groovy.lang.Closure
|
|||||||
import org.gradle.api.Action
|
import org.gradle.api.Action
|
||||||
import org.gradle.api.NamedDomainObjectContainer
|
import org.gradle.api.NamedDomainObjectContainer
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.file.ConfigurableFileCollection
|
||||||
import org.gradle.api.file.SourceDirectorySet
|
import org.gradle.api.file.SourceDirectorySet
|
||||||
import org.gradle.util.ConfigureUtil
|
import org.gradle.util.ConfigureUtil
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||||
@@ -18,6 +19,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
|
||||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||||
|
import java.util.concurrent.Callable
|
||||||
|
|
||||||
class KotlinNativeCompilation(
|
class KotlinNativeCompilation(
|
||||||
override val target: KotlinNativeTarget,
|
override val target: KotlinNativeTarget,
|
||||||
@@ -40,7 +42,7 @@ class KotlinNativeCompilation(
|
|||||||
internal val allSources: MutableSet<SourceDirectorySet> = mutableSetOf()
|
internal val allSources: MutableSet<SourceDirectorySet> = mutableSetOf()
|
||||||
|
|
||||||
// TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
|
// TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
|
||||||
internal val commonSources: MutableSet<SourceDirectorySet> = mutableSetOf()
|
internal val commonSources: ConfigurableFileCollection = project.files()
|
||||||
|
|
||||||
var friendCompilationName: String? = null
|
var friendCompilationName: String? = null
|
||||||
|
|
||||||
@@ -82,10 +84,8 @@ class KotlinNativeCompilation(
|
|||||||
val binariesTaskName: String
|
val binariesTaskName: String
|
||||||
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "binaries")
|
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "binaries")
|
||||||
|
|
||||||
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
|
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
|
||||||
allSources.add(sourceSet.kotlin)
|
allSources.add(sourceSet.kotlin)
|
||||||
if (addAsCommonSources) {
|
commonSources.from(project.files(Callable { if (addAsCommonSources.value) sourceSet.kotlin else emptyList<Any>() }))
|
||||||
commonSources.add(sourceSet.kotlin)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -218,7 +218,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
|||||||
|
|
||||||
@get:InputFiles
|
@get:InputFiles
|
||||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
internal var commonSourceSet: Iterable<File> = emptyList()
|
internal var commonSourceSet: FileCollection = project.files()
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
internal val moduleName: String
|
internal val moduleName: String
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 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.internals
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
|
||||||
|
import org.w3c.dom.Document
|
||||||
|
|
||||||
|
fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProjectStructureMetadata? =
|
||||||
|
org.jetbrains.kotlin.gradle.plugin.mpp.parseKotlinSourceSetMetadataFromXml(document)
|
||||||
Reference in New Issue
Block a user