Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign console plugin loading system #1842

Merged
merged 6 commits into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions buildSrc/src/main/kotlin/DependencyDumper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* 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
*/

import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.tasks.TaskProvider
import java.io.File
import java.util.zip.ZipFile

object DependencyDumper {
fun registerDumpTask(project: Project, confName: String, out: File): TaskProvider<Task> {
return regDmpTask(project, confName) { deps ->
deps.forEach { println(" `- $it") }
out.writeText(deps.joinToString("\n", postfix = "\n"))
}
}

fun registerDumpTaskKtSrc(project: Project, confName: String, out: File, className: String): TaskProvider<Task> {
val pkgName = className.substringBeforeLast(".")
val kname = className.substringAfterLast(".")
return regDmpTask(project, confName) { deps ->
out.printWriter().use { pr ->
pr.println("package $pkgName")
pr.println()
pr.println("internal object $kname {")
pr.println(" val dependencies: List<String> = listOf(")
deps.forEach { dependency ->
pr.append(" \"").append(dependency).println("\",")
}
pr.println(" )")
pr.println("}")
}
}
}

private fun regDmpTask(project: Project, confName: String, action: (List<String>) -> Unit): TaskProvider<Task> {
val dependenciesDump = project.tasks.maybeCreate("dependenciesDump")
dependenciesDump.group = "mirai"
return project.tasks.register("dependenciesDump_${confName.capitalize()}") {
group = "mirai"
doLast {
val dependencies = HashSet<String>()
fun emit(dep: ResolvedDependency) {
if (dependencies.add(dep.moduleGroup + ":" + dep.moduleName)) {
dep.children.forEach { emit(it) }
}
}
project.configurations.getByName(confName).resolvedConfiguration.firstLevelModuleDependencies.forEach { dependency ->
emit(dependency)
}
val stdep = dependencies.toMutableList()
stdep.sort()
action(stdep)
}
}.also { dependenciesDump.dependsOn(it) }
}

fun registerDumpClassGraph(project: Project, confName: String, out: String): TaskProvider<Task> {
val dependenciesDump = project.tasks.maybeCreate("dependenciesDump")
dependenciesDump.group = "mirai"
return project.tasks.register("dependenciesDumpGraph_${confName.capitalize()}") {
group = "mirai"
val outFile = temporaryDir.resolve(out)
outputs.file(outFile)
val conf = project.configurations.getByName(confName)
dependsOn(conf)

doLast {
outFile.parentFile.mkdirs()

val classes = HashSet<String>()
conf.resolvedConfiguration.files.forEach { file ->
if (file.isFile) {
ZipFile(file).use { zipFile ->
zipFile.entries().asSequence()
.filter { it.name.endsWith(".class") }
.filterNot { it.name.startsWith("META-INF") }
.map { it.name.substringBeforeLast('.').replace('/', '.') }
.map { it.removePrefix(".") }
.forEach { classes.add(it) }
}
} else if (file.isDirectory) {
file.walk()
.filter { it.isFile }
.filter { it.name.endsWith(".class") }
.map { it.relativeTo(file).path.substringBeforeLast('.') }
.map { it.replace('\\', '.').replace('/', '.') }
.map { it.removePrefix(".") }
.forEach { classes.add(it) }
}
}
outFile.bufferedWriter().use { writer ->
classes.sorted().forEach { writer.append(it).append('\n') }
}
}
}.also { dependenciesDump.dependsOn(it) }
}
}
8 changes: 8 additions & 0 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ object Versions {
const val difflib = "1.3.0"
const val netty = "4.1.63.Final"
const val bouncycastle = "1.64"
const val mavenArtifactResolver = "1.7.3"
const val mavenResolverProvider = "3.8.4"

const val junit = "5.7.2"

Expand Down Expand Up @@ -151,3 +153,9 @@ const val `caller-finder` = "io.github.karlatemp:caller:1.1.1"
const val `android-runtime` = "com.google.android:android:${Versions.android}"
const val `netty-all` = "io.netty:netty-all:${Versions.netty}"
const val `bouncycastle` = "org.bouncycastle:bcprov-jdk15on:${Versions.bouncycastle}"

const val `maven-resolver-api` = "org.apache.maven.resolver:maven-resolver-api:${Versions.mavenArtifactResolver}"
const val `maven-resolver-impl` = "org.apache.maven.resolver:maven-resolver-impl:${Versions.mavenArtifactResolver}"
const val `maven-resolver-connector-basic` = "org.apache.maven.resolver:maven-resolver-connector-basic:${Versions.mavenArtifactResolver}"
const val `maven-resolver-transport-http` = "org.apache.maven.resolver:maven-resolver-transport-http:${Versions.mavenArtifactResolver}"
const val `maven-resolver-provider` = "org.apache.maven:maven-resolver-provider:${Versions.mavenResolverProvider}"
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package net.mamoe.console.integrationtest

import net.mamoe.console.integrationtest.testpoints.DoNothingPoint
import net.mamoe.console.integrationtest.testpoints.MCITBSelfAssertions
import net.mamoe.console.integrationtest.testpoints.PluginSharedLibraries
import net.mamoe.console.integrationtest.testpoints.plugin.PluginDataRenameToIdTest
import net.mamoe.console.integrationtest.testpoints.terminal.TestTerminalLogging
import org.junit.jupiter.api.Test
Expand All @@ -36,6 +37,7 @@ class MiraiConsoleIntegrationTestBootstrap {
MCITBSelfAssertions,
PluginDataRenameToIdTest,
TestTerminalLogging,
PluginSharedLibraries,
).asSequence().map { v ->
when (v) {
is Class<*> -> v
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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 net.mamoe.console.integrationtest.testpoints

import net.mamoe.console.integrationtest.AbstractTestPoint
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import java.io.File
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream

internal object PluginSharedLibraries : AbstractTestPoint() {
override fun beforeConsoleStartup() {
if (System.getenv("CI").orEmpty().toBoolean()) {
println("CI env")
File("config/Console/PluginDependencies.yml").writeText(
"repoLoc: ['https://repo.maven.apache.org/maven2']"
)
}
File("plugin-shared-libraries").mkdirs()
File("plugin-shared-libraries/libraries.txt").writeText(
"""
io.github.karlatemp:unsafe-accessor:1.6.2
""".trimIndent()
)
ZipOutputStream(File("plugin-shared-libraries/test.jar").outputStream().buffered()).use { zipOutput ->
zipOutput.putNextEntry(ZipEntry("net/mamoe/console/it/psl/PluginSharedLib.class"))
ClassWriter(0).also { writer ->
writer.visit(
Opcodes.V1_8,
0,
"net/mamoe/console/it/psl/PluginSharedLib",
null,
"java/lang/Object",
null
)
}.toByteArray().let { zipOutput.write(it) }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ public object MCITSelfTestPlugin : KotlinPlugin(

assertTrue { true }
}

public fun someAction() {
logger.info { "Called!" }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2019-2021 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/master/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("MCITSelfTestPlugin"))
}
Original file line number Diff line number Diff line change
@@ -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
#

net.mamoe.console.integrationtest.ep.dependonother.PluginDependOnOther
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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 net.mamoe.console.integrationtest.ep.dependonother

import net.mamoe.console.integrationtest.ep.mcitselftest.MCITSelfTestPlugin
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.assertFails
import kotlin.test.assertFailsWith
import kotlin.test.assertNotEquals
import kotlin.test.assertSame

/*
PluginDependOnOther: 测试插件依赖其他插件的情况
*/
public object PluginDependOnOther : KotlinPlugin(
JvmPluginDescription(
id = "net.mamoe.tester.plugin-depend-on-other",
version = "1.0.0",
name = "Plugin Depend On Other",
) {
dependsOn("net.mamoe.tester.mirai-console-self-test")
dependsOn("net.mamoe.tester.plugin-dynamic-dependencies-download")
}
) {
override fun onEnable() {
logger.info { "Do dependency call: " + MCITSelfTestPlugin::class.java }
logger.info { "No Depends on: " + Class.forName("samepkg.P") }
logger.info(Throwable("Stack trace"))
MCITSelfTestPlugin.someAction()
logger.info { "Shared library: " + Class.forName("net.mamoe.console.it.psl.PluginSharedLib") }
assertNotEquals(javaClass.classLoader, Class.forName("net.mamoe.console.it.psl.PluginSharedLib").classLoader)

// dependencies-shared
kotlin.run {
val pluginDepDynDownload = Class.forName("net.mamoe.console.integrationtest.ep.pddd.P")
val gsonC = Class.forName("com.google.gson.Gson")
logger.info { "Gson located $gsonC <${gsonC.classLoader}>" }
assertSame(gsonC, Class.forName(gsonC.name, false, pluginDepDynDownload.classLoader))
assertFailsWith<ClassNotFoundException> {
Class.forName("com.zaxxer.sparsebits.SparseBitSet") // private in dynamic-dep-download
}
assertFailsWith<ClassNotFoundException> {
Class.forName("net.mamoe.assertion.something.not.existing")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
com.zaxxer:SparseBitSet:1.2

## Test console non-hard-link override
org.bouncycastle:bcprov-jdk15on:1.63
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.google.code.gson:gson:2.8.9
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
net.mamoe.console.integrationtest.ep.pddd.P
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 net.mamoe.console.integrationtest.ep.pddd

import net.mamoe.mirai.console.extension.PluginComponentStorage
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
import kotlin.test.assertEquals

/*
PluginDynamicDependenciesDownload: 测试动态运行时下载
*/
internal object P : KotlinPlugin(
JvmPluginDescription(
id = "net.mamoe.tester.plugin-dynamic-dependencies-download",
version = "1.0.0",
name = "Plugin Dynamic Dependencies Download",
)
) {
override fun PluginComponentStorage.onLoad() {
Class.forName("com.google.gson.Gson") // shared
Class.forName("com.zaxxer.sparsebits.SparseBitSet") // private

// console-non-hard-link dependency
// mirai-core used 1.64 current
assertEquals(
"1.63.0",
Class.forName("org.bouncycastle.LICENSE").`package`.implementationVersion
)
}
}
Original file line number Diff line number Diff line change
@@ -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
#

samepkg.P
24 changes: 24 additions & 0 deletions mirai-console/backend/integration-test/testers/same-pkg-1/src/P.kt
Original file line number Diff line number Diff line change
@@ -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 samepkg

import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin

/*
same-pkg-1: 测试包名一样时插件可以正常加载
*/
internal object P : KotlinPlugin(
JvmPluginDescription(
id = "net.mamoe.tester.samepkg-1",
version = "1.0.0",
name = "SamePkg 1",
)
) {}
Original file line number Diff line number Diff line change
@@ -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
#

samepkg.P
Loading