[core] Filter out relocated ktor dependencies in runtime except for mirai-core-utils and mirai-core-all. Fix #2291

This commit is contained in:
Him188 2022-10-21 16:09:27 +01:00
parent a9da3a10e2
commit 25e66d19c7
No known key found for this signature in database
GPG Key ID: BA439CDDCF652375
6 changed files with 108 additions and 19 deletions

View File

@ -79,15 +79,17 @@ private fun KotlinTarget.configureRelocationForTarget(project: Project) = projec
from(project.configurations.getByName("${targetName}RuntimeClasspath")
.files
.filter { file ->
relocationFilters.any { filter ->
val matchingFilter = relocationFilters.find { filter ->
// file.absolutePath example: /Users/xxx/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.7.0-RC/7f9f07fc65e534c15a820f61d846b9ffdba8f162/kotlin-stdlib-jdk8-1.7.0-RC.jar
filter.matchesFile(file)
}.also {
fileFiltered = fileFiltered || it
if (it) {
println("Including file: ${file.absolutePath}")
}
}
if (matchingFilter != null) {
fileFiltered = true
println("Including file: ${file.absolutePath}")
}
matchingFilter?.includeInRuntime == true
}
)
check(fileFiltered) { "[Shadow Relocation] Expected at least one file filtered for target $targetName. Filters: $relocationFilters" }
@ -224,7 +226,12 @@ data class RelocationFilter(
val groupId: String,
val artifactId: String? = null,
val shadowFilter: String = groupId,
val filesFilter: String = groupId.replace(".", "/")
val filesFilter: String = groupId.replace(".", "/"),
/**
* Pack relocated dependency into the fat jar. If set to `false`, dependencies will be removed.
* This is to avoid duplicated classes. See #2291.
*/ // #2291
val includeInRuntime: Boolean,
) {
fun matchesFile(file: File): Boolean {
@ -262,20 +269,20 @@ private fun ShadowJar.setRelocations() {
}
}
fun Project.configureRelocationForCore() {
fun Project.relocateKtorForCore(includeInRuntime: Boolean) {
// WARNING: You must also consider relocating transitive dependencies.
// Otherwise, user will get NoClassDefFound error when using mirai as a classpath dependency. See #2263.
relocateAllFromGroupId("io.ktor")
relocateAllFromGroupId("com.squareup.okhttp3")
relocateAllFromGroupId("com.squareup.okio")
relocateAllFromGroupId("io.ktor", includeInRuntime)
relocateAllFromGroupId("com.squareup.okhttp3", includeInRuntime)
relocateAllFromGroupId("com.squareup.okio", includeInRuntime)
}
fun Project.relocateAllFromGroupId(groupId: String) {
relocationFilters.add(RelocationFilter(groupId))
fun Project.relocateAllFromGroupId(groupId: String, includeInRuntime: Boolean) {
relocationFilters.add(RelocationFilter(groupId, includeInRuntime = includeInRuntime))
}
// This does not include transitive dependencies
fun Project.relocateExactArtifact(groupId: String, artifactId: String) {
relocationFilters.add(RelocationFilter(groupId, artifactId))
fun Project.relocateExactArtifact(groupId: String, artifactId: String, includeInRuntime: Boolean) {
relocationFilters.add(RelocationFilter(groupId, artifactId, includeInRuntime = includeInRuntime))
}

View File

@ -29,4 +29,4 @@ if (System.getenv("MIRAI_IS_SNAPSHOTS_PUBLISHING")?.toBoolean() != true) {
configurePublishing("mirai-core-all")
}
configureRelocationForCore()
relocateKtorForCore(true)

View File

@ -104,7 +104,7 @@ if (tasks.findByName("androidMainClasses") != null) {
configureMppPublishing()
configureBinaryValidators(setOf("jvm", "android").filterTargets())
configureRelocationForCore()
relocateKtorForCore(false)
//mavenCentralPublish {
// artifactId = "mirai-core-api"

View File

@ -96,7 +96,7 @@ if (tasks.findByName("androidMainClasses") != null) {
}
configureMppPublishing()
configureRelocationForCore()
relocateKtorForCore(true)
//mavenCentralPublish {
// artifactId = "mirai-core-utils"

View File

@ -203,7 +203,7 @@ if (tasks.findByName("androidMainClasses") != null) {
configureMppPublishing()
configureBinaryValidators(setOf("jvm", "android").filterTargets())
configureRelocationForCore()
relocateKtorForCore(false)
//mavenCentralPublish {
// artifactId = "mirai-core"

View File

@ -45,4 +45,86 @@ class CoreShadowRelocationTest : AbstractTest() {
)
runGradle("check")
}
// https://github.com/mamoe/mirai/issues/2291
@Test
@EnabledIf("isMiraiLocalAvailable", disabledReason = REASON_LOCAL_ARTIFACT_NOT_AVAILABLE)
fun `no duplicated class when dependency shared across modules`() {
testDir.resolve("test.kt").writeText(
"""
package test
import org.junit.jupiter.api.*
class MyTest {
@Test
fun `test base dependency`() {
assertThrows<ClassNotFoundException> {
Class.forName("net.mamoe.mirai.internal.deps.io.ktor.utils.io.ByteBufferChannel") // should only present in mirai-core-utils
}
}
}
""".trimIndent()
)
buildFile.appendText(
"""
dependencies {
implementation("net.mamoe:mirai-core:$miraiLocalVersion") {
exclude("net.mamoe", "mirai-core-api")
exclude("net.mamoe", "mirai-core-utils")
}
}
""".trimIndent()
)
runGradle("check")
}
@Test
@EnabledIf("isMiraiLocalAvailable", disabledReason = REASON_LOCAL_ARTIFACT_NOT_AVAILABLE)
fun `relocated ktor presents in mirai-core-utils`() {
testDir.resolve("test.kt").writeText(
"""
package test
import org.junit.jupiter.api.*
class MyTest {
@Test
fun `test base dependency`() {
Class.forName("net.mamoe.mirai.internal.deps.io.ktor.utils.io.ByteBufferChannel")
}
}
""".trimIndent()
)
buildFile.appendText(
"""
dependencies {
implementation("net.mamoe:mirai-core-utils:$miraiLocalVersion")
}
""".trimIndent()
)
runGradle("check")
}
@Test
@EnabledIf("isMiraiLocalAvailable", disabledReason = REASON_LOCAL_ARTIFACT_NOT_AVAILABLE)
fun `relocated ktor presents transitively in mirai-core`() {
testDir.resolve("test.kt").writeText(
"""
package test
import org.junit.jupiter.api.*
class MyTest {
@Test
fun `test base dependency`() {
Class.forName("net.mamoe.mirai.internal.deps.io.ktor.utils.io.ByteBufferChannel")
}
}
""".trimIndent()
)
buildFile.appendText(
"""
dependencies {
implementation("net.mamoe:mirai-core:$miraiLocalVersion")
}
""".trimIndent()
)
runGradle("check")
}
}