[Gradle] Migrate KlibBasedMppIT to new test DSL

^KT-65528 In Progress
This commit is contained in:
Yahor Berdnikau
2024-02-05 16:26:59 +01:00
committed by Space Team
parent 74c02a77fe
commit 55bbaec3f9
4 changed files with 431 additions and 299 deletions
@@ -19,9 +19,10 @@ class K2HierarchicalMppIT : HierarchicalMppIT() {
override val defaultBuildOptions: BuildOptions get() = super.defaultBuildOptions.copy(languageVersion = "2.0") override val defaultBuildOptions: BuildOptions get() = super.defaultBuildOptions.copy(languageVersion = "2.0")
} }
@Ignore @MppGradlePluginTests
@DisplayName("KLibs in K2")
class K2KlibBasedMppIT : KlibBasedMppIT() { class K2KlibBasedMppIT : KlibBasedMppIT() {
override fun defaultBuildOptions(): BuildOptions = super.defaultBuildOptions().copy(languageVersion = "2.0") override val defaultBuildOptions: BuildOptions = super.defaultBuildOptions.copyEnsuringK2()
} }
@Ignore @Ignore
@@ -5,89 +5,138 @@
package org.jetbrains.kotlin.gradle package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.util.modify import org.gradle.testkit.runner.BuildResult
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.util.replaceText
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
import org.junit.Assume import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.condition.OS
import org.junit.jupiter.api.io.TempDir
import java.io.File import java.io.File
import java.nio.file.Path
import java.util.* import java.util.*
import java.util.zip.ZipFile import java.util.zip.ZipFile
import kotlin.test.Test import kotlin.io.path.appendText
import kotlin.io.path.deleteRecursively
import kotlin.io.path.isDirectory
import kotlin.io.path.writeText
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
open class KlibBasedMppIT : BaseGradleIT() {
override val defaultGradleVersion: GradleVersionRequired = GradleVersionRequired.FOR_MPP_SUPPORT
companion object { @DisplayName("KLibs in K1")
private const val MODULE_GROUP = "com.example" @MppGradlePluginTests
} open class KlibBasedMppIT : KGPBaseTest() {
@Test override val defaultBuildOptions: BuildOptions = super.defaultBuildOptions.copyEnsuringK1()
fun testBuildWithProjectDependency() = testBuildWithDependency {
gradleBuildScript().appendText( @DisplayName("Could be compiled with project dependency")
"\n" + """ @GradleTest
dependencies { fun testBuildWithProjectDependency(
commonMainImplementation(project("$dependencyModuleName")) gradleVersion: GradleVersion,
} @TempDir localRepo: Path,
""".trimIndent() ) {
testBuildWithDependency(gradleVersion, localRepo) {
buildGradleKts.appendText(
"""
|
|dependencies {
| commonMainImplementation(project("$dependencyModuleName"))
|}
""".trimMargin()
) )
} }
}
@Test @DisplayName("KT-36674: Could be compiled with empty source set")
fun testPublishingAndConsumptionWithEmptySourceSet() = testBuildWithDependency { @GradleTest
// KT-36674 fun testPublishingAndConsumptionWithEmptySourceSet(
projectDir.resolve("$dependencyModuleName/src/windowsMain").run { gradleVersion: GradleVersion,
assertTrue { isDirectory } @TempDir localRepo: Path,
) {
testBuildWithDependency(gradleVersion, localRepo) {
subProject(dependencyModuleName)
.kotlinSourcesDir("windowsMain")
.parent
.run {
assertTrue(isDirectory())
deleteRecursively() deleteRecursively()
} }
publishProjectDepAndAddDependency(validateHostSpecificPublication = false) publishProjectDepAndAddDependency(validateHostSpecificPublication = false)
} }
}
@Test @DisplayName("Compiles with common sources in transitive dependencies")
fun testCommonSourceSetsInTransitiveDependencies() = with(Project("common-klib-lib-and-app")) { @GradleTest
fun testCommonSourceSetsInTransitiveDependencies(
gradleVersion: GradleVersion,
@TempDir localRepo: Path,
) {
project(
"common-klib-lib-and-app",
gradleVersion,
localRepoDir = localRepo
) {
// On macOS KT-41083 is also validated by publishing a lib with host specific source sets depending on another lib with host-specific source sets // On macOS KT-41083 is also validated by publishing a lib with host specific source sets depending on another lib with host-specific source sets
setupWorkingDir()
val projectDepName = "dependency" val projectDepName = "dependency"
val publishedGroup = "published" val publishedGroup = "published"
val producerProjectName = "producer" val producerProjectName = "producer"
embedProject(this, renameTo = projectDepName) includeOtherProjectAsSubmodule(
projectDir.resolve("$projectDepName/src").walkTopDown().filter { it.extension == "kt" }.forEach { ktFile -> otherProjectName = "common-klib-lib-and-app",
// Avoid FQN duplicates between producer & consumer newSubmoduleName = projectDepName,
ktFile.modify { it.replace("package com.h0tk3y.hmpp.klib.demo", "package com.h0tk3y.hmpp.klib.lib") } isKts = true,
} localRepoDir = localRepo
gradleBuildScript(projectDepName).appendText(
"""
${"\n"}
group = "$publishedGroup"
""".trimIndent()
) )
gradleBuildScript().modify {
transformBuildScriptWithPluginsDsl(it) +
"""
${"\n"}
dependencies { "commonMainImplementation"(project(":$projectDepName")) }
group = "$publishedGroup"
""".trimIndent()
}
gradleSettingsScript().appendText("\nrootProject.name = \"$producerProjectName\"")
build("publish") { subProject(projectDepName)
assertSuccessful() .projectPath
.allKotlinFiles
.forEach { ktFile ->
// Avoid FQN duplicates between producer & consumer
ktFile.replaceText("package com.h0tk3y.hmpp.klib.demo", "package com.h0tk3y.hmpp.klib.lib")
} }
subProject(projectDepName).buildGradleKts.appendText(
"""
|
|group = "$publishedGroup"
""".trimMargin()
)
buildGradleKts.appendText(
"""
|
|dependencies { "commonMainImplementation"(project(":$projectDepName")) }
|group = "$publishedGroup"
""".trimMargin()
)
settingsGradleKts.appendText(
"""
|
|rootProject.name = "$producerProjectName"
|
""".trimMargin()
)
build("publish")
// Then consume the published project. To do that, rename the modules so that Gradle chooses the published ones given the original // Then consume the published project. To do that, rename the modules so that Gradle chooses the published ones given the original
// Maven coordinates and doesn't resolve them as project dependencies. // Maven coordinates and doesn't resolve them as project dependencies.
val localGroup = "local" val localGroup = "local"
gradleBuildScript(projectDepName).appendText("""${"\n"}group = "$localGroup"""") subProject(projectDepName).buildGradleKts.appendText(
gradleBuildScript().appendText(
""" """
${"\n"} |
repositories { maven("${'$'}rootDir/repo") } |group = "$localGroup"
dependencies { "commonMainImplementation"("$publishedGroup:$producerProjectName:1.0") } """.trimMargin()
group = "$localGroup" )
""".trimIndent() buildGradleKts.appendText(
"""
|
|repositories { maven("${'$'}rootDir/repo") }
|dependencies { "commonMainImplementation"("$publishedGroup:$producerProjectName:1.0") }
|group = "$localGroup"
""".trimMargin()
) )
val commonModules = listOf( val commonModules = listOf(
@@ -112,7 +161,6 @@ open class KlibBasedMppIT : BaseGradleIT() {
) )
// The consumer should correctly receive the klibs of the host-specific source sets // The consumer should correctly receive the klibs of the host-specific source sets
if (HostManager.hostIsMac) { if (HostManager.hostIsMac) {
checkTaskCompileClasspath( checkTaskCompileClasspath(
"compileIosMainKotlinMetadata", "compileIosMainKotlinMetadata",
@@ -121,201 +169,83 @@ open class KlibBasedMppIT : BaseGradleIT() {
) )
} }
} }
}
@Test
fun testHostSpecificBuildWithPublishedDependency() = testBuildWithDependency {
// Host-specific dependencies are only possible on macOS // Host-specific dependencies are only possible on macOS
Assume.assumeTrue(HostManager.hostIsMac) @OsCondition(
supportedOn = [OS.MAC],
enabledOnCI = [OS.MAC],
)
@DisplayName("Works with host specific dependencies")
@GradleTest
fun testHostSpecificBuildWithPublishedDependency(
gradleVersion: GradleVersion,
@TempDir localRepo: Path
) {
testBuildWithDependency(gradleVersion, localRepo) {
publishProjectDepAndAddDependency(validateHostSpecificPublication = true) publishProjectDepAndAddDependency(validateHostSpecificPublication = true)
} }
private fun Project.publishProjectDepAndAddDependency(validateHostSpecificPublication: Boolean) {
build(":$dependencyModuleName:publish") {
assertSuccessful()
if (validateHostSpecificPublication)
checkPublishedHostSpecificMetadata(this@build)
} }
gradleBuildScript().appendText( @DisplayName("Works with Kotlin native transitive dependencies")
"\n" + """ @GradleTest
repositories { fun testKotlinNativeImplPublishedDeps(
maven("${'$'}rootDir/repo") gradleVersion: GradleVersion,
} @TempDir localRepo: Path
dependencies { ) {
commonMainImplementation("$MODULE_GROUP:$dependencyModuleName:1.0") testKotlinNativeImplementationDependencies(gradleVersion, localRepo) {
} build(":$transitiveDepModuleName:publish", ":$dependencyModuleName:publish")
""".trimIndent()
)
// prevent Gradle from linking the above dependency to the project: buildGradleKts.appendText(
gradleBuildScript(dependencyModuleName).appendText("\ngroup = \"some.other.group\"") """
} |
|repositories {
private val dependencyModuleName = "project-dep" | maven("${'$'}rootDir/repo")
|}
private fun testBuildWithDependency(configureDependency: Project.() -> Unit) = with(Project("common-klib-lib-and-app")) { |
embedProject(Project("common-klib-lib-and-app"), renameTo = dependencyModuleName) |dependencies {
| commonMainImplementation("$MODULE_GROUP:$dependencyModuleName:1.0")
projectDir.resolve("$dependencyModuleName/src/commonMain/kotlin/TestKt37832.kt").writeText( |}
"package com.example.test.kt37832" + "\n" + "class MyException : RuntimeException()" """.trimMargin()
)
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
projectDir.resolve(dependencyModuleName + "/src").walkTopDown().filter { it.extension == "kt" }.forEach { file ->
file.modify { it.replace("package com.h0tk3y.hmpp.klib.demo", "package com.projectdep") }
}
configureDependency()
projectDir.resolve("src/commonMain/kotlin/LibUsage.kt").appendText(
"\n" + """
package com.h0tk3y.hmpp.klib.demo.test
import com.projectdep.LibCommonMainExpect as ProjectDepExpect
private fun useProjectDep() {
ProjectDepExpect()
}
""".trimIndent()
)
projectDir.resolve("src/linuxMain/kotlin/LibLinuxMainUsage.kt").appendText(
"\n" + """
package com.h0tk3y.hmpp.klib.demo.test
import com.projectdep.libLinuxMainFun as libFun
private fun useProjectDep() {
libFun()
}
""".trimIndent()
)
val tasksToExecute = listOf(
":compileJvmAndJsMainKotlinMetadata",
":compileLinuxMainKotlinMetadata",
) + (if (HostManager.hostIsMac) listOf(":compileIosMainKotlinMetadata") else emptyList())
build("assemble") {
assertSuccessful()
assertTasksExecuted(*tasksToExecute.toTypedArray())
assertFileExists("build/classes/kotlin/metadata/commonMain/default/manifest")
assertFileExists("build/classes/kotlin/metadata/jvmAndJsMain/default/manifest")
assertFileExists("build/classes/kotlin/metadata/linuxMain/klib/${projectName}_linuxMain")
// Check that the common and JVM+JS source sets don't receive the Kotlin/Native stdlib in the classpath:
run {
fun getClasspath(taskPath: String): Iterable<String> {
val argsPrefix = " $taskPath Kotlin compiler args:"
return output.lines().single { argsPrefix in it }
.substringAfter("-classpath ").substringBefore(" -").split(File.pathSeparator)
}
fun classpathHasKNStdlib(classpath: Iterable<String>) = classpath.any { "klib/common/stdlib" in it.replace("\\", "/") }
assertFalse(classpathHasKNStdlib(getClasspath(":compileCommonMainKotlinMetadata")))
assertFalse(classpathHasKNStdlib(getClasspath(":compileJvmAndJsMainKotlinMetadata")))
}
}
}
private fun checkPublishedHostSpecificMetadata(compiledProject: CompiledProject) = with(compiledProject) {
val groupDir = project.projectDir.resolve("repo/com/example")
assertTasksExecuted(
":$dependencyModuleName:compileIosMainKotlinMetadata")
// Check that the metadata JAR doesn't contain the host-specific source set entries, but contains the shared-Native source set
// that can be built on every host:
ZipFile(groupDir.resolve("$dependencyModuleName/1.0/$dependencyModuleName-1.0-all.jar")).use { metadataJar ->
assertTrue { metadataJar.entries().asSequence().none { it.name.startsWith("iosMain") } }
assertTrue { metadataJar.entries().asSequence().any { it.name.startsWith("linuxMain") } }
}
// Then check that in the host-specific modules, there's a metadata artifact that contains the host-specific source set but not the
// common source sets:
val hostSpecificTargets = when {
HostManager.hostIsMac -> listOf("iosArm64", "iosX64")
else -> error("Host doesn't support host-specific metadata")
}
hostSpecificTargets.forEach { targetName ->
val moduleName = "$dependencyModuleName-${targetName.lowercase(Locale.getDefault())}"
ZipFile(groupDir.resolve("$moduleName/1.0/$moduleName-1.0-metadata.jar")).use { metadataJar ->
assertTrue { metadataJar.entries().asSequence().any { it.name.startsWith("iosMain") } }
assertTrue { metadataJar.entries().asSequence().none { it.name.startsWith("commonMain") } }
}
}
// Also check that the targets that don't include any host-specific sources don't even have the metadata artifact:
groupDir.resolve("$dependencyModuleName-linuxx64/1.0/$dependencyModuleName-linuxx64-1.0-metadata.jar").let { metadataJar ->
assertTrue { !metadataJar.exists() }
}
}
private val transitiveDepModuleName = "transitive-dep"
@Test
fun testKotlinNativeImplPublishedDeps() =
testKotlinNativeImplementationDependencies {
build(":$transitiveDepModuleName:publish", ":$dependencyModuleName:publish") {
assertSuccessful()
}
gradleBuildScript().appendText(
"\n" + """
repositories {
maven("${'$'}rootDir/repo")
}
dependencies {
commonMainImplementation("$MODULE_GROUP:$dependencyModuleName:1.0")
}
""".trimIndent()
) )
listOf(transitiveDepModuleName, dependencyModuleName).forEach { listOf(transitiveDepModuleName, dependencyModuleName).forEach {
// prevent Gradle from linking the above dependency to the project: // prevent Gradle from linking the above dependency to the project:
gradleBuildScript(it).appendText("\ngroup = \"com.some.other.group\"") subProject(it).buildGradleKts.appendText(
"""
|
|group = "com.some.other.group"
""".trimMargin()
)
}
} }
} }
@Test @DisplayName("Works with project dependencies containing Kotlin Native target")
fun testKotlinNativeImplProjectDeps() = @GradleTest
testKotlinNativeImplementationDependencies { fun testKotlinNativeImplProjectDeps(
gradleBuildScript().appendText("\ndependencies { \"commonMainImplementation\"(project(\":$dependencyModuleName\")) }") gradleVersion: GradleVersion,
} @TempDir localRepo: Path,
) {
private fun testKotlinNativeImplementationDependencies( testKotlinNativeImplementationDependencies(gradleVersion, localRepo) {
setupDependencies: Project.() -> Unit, buildGradleKts.appendText(
) = with(Project("common-klib-lib-and-app")) { """
embedProject(Project("common-klib-lib-and-app"), renameTo = transitiveDepModuleName) |
embedProject(Project("common-klib-lib-and-app"), renameTo = dependencyModuleName).apply { |dependencies {
projectDir.resolve(dependencyModuleName).walkTopDown().filter { it.extension == "kt" }.forEach { file -> | "commonMainImplementation"(project(":$dependencyModuleName"))
// Avoid duplicate FQNs as in the compatibility mode, the K2Metadata compiler reports duplicate symbols on them: |}
file.modify { it.replace("package com.h0tk3y.hmpp.klib.demo", "package com.h0tk3y.hmpp.klib.demo1") } """.trimMargin()
} )
}
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
gradleBuildScript(dependencyModuleName).appendText("\ndependencies { \"commonMainImplementation\"(project(\":$transitiveDepModuleName\")) }")
setupDependencies(this@with)
val compileNativeMetadataTaskName = "compileLinuxMainKotlinMetadata"
build(":$compileNativeMetadataTaskName") {
assertSuccessful()
} }
} }
@Test @DisplayName("KT-38746: Should not disable compilation of shared source set")
fun testAvoidSkippingSharedNativeSourceSetKt38746() = with(Project("hierarchical-all-native")) { @GradleTest
fun testAvoidSkippingSharedNativeSourceSetKt38746(gradleVersion: GradleVersion) {
project("hierarchical-all-native", gradleVersion) {
val targetNames = listOf( val targetNames = listOf(
// Try different alphabetical ordering of the targets to ensure that the behavior doesn't depend on it, as with 'first target' // Try different alphabetical ordering of the targets to ensure that the behavior doesn't depend on it,
// as with 'first target'
listOf("a1", "a2", "a3"), listOf("a1", "a2", "a3"),
listOf("a3", "a1", "a2"), listOf("a3", "a1", "a2"),
listOf("a2", "a3", "a1"), listOf("a2", "a3", "a1"),
@@ -330,15 +260,211 @@ open class KlibBasedMppIT : BaseGradleIT() {
} }
val params = targetParamNames.zip(names + currentHostTargetName) { k, v -> "-P$k=$v" } val params = targetParamNames.zip(names + currentHostTargetName) { k, v -> "-P$k=$v" }
build(":clean", ":compileCurrentHostAndLinuxKotlinMetadata", *params.toTypedArray()) { build(":clean", ":compileCurrentHostAndLinuxKotlinMetadata", *params.toTypedArray()) {
assertSuccessful()
assertTasksExecuted(":compileCurrentHostAndLinuxKotlinMetadata", ":compileAllNativeKotlinMetadata") assertTasksExecuted(":compileCurrentHostAndLinuxKotlinMetadata", ":compileAllNativeKotlinMetadata")
} }
} }
} }
}
private var testBuildRunId = 0 private fun TestProject.publishProjectDepAndAddDependency(validateHostSpecificPublication: Boolean) {
build(":$dependencyModuleName:publish") {
if (validateHostSpecificPublication) checkPublishedHostSpecificMetadata(this@publishProjectDepAndAddDependency)
}
private fun BaseGradleIT.Project.checkTaskCompileClasspath( buildGradleKts.appendText(
"""
|
|repositories {
| maven("${'$'}rootDir/repo")
|}
|
|dependencies {
| commonMainImplementation("$MODULE_GROUP:$dependencyModuleName:1.0")
|}
""".trimMargin()
)
// prevent Gradle from linking the above dependency to the project:
subProject(dependencyModuleName)
.buildGradleKts
.appendText(
"""
|
|group = "some.other.group"
""".trimMargin()
)
}
private val dependencyModuleName = "project-dep"
private val transitiveDepModuleName = "transitive-dep"
private fun testBuildWithDependency(
gradleVersion: GradleVersion,
localRepo: Path,
configureDependency: TestProject.() -> Unit
) {
project("common-klib-lib-and-app", gradleVersion, localRepoDir = localRepo) {
includeOtherProjectAsSubmodule(
otherProjectName = "common-klib-lib-and-app",
newSubmoduleName = dependencyModuleName,
isKts = true,
localRepoDir = localRepo,
)
subProject(dependencyModuleName)
.kotlinSourcesDir("commonMain")
.resolve("TestKt37832.kt")
.writeText(
"""
|package com.example.test.kt37832
|
|class MyException : RuntimeException()
""".trimMargin()
)
subProject(dependencyModuleName)
.projectPath
.allKotlinFiles
.forEach { file ->
file.replaceText("package com.h0tk3y.hmpp.klib.demo", "package com.projectdep")
}
configureDependency()
kotlinSourcesDir("commonMain").resolve("LibUsage.kt").writeText(
"""
|
|package com.h0tk3y.hmpp.klib.demo.test
|
|import com.projectdep.LibCommonMainExpect as ProjectDepExpect
|
|private fun useProjectDep() {
| ProjectDepExpect()
|}
""".trimMargin()
)
kotlinSourcesDir("linuxMain").resolve("LibLinuxMainUsage.kt").writeText(
"""
|
|package com.h0tk3y.hmpp.klib.demo.test
|
|import com.projectdep.libLinuxMainFun as libFun
|
|private fun useProjectDep() {
| libFun()
|}
""".trimMargin()
)
val tasksToExecute = listOfNotNull(
":compileJvmAndJsMainKotlinMetadata",
":compileLinuxMainKotlinMetadata",
if (HostManager.hostIsMac) ":compileIosMainKotlinMetadata" else null
)
build("assemble") {
assertTasksExecuted(tasksToExecute)
assertFileInProjectExists("build/classes/kotlin/metadata/commonMain/default/manifest")
assertFileInProjectExists("build/classes/kotlin/metadata/jvmAndJsMain/default/manifest")
assertDirectoryInProjectExists("build/classes/kotlin/metadata/linuxMain/klib/${projectName}_linuxMain")
// Check that the common and JVM+JS source sets don't receive the Kotlin/Native stdlib in the classpath:
assertFalse(classpathHasKNStdlib(getClasspath(":compileCommonMainKotlinMetadata")))
assertFalse(classpathHasKNStdlib(getClasspath(":compileJvmAndJsMainKotlinMetadata")))
}
}
}
private fun classpathHasKNStdlib(classpath: Iterable<String>) = classpath.any { "klib/common/stdlib" in it.replace("\\", "/") }
private fun BuildResult.getClasspath(taskPath: String): Iterable<String> {
val argsPrefix = " $taskPath Kotlin compiler args:"
return output.lines().single { argsPrefix in it }
.substringAfter("-classpath ").substringBefore(" -").split(File.pathSeparator)
}
private fun BuildResult.checkPublishedHostSpecificMetadata(project: TestProject) {
val groupDir = project.projectPath.resolve("repo/com/example")
assertTasksExecuted(":$dependencyModuleName:compileIosMainKotlinMetadata")
// Check that the metadata JAR doesn't contain the host-specific source set entries, but contains the shared-Native source set
// that can be built on every host:
ZipFile(groupDir.resolve("$dependencyModuleName/1.0/$dependencyModuleName-1.0-all.jar").toFile())
.use { metadataJar ->
assertTrue(metadataJar.entries().asSequence().none { it.name.startsWith("iosMain") })
assertTrue(metadataJar.entries().asSequence().any { it.name.startsWith("linuxMain") })
}
// Then check that in the host-specific modules, there's a metadata artifact that contains the host-specific source set but not the
// common source sets:
val hostSpecificTargets = when {
HostManager.hostIsMac -> listOf("iosArm64", "iosX64")
else -> error("Host doesn't support host-specific metadata")
}
hostSpecificTargets.forEach { targetName ->
val moduleName = "$dependencyModuleName-${targetName.lowercase(Locale.getDefault())}"
ZipFile(groupDir.resolve("$moduleName/1.0/$moduleName-1.0-metadata.jar").toFile())
.use { metadataJar ->
assertTrue(metadataJar.entries().asSequence().any { it.name.startsWith("iosMain") })
assertTrue(metadataJar.entries().asSequence().none { it.name.startsWith("commonMain") })
}
}
// Also check that the targets that don't include any host-specific sources don't even have the metadata artifact:
assertFileNotExists(
groupDir.resolve("$dependencyModuleName-linuxx64/1.0/$dependencyModuleName-linuxx64-1.0-metadata.jar")
)
}
private fun testKotlinNativeImplementationDependencies(
gradleVersion: GradleVersion,
localRepo: Path,
setupProject: TestProject.() -> Unit,
) {
project("common-klib-lib-and-app", gradleVersion, localRepoDir = localRepo) {
includeOtherProjectAsSubmodule(
otherProjectName = "common-klib-lib-and-app",
newSubmoduleName = transitiveDepModuleName,
isKts = true,
localRepoDir = localRepo,
)
includeOtherProjectAsSubmodule(
otherProjectName = "common-klib-lib-and-app",
newSubmoduleName = dependencyModuleName,
isKts = true,
localRepoDir = localRepo
)
subProject(dependencyModuleName)
.projectPath
.allKotlinFiles
.forEach { file ->
// Avoid duplicate FQNs as in the compatibility mode, the K2Metadata compiler reports duplicate symbols on them:
file.replaceText("package com.h0tk3y.hmpp.klib.demo", "package com.h0tk3y.hmpp.klib.demo1")
}
subProject(dependencyModuleName)
.buildGradleKts
.appendText(
"""
|
|dependencies {
| "commonMainImplementation"(project(":$transitiveDepModuleName"))
|}
""".trimMargin()
)
setupProject(this)
build(":compileLinuxMainKotlinMetadata")
}
}
private fun TestProject.checkTaskCompileClasspath(
taskPath: String, taskPath: String,
checkModulesInClasspath: List<Regex> = emptyList(), checkModulesInClasspath: List<Regex> = emptyList(),
checkModulesNotInClasspath: List<Regex> = emptyList(), checkModulesNotInClasspath: List<Regex> = emptyList(),
@@ -350,28 +476,27 @@ open class KlibBasedMppIT : BaseGradleIT() {
checkPrintedItems(subproject, expression, checkModulesInClasspath, checkModulesNotInClasspath) checkPrintedItems(subproject, expression, checkModulesInClasspath, checkModulesNotInClasspath)
} }
private fun BaseGradleIT.Project.checkPrintedItems( private fun TestProject.checkPrintedItems(
subproject: String?, subproject: String?,
itemsExpression: String, itemsExpression: String,
checkAnyItemsContains: List<Regex>, checkAnyItemsContains: List<Regex>,
checkNoItemContains: List<Regex>, checkNoItemContains: List<Regex>,
) = with(testCase) { ) {
setupWorkingDir() val printingTaskName = "printItems"
val testProject = if (subproject != null) subProject(subproject) else this
val printingTaskName = "printItems${testBuildRunId++}" testProject.buildGradleKts.appendText(
gradleBuildScript(subproject).appendText(
""" """
${'\n'}
tasks.register("$printingTaskName") { |tasks.register("$printingTaskName") {
dependsOn("transformDependenciesMetadata") | dependsOn("transformDependenciesMetadata")
doLast { | doLast {
println("###$printingTaskName" + $itemsExpression) | println("###$printingTaskName" + $itemsExpression)
} | }
} |}
""".trimIndent() """.trimMargin()
) )
build("${subproject?.prependIndent(":").orEmpty()}:$printingTaskName") { build("${subproject?.prependIndent(":").orEmpty()}:$printingTaskName") {
assertSuccessful()
val itemsLine = output.lines().single { "###$printingTaskName" in it }.substringAfter(printingTaskName) val itemsLine = output.lines().single { "###$printingTaskName" in it }.substringAfter(printingTaskName)
// NOTE: This does not work for commonized libraries, they may contain the ',' naturally // NOTE: This does not work for commonized libraries, they may contain the ',' naturally
val items = itemsLine.removeSurrounding("[", "]").split(", ").toSet() val items = itemsLine.removeSurrounding("[", "]").split(", ").toSet()
@@ -383,4 +508,8 @@ open class KlibBasedMppIT : BaseGradleIT() {
} }
} }
} }
companion object {
private const val MODULE_GROUP = "com.example"
}
} }
@@ -397,11 +397,16 @@ class TestProject(
*/ */
fun includeOtherProjectAsSubmodule( fun includeOtherProjectAsSubmodule(
otherProjectName: String, otherProjectName: String,
pathPrefix: String, pathPrefix: String = "",
newSubmoduleName: String = otherProjectName, newSubmoduleName: String = otherProjectName,
isKts: Boolean = false, isKts: Boolean = false,
localRepoDir: Path? = null,
) { ) {
val otherProjectPath = "$pathPrefix/$otherProjectName".testProjectPath val otherProjectPath = if (pathPrefix.isEmpty()) {
otherProjectName.testProjectPath
} else {
"$pathPrefix/$otherProjectName".testProjectPath
}
otherProjectPath.copyRecursively(projectPath.resolve(newSubmoduleName)) otherProjectPath.copyRecursively(projectPath.resolve(newSubmoduleName))
val gradleSettingToUpdate = if (isKts) settingsGradleKts else settingsGradle val gradleSettingToUpdate = if (isKts) settingsGradleKts else settingsGradle
@@ -412,6 +417,8 @@ class TestProject(
include(":$newSubmoduleName") include(":$newSubmoduleName")
""".trimIndent() """.trimIndent()
) )
localRepoDir?.let { subProject(newSubmoduleName).configureLocalRepository(localRepoDir) }
} }
fun includeOtherProjectAsIncludedBuild( fun includeOtherProjectAsIncludedBuild(
@@ -814,7 +821,7 @@ private fun TestProject.configureSingleNativeTargetInSubFolders(preset: String =
} }
} }
private fun TestProject.configureLocalRepository(localRepoDir: Path) { private fun GradleProject.configureLocalRepository(localRepoDir: Path) {
projectPath.toFile().walkTopDown() projectPath.toFile().walkTopDown()
.filter { it.isFile && it.name in buildFileNames } .filter { it.isFile && it.name in buildFileNames }
.forEach { file -> .forEach { file ->
@@ -1,16 +1,11 @@
plugins { plugins {
kotlin("multiplatform").version("<pluginMarkerVersion>") kotlin("multiplatform")
id("maven-publish") id("maven-publish")
} }
group = "com.example" group = "com.example"
version = "1.0" version = "1.0"
repositories {
mavenLocal()
mavenCentral()
}
kotlin { kotlin {
jvm() jvm()
js() js()
@@ -65,7 +60,7 @@ kotlin {
publishing { publishing {
repositories { repositories {
maven("$rootDir/repo") maven("<localRepo>")
} }
} }