Skip to content

Commit f7613b0

Browse files
committed
Update gradle system
1 parent c9e137b commit f7613b0

File tree

7 files changed

+235
-82
lines changed

7 files changed

+235
-82
lines changed

mirai-console/backend/mirai-console/src/plugin/PluginManager.kt

+6-4
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,20 @@ public interface PluginManager {
8383
public val pluginsConfigFolder: File
8484

8585
/**
86-
* 插件运行时依赖存放路径 [Path]
86+
* 插件运行时依赖存放路径 [Path], 插件自动下载的依赖都会存放于此目录
8787
*
88-
* **实现细节**: 在 terminal 前端实现为 `$rootPath/plugin-libraries`
88+
* **实现细节**: 在 terminal 前端实现为 `$rootPath/plugin-libraries`,
89+
* 依赖 jar 文件由插件共享, 但是运行时插件加载的类是互相隔离的
8990
*
9091
* @since 2.11
9192
*/
9293
public val pluginLibrariesPath: Path
9394

9495
/**
95-
* 插件运行时依赖存放路径 [File]
96+
* 插件运行时依赖存放路径 [File], 插件自动下载的依赖都会存放于此目录
9697
*
97-
* **实现细节**: 在 terminal 前端实现为 `$rootPath/plugin-libraries`
98+
* **实现细节**: 在 terminal 前端实现为 `$rootPath/plugin-libraries`,
99+
* 依赖 jar 文件由插件共享, 但是运行时插件加载的类是互相隔离的
98100
*
99101
* @since 2.11
100102
*/

mirai-console/tools/gradle-plugin/src/integTest/kotlin/AbstractTest.kt

+14
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ package net.mamoe.mirai.console.gradle
1212
import org.gradle.testkit.runner.GradleRunner
1313
import org.gradle.testkit.runner.internal.PluginUnderTestMetadataReading
1414
import org.junit.jupiter.api.BeforeEach
15+
import org.junit.jupiter.api.extension.AfterEachCallback
16+
import org.junit.jupiter.api.extension.RegisterExtension
1517
import org.junit.jupiter.api.io.TempDir
1618
import java.io.File
1719

@@ -91,4 +93,16 @@ abstract class AbstractTest {
9193
// """
9294

9395
}
96+
97+
@JvmField
98+
@RegisterExtension
99+
internal val after: AfterEachCallback = AfterEachCallback { context ->
100+
if (context.executionException.isPresent) {
101+
val inst = context.requiredTestInstance as AbstractTest
102+
println("====================== build.gradle ===========================")
103+
println(inst.tempDir.resolve("build.gradle").readText())
104+
println("==================== settings.gradle ==========================")
105+
println(inst.tempDir.resolve("settings.gradle").readText())
106+
}
107+
}
94108
}

mirai-console/tools/gradle-plugin/src/integTest/kotlin/TestBuildPlugin.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class TestBuildPlugin : AbstractTest() {
2727
""".trimIndent()
2828
)
2929
gradleRunner()
30-
.withArguments("buildPlugin", "--stacktrace")
30+
.withArguments("buildPlugin", "dependencies", "--stacktrace", "--info")
3131
.build()
3232
val jar = tempDir.resolve("build/libs").listFiles()!!.first { it.name.endsWith(".mirai.jar") }
3333
ZipFile(jar).use { zipFile ->
@@ -44,6 +44,7 @@ class TestBuildPlugin : AbstractTest() {
4444
assertTrue { dpPrivate.contains("com.zaxxer:SparseBitSet:1.2") }
4545
assertTrue { dpPrivate.contains("com.google.code.gson:gson:2.8.9") }
4646
}
47+
4748
}
4849

4950
}

mirai-console/tools/gradle-plugin/src/main/kotlin/BuildMiraiPluginNew.kt

-75
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* Copyright 2019-2022 Mamoe Technologies and contributors.
3+
*
4+
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
5+
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
6+
*
7+
* https://github.com/mamoe/mirai/blob/dev/LICENSE
8+
*/
9+
10+
package net.mamoe.mirai.console.gradle
11+
12+
import org.gradle.api.DefaultTask
13+
import org.gradle.api.artifacts.ExternalModuleDependency
14+
import org.gradle.api.artifacts.ResolvedArtifact
15+
import org.gradle.api.artifacts.ResolvedDependency
16+
import org.gradle.api.attributes.AttributeContainer
17+
import org.gradle.api.capabilities.Capability
18+
import org.gradle.api.file.DuplicatesStrategy
19+
import org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration
20+
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ArtifactVisitor
21+
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvableArtifact
22+
import org.gradle.api.internal.file.FileCollectionInternal
23+
import org.gradle.api.internal.file.FileCollectionStructureVisitor
24+
import org.gradle.api.tasks.TaskAction
25+
import org.gradle.internal.DisplayName
26+
import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier
27+
import org.gradle.jvm.tasks.Jar
28+
import org.gradle.kotlin.dsl.create
29+
import org.gradle.kotlin.dsl.get
30+
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
31+
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
32+
import java.io.File
33+
import javax.inject.Inject
34+
35+
public open class BuildMiraiPluginV2 : Jar() {
36+
37+
// @get:Internal
38+
private lateinit var metadataTask: GenMetadataTask
39+
40+
public open class GenMetadataTask
41+
@Inject internal constructor(
42+
@JvmField internal val orgTask: BuildMiraiPluginV2,
43+
) : DefaultTask() {
44+
@TaskAction
45+
internal fun run() {
46+
val runtime = mutableSetOf<String>()
47+
val api = mutableSetOf<String>()
48+
val linkedDependencies = mutableSetOf(
49+
"net.mamoe:mirai-core-api",
50+
"net.mamoe:mirai-core-api-jvm",
51+
"net.mamoe:mirai-core-api-android",
52+
"net.mamoe:mirai-core",
53+
"net.mamoe:mirai-core-jvm",
54+
"net.mamoe:mirai-core-android",
55+
"net.mamoe:mirai-core-utils",
56+
"net.mamoe:mirai-core-utils-jvm",
57+
"net.mamoe:mirai-core-utils-android",
58+
"net.mamoe:mirai-console",
59+
"net.mamoe:mirai-console-terminal",
60+
)
61+
val linkToApi = mutableSetOf<String>()
62+
val shadowedFiles = mutableSetOf<File>()
63+
64+
// TODO: check dependencies
65+
project.configurations.findByName("apiElements")?.allDependencies?.forEach { dep ->
66+
if (dep is ExternalModuleDependency) {
67+
val artId = "${dep.group}:${dep.name}"
68+
linkedDependencies.add(artId)
69+
linkToApi.add(artId)
70+
}
71+
}
72+
project.configurations.findByName("implementation")?.allDependencies?.forEach { dep ->
73+
if (dep is ExternalModuleDependency) {
74+
linkedDependencies.add("${dep.group}:${dep.name}")
75+
}
76+
}
77+
78+
fun ResolvedDependency.depId(): String = "$moduleGroup:$moduleName"
79+
80+
val runtimeClasspath = project.configurations["runtimeClasspath"].resolvedConfiguration
81+
fun markAsResolved(resolvedDependency: ResolvedDependency) {
82+
val depId = resolvedDependency.depId()
83+
linkedDependencies.add(depId)
84+
resolvedDependency.children.forEach { markAsResolved(it) }
85+
}
86+
87+
fun linkDependencyTo(resolvedDependency: ResolvedDependency, dependencies: MutableCollection<String>) {
88+
dependencies.add(resolvedDependency.module.toString())
89+
resolvedDependency.children.forEach { linkDependencyTo(it, dependencies) }
90+
}
91+
92+
fun resolveDependency(resolvedDependency: ResolvedDependency) {
93+
val depId = resolvedDependency.depId()
94+
if (depId in linkedDependencies) {
95+
markAsResolved(resolvedDependency)
96+
linkDependencyTo(resolvedDependency, runtime)
97+
if (depId in linkToApi) {
98+
linkDependencyTo(resolvedDependency, api)
99+
}
100+
return
101+
}
102+
}
103+
runtimeClasspath.firstLevelModuleDependencies.forEach { resolveDependency(it) }
104+
105+
logger.info { "linkedDependencies: $linkedDependencies" }
106+
logger.info { "linkToAPi : $linkToApi" }
107+
logger.info { "api : $api" }
108+
logger.info { "runtime : $runtime" }
109+
110+
val lenientConfiguration = runtimeClasspath.lenientConfiguration
111+
if (lenientConfiguration is DefaultLenientConfiguration) {
112+
val resolvedArtifacts = mutableSetOf<ResolvedArtifact>()
113+
lenientConfiguration.select().visitArtifacts(object : ArtifactVisitor {
114+
override fun prepareForVisit(source: FileCollectionInternal.Source): FileCollectionStructureVisitor.VisitType {
115+
return FileCollectionStructureVisitor.VisitType.Visit
116+
}
117+
118+
override fun visitArtifact(
119+
variantName: DisplayName,
120+
variantAttributes: AttributeContainer,
121+
capabilities: MutableList<out Capability>,
122+
artifact: ResolvableArtifact
123+
) {
124+
resolvedArtifacts.add(artifact.toPublicView())
125+
}
126+
127+
override fun requireArtifactFiles(): Boolean = false
128+
override fun visitFailure(failure: Throwable) {}
129+
}, false)
130+
resolvedArtifacts
131+
} else {
132+
runtimeClasspath.resolvedArtifacts
133+
}.forEach { artifact ->
134+
val artId = artifact.id
135+
if (artId is ModuleComponentArtifactIdentifier) {
136+
val cid = artId.componentIdentifier
137+
if ("${cid.group}:${cid.module}" in linkedDependencies) {
138+
return@forEach
139+
}
140+
}
141+
logger.info { " `- $artId - ${artId.javaClass}" }
142+
shadowedFiles.add(artifact.file)
143+
}
144+
145+
shadowedFiles.forEach { file ->
146+
if (file.isDirectory) {
147+
orgTask.from(file)
148+
} else if (file.extension == "jar") {
149+
orgTask.from(project.zipTree(file))
150+
} else {
151+
orgTask.from(file)
152+
}
153+
}
154+
155+
temporaryDir.also {
156+
it.mkdirs()
157+
}.let { tmpDir ->
158+
tmpDir.resolve("api.txt").writeText(api.sorted().joinToString("\n"))
159+
tmpDir.resolve("runtime.txt").writeText(runtime.sorted().joinToString("\n"))
160+
orgTask.from(tmpDir.resolve("api.txt")) { copy ->
161+
copy.into("META-INF/mirai-console-plugin")
162+
copy.rename { "dependencies-shared.txt" }
163+
}
164+
orgTask.from(tmpDir.resolve("runtime.txt")) { copy ->
165+
copy.into("META-INF/mirai-console-plugin")
166+
copy.rename { "dependencies-private.txt" }
167+
}
168+
}
169+
}
170+
}
171+
172+
@Suppress("RedundantLambdaArrow", "RemoveExplicitTypeArguments")
173+
internal fun init(target: KotlinTarget) {
174+
metadataTask = project.tasks.create<GenMetadataTask>(name + "GenMetadata", this)
175+
dependsOn(metadataTask)
176+
archiveExtension.set("mirai.jar")
177+
duplicatesStrategy = DuplicatesStrategy.WARN
178+
179+
val compilations = target.compilations.filter { it.name == KotlinCompilation.MAIN_COMPILATION_NAME }
180+
compilations.forEach {
181+
dependsOn(it.compileKotlinTask)
182+
from(it.output.allOutputs)
183+
metadataTask.dependsOn(it.compileKotlinTask)
184+
}
185+
exclude { elm ->
186+
elm.path.startsWith("META-INF/") && elm.name.endsWith(".sf", ignoreCase = true)
187+
}
188+
}
189+
}

mirai-console/tools/gradle-plugin/src/main/kotlin/MiraiConsoleGradlePlugin.kt

+8-2
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ public class MiraiConsoleGradlePlugin : Plugin<Project> {
113113
fun registerBuildPluginTask(target: KotlinTarget, isSingleTarget: Boolean) {
114114
tasks.create(
115115
"buildPlugin".wrapNameWithPlatform(target, isSingleTarget),
116-
BuildMiraiPluginNew::class.java
117-
).init()
116+
BuildMiraiPluginV2::class.java
117+
).init(target)
118118
tasks.create(
119119
"buildPluginLegacy".wrapNameWithPlatform(target, isSingleTarget),
120120
BuildMiraiPluginTask::class.java,
@@ -157,6 +157,10 @@ public class MiraiConsoleGradlePlugin : Plugin<Project> {
157157
}
158158
}
159159

160+
private fun Project.setupConfigurations() {
161+
// TODO
162+
}
163+
160164
override fun apply(target: Project): Unit = with(target) {
161165
extensions.create("mirai", MiraiConsoleExtension::class.java)
162166

@@ -166,6 +170,8 @@ public class MiraiConsoleGradlePlugin : Plugin<Project> {
166170
plugins.apply(ShadowPlugin::class.java)
167171
plugins.apply(BintrayPlugin::class.java)
168172

173+
project.setupConfigurations()
174+
169175
afterEvaluate {
170176
configureCompileTarget()
171177
kotlinTargets.forEach { configureTarget(it) }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright 2019-2022 Mamoe Technologies and contributors.
3+
*
4+
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
5+
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
6+
*
7+
* https://github.com/mamoe/mirai/blob/dev/LICENSE
8+
*/
9+
10+
package net.mamoe.mirai.console.gradle
11+
12+
import org.gradle.api.logging.Logger
13+
14+
internal inline fun Logger.info(msg: () -> String) {
15+
if (isInfoEnabled) info(msg())
16+
}

0 commit comments

Comments
 (0)