mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-24 20:43:33 +08:00
[console] Load plugins with plugin.yml
This commit is contained in:
parent
bd3f50f848
commit
f14f1a01b6
mirai-console/backend
integration-test/testers
plugin-with-pluginyml-can-use-libraries-while-clinit
plugin-with-pluginyml
resources
src
mirai-console/src
@ -0,0 +1 @@
|
||||
net.mamoe.consoleit.plugin-with-yml:plugin-library:0.0.0
|
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2019-2023 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 net.mamoe.console.itest.pluginwithpluginyml.library
|
||||
|
||||
public object PluginLibrary {
|
||||
@JvmStatic
|
||||
public fun ok() {
|
||||
println("Plugin with plugin.yml using libraries under clinit ok")
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
net.mamoe.consoleit.plugin-with-yml:plugin-library:0.0.0
|
@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2019-2023 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
|
||||
#
|
||||
|
||||
net.mamoe.console.itest.pluginwithpluginyml.clinit.PluginWithPluginYmlClinitTest
|
@ -0,0 +1,5 @@
|
||||
id: net.mamoe.console.itest.plugin-with-yml-can-use-library-while-clinit
|
||||
version: 0.0.0
|
||||
|
||||
dependencies:
|
||||
- net.mamoe.console.itest.plugin-with-yml
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2019-2023 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 net.mamoe.console.itest.pluginwithpluginyml.clinit
|
||||
|
||||
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
||||
|
||||
internal class PluginWithPluginYmlClinitTest : KotlinPlugin() {
|
||||
|
||||
companion object {
|
||||
init {
|
||||
// this is <clinit>
|
||||
|
||||
Thread.dumpStack()
|
||||
Class.forName("net.mamoe.console.itest.pluginwithpluginyml.library.PluginLibrary")
|
||||
.getMethod("ok").invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2019-2023 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
|
||||
#
|
||||
|
||||
net.mamoe.console.itest.pluginwithpluginyml.PluginWithPluginYml
|
@ -0,0 +1,5 @@
|
||||
id: net.mamoe.console.itest.plugin-with-yml
|
||||
version: 0.0.0
|
||||
|
||||
dependencies:
|
||||
- net.mamoe.console.itest.serviceloader
|
@ -0,0 +1,27 @@
|
||||
package net.mamoe.console.itest.pluginwithpluginyml
|
||||
|
||||
import net.mamoe.mirai.console.plugin.PluginManager
|
||||
import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.description
|
||||
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/*
|
||||
* Copyright 2019-2023 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
|
||||
*/
|
||||
|
||||
internal object PluginWithPluginYml : KotlinPlugin() {
|
||||
override fun onEnable() {
|
||||
println(description)
|
||||
println(description.id)
|
||||
val pluginId = description.id
|
||||
|
||||
assertTrue {
|
||||
PluginManager.plugins.first { it.description.id == pluginId } === PluginWithPluginYml
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import net.mamoe.mirai.console.plugin.loader.PluginLoadException
|
||||
import net.mamoe.mirai.console.plugin.name
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.yamlkt.Yaml
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@ -177,7 +178,7 @@ internal class BuiltInJvmPluginLoaderImpl(
|
||||
override fun Sequence<File>.extractPlugins(): List<JvmPlugin> {
|
||||
ensureActive()
|
||||
|
||||
fun Sequence<Map.Entry<File, JvmPluginClassLoaderN>>.findAllInstances(): Sequence<Map.Entry<File, JvmPlugin>> {
|
||||
fun Sequence<Map.Entry<File, JvmPluginClassLoaderN>>.initialize(): Sequence<Map.Entry<File, JvmPluginClassLoaderN>> {
|
||||
return onEach { (_, pluginClassLoader) ->
|
||||
val exportManagers = pluginClassLoader.findServices(
|
||||
ExportManager::class
|
||||
@ -192,7 +193,11 @@ internal class BuiltInJvmPluginLoaderImpl(
|
||||
} else {
|
||||
pluginClassLoader.declaredFilter = exportManagers[0]
|
||||
}
|
||||
}.map { (f, pluginClassLoader) ->
|
||||
}
|
||||
}
|
||||
|
||||
fun Sequence<Map.Entry<File, JvmPluginClassLoaderN>>.findAllInstances(): Sequence<Map.Entry<File, JvmPlugin>> {
|
||||
return map { (f, pluginClassLoader) ->
|
||||
f to pluginClassLoader.findServices(
|
||||
JvmPlugin::class,
|
||||
KotlinPlugin::class,
|
||||
@ -206,19 +211,80 @@ internal class BuiltInJvmPluginLoaderImpl(
|
||||
}
|
||||
}
|
||||
|
||||
fun Map.Entry<File, JvmPluginClassLoaderN>.loadWithoutPluginDescription(): Sequence<Pair<File, JvmPlugin>> {
|
||||
return sequenceOf(this).initialize().findAllInstances().map { (k, v) -> k to v }
|
||||
}
|
||||
|
||||
fun Map.Entry<File, JvmPluginClassLoaderN>.loadWithPluginDescription(description: JvmPluginDescription): Sequence<Pair<File, JvmPlugin>> {
|
||||
val pluginClassLoader = this.value
|
||||
val pluginFile = this.key
|
||||
pluginClassLoader.pluginDescriptionFromPluginResource = description
|
||||
|
||||
val pendingPlugin = object : NotYetLoadedJvmPlugin(
|
||||
description = description,
|
||||
classLoaderN = pluginClassLoader,
|
||||
) {
|
||||
private val plugin by lazy {
|
||||
val services = pluginClassLoader.findServices(
|
||||
JvmPlugin::class,
|
||||
KotlinPlugin::class,
|
||||
JavaPlugin::class
|
||||
).loadAllServices()
|
||||
if (services.isEmpty()) {
|
||||
error("No plugin instance found in $pluginFile")
|
||||
}
|
||||
if (services.size > 1) {
|
||||
error(
|
||||
"Only one plugin can exist at the same time when using plugin.yml:\n\nPlugins found:\n" + services.joinToString(
|
||||
separator = "\n"
|
||||
) { it.javaClass.name + " (from " + it.javaClass.classLoader + ")" }
|
||||
)
|
||||
}
|
||||
|
||||
return@lazy services[0]
|
||||
}
|
||||
|
||||
override fun resolve(): JvmPlugin = plugin
|
||||
}
|
||||
pluginClassLoader.linkedLogger = pendingPlugin.logger
|
||||
|
||||
|
||||
return sequenceOf(pluginFile to pendingPlugin)
|
||||
}
|
||||
|
||||
val filePlugins = this.filterNot {
|
||||
pluginFileToInstanceMap.containsKey(it)
|
||||
}.associateWith {
|
||||
JvmPluginClassLoaderN.newLoader(it, jvmPluginLoadingCtx)
|
||||
}.onEach { (_, classLoader) ->
|
||||
classLoaders.add(classLoader)
|
||||
}.asSequence().findAllInstances().onEach {
|
||||
//logger.verbose { "Successfully initialized JvmPlugin ${loaded}." }
|
||||
}.asSequence().flatMap { entry ->
|
||||
val (file, pluginClassLoader) = entry
|
||||
|
||||
val pluginDescriptionDefine = pluginClassLoader.getResourceAsStream("plugin.yml")
|
||||
if (pluginDescriptionDefine == null) {
|
||||
entry.loadWithoutPluginDescription()
|
||||
} else {
|
||||
val desc = kotlin.runCatching {
|
||||
pluginDescriptionDefine.bufferedReader().use { resource ->
|
||||
Yaml.decodeFromString(
|
||||
SimpleJvmPluginDescription.SerialData.serializer(),
|
||||
resource.readText()
|
||||
).toJvmPluginDescription()
|
||||
}
|
||||
}.onFailure { err ->
|
||||
throw PluginLoadException("Invalid plugin.yml in " + file.absolutePath, err)
|
||||
}.getOrThrow()
|
||||
|
||||
entry.loadWithPluginDescription(desc)
|
||||
}
|
||||
}.onEach {
|
||||
logger.verbose { "Successfully initialized JvmPlugin ${it.second}." }
|
||||
}.onEach { (file, plugin) ->
|
||||
pluginFileToInstanceMap[file] = plugin
|
||||
} + pluginFileToInstanceMap.asSequence()
|
||||
}
|
||||
|
||||
return filePlugins.toSet().map { it.value }
|
||||
return filePlugins.toSet().map { it.second }
|
||||
}
|
||||
|
||||
private val loadedPlugins = ConcurrentHashMap<JvmPlugin, Unit>()
|
||||
@ -266,9 +332,17 @@ internal class BuiltInJvmPluginLoaderImpl(
|
||||
// move nameFolder in config and data to idFolder
|
||||
PluginManager.pluginsDataPath.moveNameFolder(plugin)
|
||||
PluginManager.pluginsConfigPath.moveNameFolder(plugin)
|
||||
check(plugin is JvmPluginInternal) { "A JvmPlugin must extend AbstractJvmPlugin to be loaded by JvmPluginLoader.BuiltIn" }
|
||||
|
||||
check(plugin is JvmPluginInternal || plugin is NotYetLoadedJvmPlugin) {
|
||||
"A JvmPlugin must extend AbstractJvmPlugin to be loaded by JvmPluginLoader.BuiltIn"
|
||||
}
|
||||
|
||||
|
||||
// region Link dependencies
|
||||
plugin.javaClass.classLoader.safeCast<JvmPluginClassLoaderN>()?.let { jvmPluginClassLoaderN ->
|
||||
when (plugin) {
|
||||
is NotYetLoadedJvmPlugin -> plugin.classLoaderN
|
||||
else -> plugin.javaClass.classLoader
|
||||
}.safeCast<JvmPluginClassLoaderN>()?.let { jvmPluginClassLoaderN ->
|
||||
// Link plugin dependencies
|
||||
plugin.description.dependencies.asSequence().mapNotNull { dependency ->
|
||||
plugin.logger.verbose { "Linking dependency: ${dependency.id}" }
|
||||
@ -282,8 +356,19 @@ internal class BuiltInJvmPluginLoaderImpl(
|
||||
}
|
||||
jvmPluginClassLoaderN.linkPluginLibraries(plugin.logger)
|
||||
}
|
||||
|
||||
val realPlugin = when (plugin) {
|
||||
is NotYetLoadedJvmPlugin -> plugin.resolve().also { realPlugin ->
|
||||
check(plugin.description === realPlugin.description) {
|
||||
"A JvmPlugin loaded by plugin.yml must has same description reference"
|
||||
}
|
||||
}
|
||||
else -> plugin
|
||||
}
|
||||
|
||||
check(realPlugin is JvmPluginInternal) { "A JvmPlugin must extend AbstractJvmPlugin to be loaded by JvmPluginLoader.BuiltIn" }
|
||||
// endregion
|
||||
plugin.internalOnLoad()
|
||||
realPlugin.internalOnLoad()
|
||||
}.getOrElse {
|
||||
throw PluginLoadException("Exception while loading ${plugin.description.smartToString()}", it)
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ package net.mamoe.mirai.console.internal.plugin
|
||||
|
||||
import net.mamoe.mirai.console.plugin.jvm.ExportManager
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginClasspath
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
||||
import net.mamoe.mirai.utils.*
|
||||
import org.eclipse.aether.artifact.Artifact
|
||||
@ -245,6 +246,8 @@ internal class DynLibClassLoader : DynamicClasspathClassLoader {
|
||||
}
|
||||
|
||||
internal class JvmPluginClassLoaderN : URLClassLoader {
|
||||
var pluginDescriptionFromPluginResource: JvmPluginDescription? = null
|
||||
|
||||
val openaccess: JvmPluginClasspath = OpenAccess()
|
||||
val file: File
|
||||
val ctx: JvmPluginsLoadingCtx
|
||||
|
@ -33,6 +33,7 @@ import net.mamoe.mirai.console.plugin.id
|
||||
import net.mamoe.mirai.console.plugin.jvm.AbstractJvmPlugin
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
@ -106,7 +107,13 @@ internal abstract class JvmPluginInternal(
|
||||
}
|
||||
error("Failed to switch plugin '$id' status from $nowStatus to $update, current status = ${pluginStatus.value}")
|
||||
}
|
||||
error("Failed to switch plugin '$id' status to $update because current status $nowStatus doesn't contain flag ${Integer.toBinaryString(expectFlag)}")
|
||||
error(
|
||||
"Failed to switch plugin '$id' status to $update because current status $nowStatus doesn't contain flag ${
|
||||
Integer.toBinaryString(
|
||||
expectFlag
|
||||
)
|
||||
}"
|
||||
)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
@ -364,3 +371,11 @@ internal inline fun AtomicLong.updateWhen(condition: (Long) -> Boolean, update:
|
||||
}
|
||||
|
||||
internal val Throwable.rootCauseOrSelf: Throwable get() = generateSequence(this) { it.cause }.lastOrNull() ?: this
|
||||
|
||||
internal fun Class<out JvmPluginInternal>.loadPluginDescriptionFromClassLoader(): JvmPluginDescription {
|
||||
val classLoader =
|
||||
this.classLoader as? JvmPluginClassLoaderN ?: error("Plugin $this is not loaded by JvmPluginClassLoader")
|
||||
|
||||
return classLoader.pluginDescriptionFromPluginResource ?: error("Missing `plugin.yml`")
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2019-2023 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 net.mamoe.mirai.console.internal.plugin
|
||||
|
||||
import net.mamoe.mirai.console.data.runCatchingLog
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
import net.mamoe.mirai.console.plugin.NotYetLoadedPlugin
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.nio.file.Path
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
internal abstract class NotYetLoadedJvmPlugin(
|
||||
override val description: JvmPluginDescription,
|
||||
val classLoaderN: JvmPluginClassLoaderN,
|
||||
) : JvmPlugin, NotYetLoadedPlugin<JvmPlugin> {
|
||||
abstract override fun resolve(): JvmPlugin
|
||||
|
||||
override val logger: MiraiLogger by lazy {
|
||||
BuiltInJvmPluginLoaderImpl.logger.runCatchingLog {
|
||||
MiraiLogger.Factory.create(NotYetLoadedJvmPlugin::class, this.description.name)
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
override val isEnabled: Boolean get() = false
|
||||
override val parentPermission: Permission
|
||||
get() = error("Not yet loaded")
|
||||
|
||||
override fun permissionId(name: String): PermissionId {
|
||||
return PermissionService.INSTANCE.allocatePermissionIdForPlugin(this, name)
|
||||
}
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = error("Not yet loaded")
|
||||
override val dataFolderPath: Path
|
||||
get() = error("Not yet loaded")
|
||||
override val dataFolder: File
|
||||
get() = error("Not yet loaded")
|
||||
override val configFolderPath: Path
|
||||
get() = error("Not yet loaded")
|
||||
override val configFolder: File
|
||||
get() = error("Not yet loaded")
|
||||
|
||||
override fun getResourceAsStream(path: String): InputStream? {
|
||||
return classLoaderN.getResourceAsStream(path)
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.extensions.PluginLoaderProvider
|
||||
import net.mamoe.mirai.console.internal.data.mkdir
|
||||
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
|
||||
import net.mamoe.mirai.console.plugin.NotYetLoadedPlugin
|
||||
import net.mamoe.mirai.console.plugin.Plugin
|
||||
import net.mamoe.mirai.console.plugin.PluginManager
|
||||
import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.safeLoader
|
||||
@ -94,7 +95,15 @@ internal class PluginManagerImpl(
|
||||
private fun <P : Plugin, D : PluginDescription> PluginLoader<P, D>.loadPluginNoEnable(plugin: P) {
|
||||
kotlin.runCatching {
|
||||
this.load(plugin)
|
||||
resolvedPlugins.add(plugin)
|
||||
|
||||
resolvedPlugins.add(
|
||||
when (plugin) {
|
||||
is NotYetLoadedPlugin<*> -> plugin.resolve()
|
||||
|
||||
else -> plugin
|
||||
}
|
||||
)
|
||||
|
||||
}.fold(
|
||||
onSuccess = {
|
||||
logger.info { "Successfully loaded plugin ${getPluginDescription(plugin).smartToString()}" }
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2019-2023 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 net.mamoe.mirai.console.plugin
|
||||
|
||||
import net.mamoe.mirai.console.plugin.loader.PluginLoader
|
||||
|
||||
/**
|
||||
* 代表一个 未完成加载/延迟加载 的插件
|
||||
*
|
||||
* 此实例仅用于插件加载系统, 当 [PluginManager] 加载插件时会自动调用 [resolve] 解析真正的插件实例
|
||||
*
|
||||
* @see PluginLoader.listPlugins
|
||||
* @see PluginManager
|
||||
*
|
||||
* @since 2.16.0
|
||||
*/
|
||||
public interface NotYetLoadedPlugin<T : Plugin> : Plugin {
|
||||
public fun resolve(): T
|
||||
}
|
@ -16,6 +16,7 @@ import net.mamoe.mirai.console.data.PluginConfig
|
||||
import net.mamoe.mirai.console.data.PluginData
|
||||
import net.mamoe.mirai.console.internal.plugin.JvmPluginClassLoaderN
|
||||
import net.mamoe.mirai.console.internal.plugin.JvmPluginInternal
|
||||
import net.mamoe.mirai.console.internal.plugin.loadPluginDescriptionFromClassLoader
|
||||
import net.mamoe.mirai.console.internal.util.PluginServiceHelper
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
@ -33,9 +34,22 @@ import kotlin.reflect.KClass
|
||||
* @see KotlinPlugin
|
||||
*/
|
||||
@OptIn(ConsoleExperimentalApi::class)
|
||||
public abstract class AbstractJvmPlugin @JvmOverloads constructor(
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
) : JvmPlugin, JvmPluginInternal(parentCoroutineContext), AutoSavePluginDataHolder {
|
||||
public abstract class AbstractJvmPlugin : JvmPluginInternal, JvmPlugin, AutoSavePluginDataHolder {
|
||||
@JvmOverloads
|
||||
public constructor(
|
||||
description: JvmPluginDescription,
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
) : super(parentCoroutineContext) {
|
||||
this.description = description
|
||||
}
|
||||
|
||||
public constructor(parentCoroutineContext: CoroutineContext = EmptyCoroutineContext) : super(parentCoroutineContext) {
|
||||
this.description = javaClass.loadPluginDescriptionFromClassLoader()
|
||||
}
|
||||
|
||||
|
||||
final override val description: JvmPluginDescription
|
||||
|
||||
@ConsoleExperimentalApi
|
||||
public final override val dataHolderName: String
|
||||
get() = this.description.id
|
||||
@ -106,7 +120,7 @@ public abstract class AbstractJvmPlugin @JvmOverloads constructor(
|
||||
* 注: 仅包括当前插件 JAR 的 Service
|
||||
*/
|
||||
@JvmSynthetic
|
||||
protected fun <T: Any> services(kClass: KClass<out T>): Lazy<List<T>> = lazy {
|
||||
protected fun <T : Any> services(kClass: KClass<out T>): Lazy<List<T>> = lazy {
|
||||
val classLoader = try {
|
||||
jvmPluginClasspath.pluginClassLoader
|
||||
} catch (_: IllegalStateException) {
|
||||
@ -127,7 +141,7 @@ public abstract class AbstractJvmPlugin @JvmOverloads constructor(
|
||||
*
|
||||
* 注: 仅包括当前插件 JAR 的 Service
|
||||
*/
|
||||
protected fun <T: Any> services(clazz: Class<out T>): Lazy<List<T>> = services(kClass = clazz.kotlin)
|
||||
protected fun <T : Any> services(clazz: Class<out T>): Lazy<List<T>> = services(kClass = clazz.kotlin)
|
||||
|
||||
/**
|
||||
* 获取 指定类的 SPI Service
|
||||
|
@ -17,10 +17,20 @@ import kotlin.coroutines.EmptyCoroutineContext
|
||||
/**
|
||||
* Java 插件的父类
|
||||
*/
|
||||
public abstract class JavaPlugin @JvmOverloads constructor(
|
||||
public final override val description: JvmPluginDescription,
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||
) : JvmPlugin, AbstractJvmPlugin(parentCoroutineContext) {
|
||||
public abstract class JavaPlugin : JvmPlugin, AbstractJvmPlugin {
|
||||
|
||||
@JvmOverloads
|
||||
public constructor(
|
||||
description: JvmPluginDescription,
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
) : super(description, parentCoroutineContext)
|
||||
|
||||
@JvmOverloads
|
||||
public constructor(
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
) : super(parentCoroutineContext)
|
||||
|
||||
|
||||
init {
|
||||
__jpi_try_to_init_dependencies()
|
||||
}
|
||||
|
@ -17,10 +17,19 @@ import kotlin.coroutines.EmptyCoroutineContext
|
||||
/**
|
||||
* Kotlin 插件的父类.
|
||||
*/
|
||||
public abstract class KotlinPlugin @JvmOverloads constructor(
|
||||
public final override val description: JvmPluginDescription,
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
) : JvmPlugin, AbstractJvmPlugin(parentCoroutineContext) {
|
||||
public abstract class KotlinPlugin : JvmPlugin, AbstractJvmPlugin {
|
||||
@JvmOverloads
|
||||
public constructor(
|
||||
description: JvmPluginDescription,
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
) : super(description, parentCoroutineContext)
|
||||
|
||||
@JvmOverloads
|
||||
public constructor(
|
||||
parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
) : super(parentCoroutineContext)
|
||||
|
||||
|
||||
init {
|
||||
__jpi_try_to_init_dependencies()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user