From 48c2b04a49ff4b2bf41f2412c27ae87ec10d6132 Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Tue, 24 May 2022 17:56:29 +0800 Subject: [PATCH] Fix plugin's dependencies classes linking; fix #2054 --- .../module-moda/.nested-module.txt | 0 .../module-moda/resources/mvn.txt | 1 + .../module-moda/src/ModuleA.kt | 16 +++++++++ .../module-modb/.nested-module.txt | 0 .../module-modb/build.gradle.kts | 27 ++++++++++++++ .../module-modb/resources/mvn.txt | 1 + .../module-modb/src/ModuleB.kt | 20 +++++++++++ ...t.mamoe.mirai.console.plugin.jvm.JvmPlugin | 10 ++++++ .../second-plugin/.nested-module.txt | 0 ...t.mamoe.mirai.console.plugin.jvm.JvmPlugin | 10 ++++++ .../second-plugin/src/PDepDependOnDepSec.kt | 35 +++++++++++++++++++ .../src/PDepDependOnDep.kt | 24 +++++++++++++ .../plugin/BuiltInJvmPluginLoaderImpl.kt | 3 ++ .../internal/plugin/JvmPluginClassLoader.kt | 33 +++++++++-------- 14 files changed, 163 insertions(+), 17 deletions(-) create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/.nested-module.txt create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/resources/mvn.txt create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/src/ModuleA.kt create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/.nested-module.txt create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/build.gradle.kts create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/resources/mvn.txt create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/src/ModuleB.kt create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/.nested-module.txt create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/src/PDepDependOnDepSec.kt create mode 100644 mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/src/PDepDependOnDep.kt diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/.nested-module.txt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/.nested-module.txt new file mode 100644 index 000000000..e69de29bb diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/resources/mvn.txt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/resources/mvn.txt new file mode 100644 index 000000000..9e707303e --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/resources/mvn.txt @@ -0,0 +1 @@ +net.mamoe.consoleit.issue2054:moda:1.0.0 diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/src/ModuleA.kt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/src/ModuleA.kt new file mode 100644 index 000000000..495be17b6 --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-moda/src/ModuleA.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package issue2054.modulea + +public object ModuleA { + public fun act(b: () -> Unit) { + b() + } +} diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/.nested-module.txt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/.nested-module.txt new file mode 100644 index 000000000..e69de29bb diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/build.gradle.kts b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/build.gradle.kts new file mode 100644 index 000000000..dc265cc74 --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +@file:Suppress("UnusedImport") + +plugins { + kotlin("jvm") + kotlin("plugin.serialization") + id("java") +} + +version = "0.0.0" + +kotlin { + explicitApiWarning() +} + +dependencies { + api(project(":mirai-console.integration-test")) + api(parent!!.project("module-moda")) +} diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/resources/mvn.txt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/resources/mvn.txt new file mode 100644 index 000000000..c52f34c1f --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/resources/mvn.txt @@ -0,0 +1 @@ +net.mamoe.consoleit.issue2054:modb:1.0.0 diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/src/ModuleB.kt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/src/ModuleB.kt new file mode 100644 index 000000000..378ee06a9 --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/module-modb/src/ModuleB.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package issue2054.moduleb + +import issue2054.modulea.ModuleA + + +public object ModuleB { + public val getModuleA: Any get() = ModuleA + public fun act(b: () -> Unit) { + b() + } +} diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin new file mode 100644 index 000000000..12c7d1f96 --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin @@ -0,0 +1,10 @@ +# +# Copyright 2019-2022 Mamoe Technologies and contributors. +# +# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. +# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. +# +# https://github.com/mamoe/mirai/blob/dev/LICENSE +# + +pdepdep2054.PDepDependOnDep diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/.nested-module.txt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/.nested-module.txt new file mode 100644 index 000000000..e69de29bb diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin new file mode 100644 index 000000000..8ee888785 --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin @@ -0,0 +1,10 @@ +# +# Copyright 2019-2022 Mamoe Technologies and contributors. +# +# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. +# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. +# +# https://github.com/mamoe/mirai/blob/dev/LICENSE +# + +pdepdep2054sec.PDepDependOnDepSec diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/src/PDepDependOnDepSec.kt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/src/PDepDependOnDepSec.kt new file mode 100644 index 000000000..b4eebba3a --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/second-plugin/src/PDepDependOnDepSec.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package pdepdep2054sec + +import issue2054.modulea.ModuleA +import issue2054.moduleb.ModuleB +import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription +import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin +import net.mamoe.mirai.utils.info +import kotlin.test.assertSame + +public object PDepDependOnDepSec : KotlinPlugin( + JvmPluginDescription("net.mamoe.console.itest.plugin-dep-dependon-dep-sec", "0.0.0") { + dependsOn("net.mamoe.console.itest.plugin-dep-dependon-dep") + } +) { + override fun onEnable() { + jvmPluginClasspath.downloadAndAddToPath( + jvmPluginClasspath.pluginIndependentLibrariesClassLoader, + listOf("net.mamoe.consoleit.issue2054:modb:1.0.0") + ) + + assertSame(ModuleA, ModuleB.getModuleA) + logger.info { "issue 2054" } + + ModuleB.act { ModuleA.act { logger.info(Throwable("Stack trace")) } } + } +} diff --git a/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/src/PDepDependOnDep.kt b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/src/PDepDependOnDep.kt new file mode 100644 index 000000000..d1142e7ae --- /dev/null +++ b/mirai-console/backend/integration-test/testers/plugin-dep-dependon-dep-issue-2054/src/PDepDependOnDep.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package pdepdep2054 + +import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription +import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin + +public object PDepDependOnDep : KotlinPlugin( + JvmPluginDescription("net.mamoe.console.itest.plugin-dep-dependon-dep", "0.0.0") +) { + init { + jvmPluginClasspath.downloadAndAddToPath( + jvmPluginClasspath.pluginSharedLibrariesClassLoader, + listOf("net.mamoe.consoleit.issue2054:moda:1.0.0") + ) + } +} diff --git a/mirai-console/backend/mirai-console/src/internal/plugin/BuiltInJvmPluginLoaderImpl.kt b/mirai-console/backend/mirai-console/src/internal/plugin/BuiltInJvmPluginLoaderImpl.kt index 7c48f911e..17d9f4206 100644 --- a/mirai-console/backend/mirai-console/src/internal/plugin/BuiltInJvmPluginLoaderImpl.kt +++ b/mirai-console/backend/mirai-console/src/internal/plugin/BuiltInJvmPluginLoaderImpl.kt @@ -245,6 +245,9 @@ internal class BuiltInJvmPluginLoaderImpl( }.mapNotNull { it.javaClass.classLoader.safeCast() }.forEach { dependency -> plugin.logger.debug { "Linked dependency: $dependency" } jvmPluginClassLoaderN.dependencies.add(dependency) + jvmPluginClassLoaderN.pluginSharedCL.dependencies.cast>().add( + dependency.pluginSharedCL + ) } jvmPluginClassLoaderN.linkPluginLibraries(plugin.logger) } diff --git a/mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginClassLoader.kt b/mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginClassLoader.kt index bb9a08327..959dc18f0 100644 --- a/mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginClassLoader.kt +++ b/mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginClassLoader.kt @@ -54,6 +54,7 @@ internal class JvmPluginsLoadingCtx( internal class DynLibClassLoader : URLClassLoader { private val clName: String? + internal var dependencies: List = emptyList() private constructor(parent: ClassLoader?, clName: String?) : super(arrayOf(), parent) { this.clName = clName @@ -140,13 +141,22 @@ internal class DynLibClassLoader : URLClassLoader { } } - internal fun findButNoSystem(name: String): Class<*>? { + internal fun findButNoSystem(name: String): Class<*>? = findButNoSystem(name, mutableListOf()) + private fun findButNoSystem(name: String, track: MutableList): Class<*>? { if (name.startsWith("java.")) return null + // Skip duplicated searching, for faster speed. + if (this in track) return null + track.add(this) + val pt = this.parent if (pt is DynLibClassLoader) { - pt.findButNoSystem(name)?.let { return it } + pt.findButNoSystem(name, track)?.let { return it } } + dependencies.forEach { dep -> + dep.findButNoSystem(name, track)?.let { return it } + } + synchronized(getClassLoadingLock(name)) { findLoadedClass(name)?.let { return it } try { @@ -160,22 +170,10 @@ internal class DynLibClassLoader : URLClassLoader { override fun loadClass(name: String, resolve: Boolean): Class<*> { tryFastOrStrictResolve(name)?.let { return it } - val pt = this.parent - val topPt: ClassLoader? = if (pt is DynLibClassLoader) { - pt.findButNoSystem(name)?.let { return it } + findButNoSystem(name)?.let { return it } - generateSequence(pt) { it.parent }.firstOrNull { it !is DynLibClassLoader } - } else pt - - - synchronized(getClassLoadingLock(name)) { - findLoadedClass(name)?.let { return it } - try { - return findClass(name) - } catch (ignored: ClassNotFoundException) { - } - return Class.forName(name, false, topPt) - } + val topParent = generateSequence(this) { it.parent }.firstOrNull { it !is DynLibClassLoader } + return Class.forName(name, false, topParent) } } @@ -236,6 +234,7 @@ internal class JvmPluginClassLoaderN : URLClassLoader { pluginIndependentCL = DynLibClassLoader.newInstance( pluginSharedCL, "IndependentCL{${file.name}}", "${file.name}[private]" ) + pluginSharedCL.dependencies = mutableListOf() addURL(file.toURI().toURL()) }