Selaa lähdekoodia

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

Him188 2 vuotta sitten
vanhempi
commit
25e66d19c7

+ 22 - 15
buildSrc/src/main/kotlin/Shadow.kt

@@ -79,15 +79,17 @@ private fun KotlinTarget.configureRelocationForTarget(project: Project) = projec
                 from(project.configurations.getByName("${targetName}RuntimeClasspath")
                 from(project.configurations.getByName("${targetName}RuntimeClasspath")
                     .files
                     .files
                     .filter { file ->
                     .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
                             // 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)
                             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" }
                 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 groupId: String,
     val artifactId: String? = null,
     val artifactId: String? = null,
     val shadowFilter: String = groupId,
     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 {
     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.
     // WARNING: You must also consider relocating transitive dependencies.
     // Otherwise, user will get NoClassDefFound error when using mirai as a classpath dependency. See #2263.
     // 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
 // 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))
 }
 }

+ 1 - 1
mirai-core-all/build.gradle.kts

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

+ 1 - 1
mirai-core-api/build.gradle.kts

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

+ 1 - 1
mirai-core-utils/build.gradle.kts

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

+ 1 - 1
mirai-core/build.gradle.kts

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

+ 82 - 0
mirai-deps-test/test/CoreShadowRelocationTest.kt

@@ -45,4 +45,86 @@ class CoreShadowRelocationTest : AbstractTest() {
         )
         )
         runGradle("check")
         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")
+    }
 }
 }