mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-11 02:50:15 +08:00
Merge remote-tracking branch 'origin/reborn' into reborn
# Conflicts: # backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt
This commit is contained in:
commit
26ebd03300
@ -1,8 +1,6 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
id("kotlin")
|
||||
kotlin("plugin.serialization")
|
||||
kotlin("jvm") version "1.4-M2"
|
||||
kotlin("plugin.serialization") version "1.4-M2"
|
||||
id("java")
|
||||
}
|
||||
|
||||
@ -10,8 +8,10 @@ kotlin {
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||
languageSettings.progressiveMode = true
|
||||
languageSettings.languageVersion = "1.4"
|
||||
languageSettings.apiVersion = "1.4"
|
||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference")
|
||||
@ -21,21 +21,5 @@ kotlin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(kotlin("stdlib"))
|
||||
}
|
||||
|
||||
val compileKotlin: KotlinCompile by tasks
|
||||
compileKotlin.kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
val compileTestKotlin: KotlinCompile by tasks
|
||||
compileTestKotlin.kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
tasks.withType(JavaCompile::class.java) {
|
||||
options.encoding = "UTF8"
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2020 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("FunctionName", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
|
||||
package net.mamoe.mirai.console.codegen
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
abstract class Replacer(private val name: String) : (String) -> String {
|
||||
override fun toString(): String {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
fun Codegen.Replacer(block: (String) -> String): Replacer {
|
||||
return object : Replacer(this@Replacer::class.simpleName ?: "<unnamed>") {
|
||||
override fun invoke(p1: String): String = block(p1)
|
||||
}
|
||||
}
|
||||
|
||||
class CodegenScope : MutableList<Replacer> by mutableListOf() {
|
||||
fun applyTo(fileContent: String): String {
|
||||
return this.fold(fileContent) { acc, replacer -> replacer(acc) }
|
||||
}
|
||||
|
||||
@CodegenDsl
|
||||
operator fun Codegen.invoke(vararg ktTypes: KtType) {
|
||||
if (ktTypes.isEmpty() && this is DefaultInvoke) {
|
||||
invoke(defaultInvokeArgs)
|
||||
}
|
||||
invoke(ktTypes.toList())
|
||||
}
|
||||
|
||||
@CodegenDsl
|
||||
operator fun Codegen.invoke(ktTypes: Collection<KtType>) {
|
||||
add(Replacer {
|
||||
it + buildString {
|
||||
ktTypes.forEach { applyTo(this, it) }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@RegionCodegenDsl
|
||||
operator fun RegionCodegen.invoke(vararg ktTypes: KtType) = invoke(ktTypes.toList())
|
||||
|
||||
@RegionCodegenDsl
|
||||
operator fun RegionCodegen.invoke(ktTypes: Collection<KtType>) {
|
||||
add(Replacer {
|
||||
it.replace(Regex("""//// region $regionName CODEGEN ////([\s\S]*?)//// endregion $regionName CODEGEN ////""")) {
|
||||
val code = CodegenScope().apply { (this@invoke as Codegen).invoke(*ktTypes.toTypedArray()) }.applyTo("")
|
||||
"""
|
||||
|//// region $regionName CODEGEN ////
|
||||
|
|
||||
|$code
|
||||
|
|
||||
|//// endregion $regionName CODEGEN ////
|
||||
""".trimMargin()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@DslMarker
|
||||
annotation class CodegenDsl
|
||||
}
|
||||
|
||||
@DslMarker
|
||||
annotation class RegionCodegenDsl
|
||||
|
||||
interface DefaultInvoke {
|
||||
val defaultInvokeArgs: List<KtType>
|
||||
}
|
||||
|
||||
abstract class Codegen {
|
||||
fun applyTo(stringBuilder: StringBuilder, ktType: KtType) = this.run { stringBuilder.apply(ktType) }
|
||||
|
||||
protected abstract fun StringBuilder.apply(ktType: KtType)
|
||||
}
|
||||
|
||||
abstract class RegionCodegen(regionName: String? = null) : Codegen() {
|
||||
val regionName: String by lazy {
|
||||
regionName ?: this::class.simpleName!!.substringBefore("Codegen")
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PrimitiveCodegen : Codegen() {
|
||||
protected abstract fun StringBuilder.apply(ktType: KtPrimitive)
|
||||
|
||||
fun StringBuilder.apply(ktType: List<KtPrimitive>) = ktType.forEach { apply(it) }
|
||||
}
|
||||
|
||||
fun StringBuilder.appendKCode(@Language("kt") ktCode: String): StringBuilder = append(kCode(ktCode)).appendLine()
|
@ -46,35 +46,37 @@ fun JClazz.getTemplate():String = """
|
||||
|
||||
fun main(){
|
||||
println(buildString {
|
||||
appendln(COPYRIGHT)
|
||||
appendln()
|
||||
appendln(FILE_SUPPRESS)
|
||||
appendln()
|
||||
appendln("/**\n" +
|
||||
" * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JSettingCodegen.kt\n" +
|
||||
" * !!! DO NOT MODIFY THIS FILE MANUALLY\n" +
|
||||
" */\n" +
|
||||
"\"\"\"")
|
||||
appendln()
|
||||
appendln()
|
||||
appendLine(COPYRIGHT)
|
||||
appendLine()
|
||||
appendLine(FILE_SUPPRESS)
|
||||
appendLine()
|
||||
appendLine(
|
||||
"/**\n" +
|
||||
" * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JSettingCodegen.kt\n" +
|
||||
" * !!! DO NOT MODIFY THIS FILE MANUALLY\n" +
|
||||
" */\n" +
|
||||
"\"\"\""
|
||||
)
|
||||
appendLine()
|
||||
appendLine()
|
||||
|
||||
|
||||
//do simplest
|
||||
(J_EXTRA + J_NUMBERS).forEach {
|
||||
appendln(it.getTemplate())
|
||||
appendLine(it.getTemplate())
|
||||
}
|
||||
|
||||
(J_EXTRA + J_NUMBERS).forEach {
|
||||
appendln(JListClazz(it).getTemplate())
|
||||
appendLine(JListClazz(it).getTemplate())
|
||||
}
|
||||
|
||||
(J_EXTRA + J_NUMBERS).forEach {
|
||||
appendln(JArrayClazz(it).getTemplate())
|
||||
appendLine(JArrayClazz(it).getTemplate())
|
||||
}
|
||||
|
||||
(J_EXTRA + J_NUMBERS).forEach {key ->
|
||||
(J_EXTRA + J_NUMBERS).forEach { value ->
|
||||
appendln(JMapClazz(key, value).getTemplate())
|
||||
appendLine(JMapClazz(key, value).getTemplate())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -19,19 +19,19 @@ fun main() {
|
||||
File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Setting.kt").apply {
|
||||
createNewFile()
|
||||
}.writeText(buildString {
|
||||
appendln(COPYRIGHT)
|
||||
appendln()
|
||||
appendln(FILE_SUPPRESS)
|
||||
appendln()
|
||||
appendln(PACKAGE)
|
||||
appendln()
|
||||
appendln(IMPORTS)
|
||||
appendln()
|
||||
appendln()
|
||||
appendln(DO_NOT_MODIFY)
|
||||
appendln()
|
||||
appendln()
|
||||
appendln(genAllValueUseSite())
|
||||
appendLine(COPYRIGHT)
|
||||
appendLine()
|
||||
appendLine(FILE_SUPPRESS)
|
||||
appendLine()
|
||||
appendLine(PACKAGE)
|
||||
appendLine()
|
||||
appendLine(IMPORTS)
|
||||
appendLine()
|
||||
appendLine()
|
||||
appendLine(DO_NOT_MODIFY)
|
||||
appendLine()
|
||||
appendLine()
|
||||
appendLine(genAllValueUseSite())
|
||||
})
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ import kotlin.internal.LowPriorityInOverloadResolution
|
||||
|
||||
fun genAllValueUseSite(): String = buildString {
|
||||
fun appendln(@Language("kt") code: String) {
|
||||
this.appendln(code.trimIndent())
|
||||
this.appendLine(code.trimIndent())
|
||||
}
|
||||
// PRIMITIVE
|
||||
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
||||
@ -83,7 +83,7 @@ fun genAllValueUseSite(): String = buildString {
|
||||
// MUTABLE LIST / MUTABLE SET
|
||||
for (collectionName in listOf("List", "Set")) {
|
||||
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
||||
appendln()
|
||||
appendLine()
|
||||
appendln(
|
||||
"""
|
||||
@JvmName("valueMutable")
|
||||
@ -94,7 +94,7 @@ fun genAllValueUseSite(): String = buildString {
|
||||
}
|
||||
|
||||
// SPECIAL
|
||||
appendln()
|
||||
appendLine()
|
||||
appendln(
|
||||
"""
|
||||
fun <T : Setting> Setting.value(default: T): Value<T> {
|
||||
|
@ -19,17 +19,17 @@ fun main() {
|
||||
File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt").apply {
|
||||
createNewFile()
|
||||
}.writeText(buildString {
|
||||
appendln(COPYRIGHT)
|
||||
appendln()
|
||||
appendln(PACKAGE)
|
||||
appendln()
|
||||
appendln(IMPORTS)
|
||||
appendln()
|
||||
appendln()
|
||||
appendln(DO_NOT_MODIFY)
|
||||
appendln()
|
||||
appendln()
|
||||
appendln(genAllValueImpl())
|
||||
appendLine(COPYRIGHT)
|
||||
appendLine()
|
||||
appendLine(PACKAGE)
|
||||
appendLine()
|
||||
appendLine(IMPORTS)
|
||||
appendLine()
|
||||
appendLine()
|
||||
appendLine(DO_NOT_MODIFY)
|
||||
appendLine()
|
||||
appendLine()
|
||||
appendLine(genAllValueImpl())
|
||||
})
|
||||
}
|
||||
|
||||
@ -52,19 +52,19 @@ import net.mamoe.mirai.console.setting.*
|
||||
|
||||
fun genAllValueImpl(): String = buildString {
|
||||
fun appendln(@Language("kt") code: String) {
|
||||
this.appendln(code.trimIndent())
|
||||
this.appendLine(code.trimIndent())
|
||||
}
|
||||
|
||||
// PRIMITIVE
|
||||
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
||||
appendln(genPrimitiveValueImpl(number, number, "$number.serializer()", false))
|
||||
appendln()
|
||||
appendLine()
|
||||
}
|
||||
|
||||
// PRIMITIVE ARRAYS
|
||||
for (number in NUMBERS + OTHER_PRIMITIVES.filterNot { it == "String" }) {
|
||||
appendln(genPrimitiveValueImpl("${number}Array", "${number}Array", "${number}ArraySerializer()", true))
|
||||
appendln()
|
||||
appendLine()
|
||||
}
|
||||
|
||||
// TYPED ARRAYS
|
||||
@ -77,7 +77,7 @@ fun genAllValueImpl(): String = buildString {
|
||||
true
|
||||
)
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
}
|
||||
|
||||
// PRIMITIVE LISTS / SETS
|
||||
@ -92,11 +92,11 @@ fun genAllValueImpl(): String = buildString {
|
||||
false
|
||||
)
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
// MUTABLE LIST / MUTABLE SET
|
||||
|
||||
@ -141,11 +141,11 @@ fun genAllValueImpl(): String = buildString {
|
||||
}
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
|
||||
appendln(
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.codegen
|
||||
|
||||
|
||||
object ValueKtCodegen {
|
||||
object SettingCodegen {
|
||||
object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke {
|
||||
override val defaultInvokeArgs: List<KtType>
|
||||
get() = KtType.Primitives + KtString
|
||||
|
||||
override fun StringBuilder.apply(ktType: KtType) {
|
||||
@Suppress("ClassName")
|
||||
appendKCode(
|
||||
"""
|
||||
/**
|
||||
* Represents a non-null [$ktType] value.
|
||||
*/
|
||||
interface ${ktType}Value : PrimitiveValue<$ktType>
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
codegen("Value.kt") {
|
||||
SettingCodegen.PrimitiveValuesCodegen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,11 +56,11 @@ internal val OTHER_PRIMITIVES = listOf(
|
||||
|
||||
fun genPublicApi() = buildString {
|
||||
fun appendln(@Language("kt") code: String) {
|
||||
this.appendln(code.trimIndent())
|
||||
this.appendLine(code.trimIndent())
|
||||
}
|
||||
|
||||
appendln(COPYRIGHT.trim())
|
||||
appendln()
|
||||
appendLine()
|
||||
appendln(
|
||||
"""
|
||||
package net.mamoe.mirai.console.setting
|
||||
@ -70,7 +70,7 @@ fun genPublicApi() = buildString {
|
||||
import kotlin.reflect.KProperty
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
appendln(
|
||||
"""
|
||||
/**
|
||||
@ -80,7 +80,7 @@ fun genPublicApi() = buildString {
|
||||
*/
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
appendln(
|
||||
"""
|
||||
@ -107,7 +107,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
}
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
// PRIMITIVES
|
||||
|
||||
@ -127,7 +127,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
appendln(template)
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
for (number in OTHER_PRIMITIVES) {
|
||||
val template = """
|
||||
@ -137,7 +137,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
appendln(template)
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
// ARRAYS
|
||||
|
||||
@ -154,7 +154,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
sealed class PrimitiveArrayValue<T : Any> : ArrayValue<T>()
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
for (number in (NUMBERS + OTHER_PRIMITIVES).filterNot { it == "String" }) {
|
||||
appendln(
|
||||
@ -164,10 +164,10 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
}
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
// TYPED ARRAYS
|
||||
|
||||
@ -178,7 +178,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
}
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
for (number in (NUMBERS + OTHER_PRIMITIVES)) {
|
||||
appendln(
|
||||
@ -188,7 +188,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
)
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
// TYPED LISTS / SETS
|
||||
for (collectionName in listOf("List", "Set")) {
|
||||
@ -207,14 +207,14 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
appendln(template)
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
// SETTING
|
||||
appendln(
|
||||
"""
|
||||
abstract class Setting${collectionName}Value<T: Setting> internal constructor() : Value<${collectionName}<T>>(), ${collectionName}<T>
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
}
|
||||
|
||||
// SETTING VALUE
|
||||
@ -225,7 +225,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
"""
|
||||
)
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
// MUTABLE LIST / MUTABLE SET
|
||||
for (collectionName in listOf("List", "Set")) {
|
||||
@ -235,7 +235,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
"""
|
||||
)
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
|
||||
for (number in (NUMBERS + OTHER_PRIMITIVES)) {
|
||||
appendln(
|
||||
@ -245,17 +245,17 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
||||
)
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
// SETTING
|
||||
appendln(
|
||||
"""
|
||||
abstract class MutableSetting${collectionName}Value<T: Setting> internal constructor() : Value<Mutable${collectionName}<T>>(), Mutable${collectionName}<T>
|
||||
"""
|
||||
)
|
||||
appendln()
|
||||
appendLine()
|
||||
}
|
||||
|
||||
appendln()
|
||||
appendLine()
|
||||
// DYNAMIC
|
||||
|
||||
appendln(
|
||||
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2020 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("NOTHING_TO_INLINE", "MemberVisibilityCanBePrivate", "unused")
|
||||
|
||||
package net.mamoe.mirai.console.codegen
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
import java.io.File
|
||||
|
||||
|
||||
typealias KtByte = KtType.KtPrimitive.KtByte
|
||||
typealias KtShort = KtType.KtPrimitive.KtShort
|
||||
typealias KtInt = KtType.KtPrimitive.KtInt
|
||||
typealias KtLong = KtType.KtPrimitive.KtLong
|
||||
typealias KtFloat = KtType.KtPrimitive.KtFloat
|
||||
typealias KtDouble = KtType.KtPrimitive.KtDouble
|
||||
typealias KtChar = KtType.KtPrimitive.KtChar
|
||||
typealias KtBoolean = KtType.KtPrimitive.KtBoolean
|
||||
|
||||
typealias KtString = KtType.KtString
|
||||
|
||||
typealias KtCollection = KtType.KtCollection
|
||||
typealias KtMap = KtType.KtMap
|
||||
|
||||
typealias KtPrimitive = KtType.KtPrimitive
|
||||
|
||||
|
||||
sealed class KtType {
|
||||
/**
|
||||
* Its classname in standard library
|
||||
*/
|
||||
abstract val standardName: String
|
||||
override fun toString(): String = standardName
|
||||
|
||||
/**
|
||||
* Not Including [String]
|
||||
*/
|
||||
sealed class KtPrimitive(
|
||||
override val standardName: String,
|
||||
val jPrimitiveName: String = standardName.toLowerCase(),
|
||||
val jObjectName: String = standardName
|
||||
) : KtType() {
|
||||
object KtByte : KtPrimitive("Byte")
|
||||
object KtShort : KtPrimitive("Short")
|
||||
object KtInt : KtPrimitive("Int", jObjectName = "Integer")
|
||||
object KtLong : KtPrimitive("Long")
|
||||
|
||||
object KtFloat : KtPrimitive("Float")
|
||||
object KtDouble : KtPrimitive("Double")
|
||||
|
||||
object KtChar : KtPrimitive("Char", jObjectName = "Character")
|
||||
object KtBoolean : KtPrimitive("Boolean")
|
||||
}
|
||||
|
||||
object KtString : KtType() {
|
||||
override val standardName: String get() = "String"
|
||||
}
|
||||
|
||||
/**
|
||||
* [List], [Set]
|
||||
*/
|
||||
data class KtCollection(override val standardName: String) : KtType()
|
||||
|
||||
object KtMap : KtType() {
|
||||
override val standardName: String get() = "Map"
|
||||
}
|
||||
|
||||
companion object {
|
||||
val PrimitiveIntegers = listOf(KtByte, KtShort, KtInt, KtLong)
|
||||
val PrimitiveFloatings = listOf(KtFloat, KtDouble)
|
||||
|
||||
val PrimitiveNumbers = PrimitiveIntegers + PrimitiveFloatings
|
||||
val PrimitiveNonNumbers = listOf(KtChar, KtBoolean)
|
||||
|
||||
val Primitives = PrimitiveNumbers + PrimitiveNonNumbers
|
||||
}
|
||||
}
|
||||
|
||||
operator fun KtType.plus(type: KtType): List<KtType> {
|
||||
return listOf(this, type)
|
||||
}
|
||||
|
||||
val KtType.lowerCaseName: String get() = this.standardName.toLowerCase()
|
||||
|
||||
inline fun kCode(@Language("kt") source: String) = source.trimIndent()
|
||||
|
||||
fun codegen(targetFile: String, block: CodegenScope.() -> Unit) {
|
||||
//// region PrimitiveValue CODEGEN ////
|
||||
//// region PrimitiveValue CODEGEN ////
|
||||
|
||||
targetFile.findFileSmart().also {
|
||||
println("Codegen target: ${it.absolutePath}")
|
||||
}.apply {
|
||||
writeText(
|
||||
CodegenScope().apply(block).also { list ->
|
||||
list.forEach {
|
||||
println("Applying replacement: $it")
|
||||
}
|
||||
}.applyTo(readText())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun String.findFileSmart(): File = kotlin.run {
|
||||
if (contains("/")) { // absolute
|
||||
File(this)
|
||||
} else {
|
||||
val list = File(".").walk().filter { it.name == this }.toList()
|
||||
if (list.isNotEmpty()) return list.single()
|
||||
|
||||
File(".").walk().filter { it.name.contains(this) }.single()
|
||||
}
|
||||
}.also {
|
||||
require(it.exists()) { "file doesn't exist" }
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import upload.Bintray
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
plugins {
|
||||
id("kotlin")
|
||||
kotlin("plugin.serialization")
|
||||
kotlin("jvm") version Versions.kotlin
|
||||
kotlin("plugin.serialization") version Versions.kotlin
|
||||
id("java")
|
||||
`maven-publish`
|
||||
id("com.jfrog.bintray")
|
||||
id("com.jfrog.bintray") version Versions.bintray
|
||||
}
|
||||
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
|
||||
version = Versions.Mirai.console
|
||||
version = Versions.console
|
||||
description = "Console backend for mirai"
|
||||
|
||||
java {
|
||||
@ -56,14 +56,14 @@ kotlin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileAndRuntime("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
||||
compileAndRuntime("net.mamoe:mirai-core:${Versions.core}")
|
||||
compileAndRuntime(kotlin("stdlib"))
|
||||
|
||||
api("net.mamoe.yamlkt:yamlkt:0.3.1")
|
||||
api("org.jetbrains:annotations:19.0.0")
|
||||
api(kotlinx("coroutines-jdk8", Versions.Kotlin.coroutines))
|
||||
api(kotlinx("coroutines-jdk8", Versions.coroutines))
|
||||
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||
testApi(kotlin("stdlib-jdk8"))
|
||||
testApi(kotlin("test"))
|
||||
testApi(kotlin("test-junit5"))
|
||||
@ -76,6 +76,33 @@ tasks {
|
||||
"test"(Test::class) {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
val compileKotlin by getting {}
|
||||
|
||||
val fillBuildConstants by registering {
|
||||
doLast {
|
||||
(compileKotlin as KotlinCompile).source.filter { it.name == "MiraiConsole.kt" }.single().let { file ->
|
||||
file.writeText(file.readText()
|
||||
.replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) {
|
||||
"""
|
||||
val buildDate: Date = Date(${System.currentTimeMillis()}L) // ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").apply {
|
||||
timeZone = TimeZone.getTimeZone("GMT+8")
|
||||
}.format(Date())}
|
||||
""".trimIndent()
|
||||
}
|
||||
.replace(Regex("""const val version: String = "(.*)"""")) {
|
||||
"""
|
||||
const val version: String = "${Versions.console}"
|
||||
""".trimIndent()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"compileKotlin" {
|
||||
dependsOn(fillBuildConstants)
|
||||
}
|
||||
}
|
||||
|
||||
// region PUBLISHING
|
||||
|
@ -105,10 +105,10 @@ public final class JCommandManager {
|
||||
* 解析并执行一个指令
|
||||
*
|
||||
* @param args 接受 {@link String} 或 {@link Message} , 其他对象将会被 {@link Object#toString()}
|
||||
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
||||
* @see CommandExecuteResult
|
||||
* @see #executeCommandAsync(CoroutineScope, CommandSender, Object...)
|
||||
*/
|
||||
public static boolean executeCommand(final @NotNull CommandSender sender, final @NotNull Object... args) throws InterruptedException {
|
||||
public static CommandExecuteResult executeCommand(final @NotNull CommandSender sender, final @NotNull Object... args) throws InterruptedException {
|
||||
Objects.requireNonNull(sender, "sender");
|
||||
Objects.requireNonNull(args, "args");
|
||||
for (Object arg : args) {
|
||||
@ -123,10 +123,10 @@ public final class JCommandManager {
|
||||
*
|
||||
* @param scope 协程作用域 (用于管理协程生命周期). 一般填入 {@link JavaPlugin} 实例.
|
||||
* @param args 接受 {@link String} 或 {@link Message} , 其他对象将会被 {@link Object#toString()}
|
||||
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
||||
* @see CommandExecuteResult
|
||||
* @see #executeCommand(CommandSender, Object...)
|
||||
*/
|
||||
public static CompletableFuture<Boolean> executeCommandAsync(final @NotNull CoroutineScope scope, final @NotNull CommandSender sender, final @NotNull Object... args) {
|
||||
public static CompletableFuture<CommandExecuteResult> executeCommandAsync(final @NotNull CoroutineScope scope, final @NotNull CommandSender sender, final @NotNull Object... args) {
|
||||
Objects.requireNonNull(sender, "sender");
|
||||
Objects.requireNonNull(args, "args");
|
||||
Objects.requireNonNull(scope, "scope");
|
||||
|
@ -13,41 +13,58 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.io.charsets.Charset
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.center.CuiPluginCenter
|
||||
import net.mamoe.mirai.console.center.PluginCenter
|
||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
internal object MiraiConsoleInitializer {
|
||||
internal lateinit var instance: IMiraiConsole
|
||||
|
||||
/** 由前端调用 */
|
||||
internal fun init(instance: IMiraiConsole) {
|
||||
this.instance = instance
|
||||
MiraiConsole.initialize()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
|
||||
@JvmStatic
|
||||
val buildDate: Date = Date(1592799753404L) // 2020-06-22 12:22:33
|
||||
const val version: String = "0.5.1"
|
||||
}
|
||||
|
||||
/**
|
||||
* mirai 控制台实例.
|
||||
*/
|
||||
object MiraiConsole : CoroutineScope, IMiraiConsole {
|
||||
private lateinit var instance: IMiraiConsole
|
||||
val pluginCenter: PluginCenter get() = CuiPluginCenter
|
||||
|
||||
/** 由前端调用 */
|
||||
internal fun init(instance: IMiraiConsole) {
|
||||
this.instance = instance
|
||||
}
|
||||
private val instance: IMiraiConsole
|
||||
get() = MiraiConsoleInitializer.instance
|
||||
|
||||
/**
|
||||
* `mirai-console` build 号
|
||||
*
|
||||
* UTC+8 时间
|
||||
*/
|
||||
@MiraiExperimentalAPI
|
||||
override val build: String
|
||||
get() = instance.build
|
||||
@JvmStatic
|
||||
val buildDate: Date
|
||||
get() = MiraiConsoleBuildConstants.buildDate
|
||||
|
||||
/**
|
||||
* `mirai-console` 版本
|
||||
*/
|
||||
@MiraiExperimentalAPI
|
||||
override val version: String
|
||||
get() = instance.version
|
||||
const val version: String = MiraiConsoleBuildConstants.version
|
||||
|
||||
/**
|
||||
* Console 运行路径
|
||||
@ -79,14 +96,15 @@ object MiraiConsole : CoroutineScope, IMiraiConsole {
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity)
|
||||
|
||||
internal fun initialize() {
|
||||
// Only for initialize
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 前端使用
|
||||
internal interface IMiraiConsole : CoroutineScope {
|
||||
val build: String
|
||||
val version: String
|
||||
|
||||
/**
|
||||
* Console 运行路径
|
||||
*/
|
||||
|
@ -10,8 +10,6 @@
|
||||
package net.mamoe.mirai.console
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.center.CuiPluginCenter
|
||||
import net.mamoe.mirai.console.center.PluginCenter
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
@ -22,11 +20,6 @@ import net.mamoe.mirai.utils.MiraiLogger
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
interface MiraiConsoleFrontEnd {
|
||||
/**
|
||||
* 提供 [PluginCenter]
|
||||
*/
|
||||
val pluginCenter: PluginCenter get() = CuiPluginCenter
|
||||
|
||||
fun loggerFor(identity: String?): MiraiLogger
|
||||
|
||||
/**
|
||||
@ -43,12 +36,6 @@ interface MiraiConsoleFrontEnd {
|
||||
bot: Bot
|
||||
)
|
||||
|
||||
fun pushVersion(
|
||||
consoleVersion: String,
|
||||
consoleBuild: String,
|
||||
coreVersion: String
|
||||
)
|
||||
|
||||
/**
|
||||
* 让 UI 层提供一个输入, 相当于 [readLine]
|
||||
*/
|
||||
|
@ -134,12 +134,14 @@ fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock {
|
||||
* Java 调用方式: `<static> CommandManager.executeCommand(Command)`
|
||||
*
|
||||
* @param messages 接受 [String] 或 [Message], 其他对象将会被 [Any.toString]
|
||||
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
||||
* @see CommandExecuteResult
|
||||
*
|
||||
* @see JCommandManager.executeCommand Java 方法
|
||||
*/
|
||||
suspend fun CommandSender.executeCommand(vararg messages: Any): Boolean {
|
||||
if (messages.isEmpty()) return false
|
||||
suspend fun CommandSender.executeCommand(vararg messages: Any): CommandExecuteResult {
|
||||
if (messages.isEmpty()) return CommandExecuteResult(
|
||||
status = CommandExecuteStatus.EMPTY_COMMAND
|
||||
)
|
||||
return executeCommandInternal(
|
||||
messages,
|
||||
messages[0].let { if (it is SingleMessage) it.toString() else it.toString().substringBefore(' ') })
|
||||
@ -150,12 +152,14 @@ internal inline fun <reified T> List<T>.dropToTypedArray(n: Int): Array<T> = Arr
|
||||
|
||||
/**
|
||||
* 解析并执行一个指令
|
||||
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
||||
* @see CommandExecuteResult
|
||||
*
|
||||
* @see JCommandManager.executeCommand Java 方法
|
||||
*/
|
||||
suspend fun CommandSender.executeCommand(message: MessageChain): Boolean {
|
||||
if (message.isEmpty()) return false
|
||||
suspend fun CommandSender.executeCommand(message: MessageChain): CommandExecuteResult {
|
||||
if (message.isEmpty()) return CommandExecuteResult(
|
||||
status = CommandExecuteStatus.EMPTY_COMMAND
|
||||
)
|
||||
return executeCommandInternal(message, message[0].toString())
|
||||
}
|
||||
|
||||
@ -163,9 +167,63 @@ suspend fun CommandSender.executeCommand(message: MessageChain): Boolean {
|
||||
internal suspend inline fun CommandSender.executeCommandInternal(
|
||||
messages: Any,
|
||||
commandName: String
|
||||
): Boolean {
|
||||
val command = InternalCommandManager.matchCommand(commandName) ?: return false
|
||||
): CommandExecuteResult {
|
||||
val command = InternalCommandManager.matchCommand(commandName) ?: return CommandExecuteResult(
|
||||
status = CommandExecuteStatus.COMMAND_NOT_FOUND,
|
||||
commandName = commandName
|
||||
)
|
||||
val rawInput = messages.flattenCommandComponents()
|
||||
command.onCommand(this, rawInput.dropToTypedArray(1))
|
||||
return true
|
||||
}
|
||||
kotlin.runCatching {
|
||||
command.onCommand(this, rawInput.dropToTypedArray(1))
|
||||
}.onFailure {
|
||||
return CommandExecuteResult(
|
||||
status = CommandExecuteStatus.FAILED,
|
||||
commandName = commandName,
|
||||
command = command,
|
||||
exception = it
|
||||
)
|
||||
}
|
||||
return CommandExecuteResult(
|
||||
status = CommandExecuteStatus.SUCCESSFUL,
|
||||
commandName = commandName,
|
||||
command = command
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 命令的执行返回
|
||||
*
|
||||
* @param status 命令最终执行状态
|
||||
* @param exception 命令执行时发生的错误(如果有)
|
||||
* @param command 尝试执行的命令 (status = SUCCESSFUL | FAILED)
|
||||
* @param commandName 尝试执行的命令的名字 (status != EMPTY_COMMAND)
|
||||
*
|
||||
*
|
||||
* @see CommandExecuteStatus
|
||||
*/
|
||||
class CommandExecuteResult(
|
||||
val status: CommandExecuteStatus,
|
||||
val exception: Throwable? = null,
|
||||
val command: Command? = null,
|
||||
val commandName: String? = null
|
||||
) {
|
||||
/**
|
||||
* 命令的执行状态
|
||||
*
|
||||
* 当为 [SUCCESSFUL] 的时候,代表命令执行成功
|
||||
*
|
||||
* 当为 [FAILED] 的时候, 代表命令执行出现了错误
|
||||
*
|
||||
* 当为 [COMMAND_NOT_FOUND] 的时候,代表没有匹配的命令
|
||||
*
|
||||
* 当为 [EMPTY_COMMAND] 的时候, 代表尝试执行 ""
|
||||
*
|
||||
*/
|
||||
enum class CommandExecuteStatus {
|
||||
SUCCESSFUL, FAILED, COMMAND_NOT_FOUND, EMPTY_COMMAND
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Suppress("RemoveRedundantQualifierName")
|
||||
typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus
|
||||
|
@ -16,7 +16,7 @@ import java.net.URLClassLoader
|
||||
internal class PluginsLoader(private val parentClassLoader: ClassLoader) {
|
||||
private val loggerName = "PluginsLoader"
|
||||
private val pluginLoaders = linkedMapOf<String, PluginClassLoader>()
|
||||
private val classesCache = mutableMapOf<String,Class<*>>()
|
||||
private val classesCache = mutableMapOf<String, Class<*>>()
|
||||
private val logger = MiraiConsole.newLogger(loggerName)
|
||||
|
||||
/**
|
||||
@ -34,7 +34,7 @@ internal class PluginsLoader(private val parentClassLoader: ClassLoader) {
|
||||
} catch (e: Throwable) {
|
||||
logger.error("Plugin(${plugin.key}) can't not close its ClassLoader(${cl})", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
classesCache.clear()
|
||||
}
|
||||
|
||||
@ -93,9 +93,9 @@ internal class PluginsLoader(private val parentClassLoader: ClassLoader) {
|
||||
* A Adapted URL Class Loader that supports Android and JVM for single URL(File) Class Load
|
||||
*/
|
||||
|
||||
internal open class AdaptiveURLClassLoader(file: File, parent: ClassLoader):ClassLoader(){
|
||||
internal open class AdaptiveURLClassLoader(file: File, parent: ClassLoader) : ClassLoader() {
|
||||
|
||||
private val internalClassLoader:ClassLoader by lazy {
|
||||
private val internalClassLoader: ClassLoader by lazy {
|
||||
kotlin.runCatching {
|
||||
val loaderClass = Class.forName("dalvik.system.PathClassLoader")
|
||||
loaderClass.getConstructor(String::class.java, ClassLoader::class.java)
|
||||
@ -110,19 +110,19 @@ internal open class AdaptiveURLClassLoader(file: File, parent: ClassLoader):Clas
|
||||
}
|
||||
|
||||
|
||||
private val internalClassCache = mutableMapOf<String,Class<*>>()
|
||||
private val internalClassCache = mutableMapOf<String, Class<*>>()
|
||||
|
||||
internal val classesCache:Map<String,Class<*>>
|
||||
internal val classesCache: Map<String, Class<*>>
|
||||
get() = internalClassCache
|
||||
|
||||
internal fun addClassCache(string: String, clazz: Class<*>){
|
||||
synchronized(internalClassCache){
|
||||
internal fun addClassCache(string: String, clazz: Class<*>) {
|
||||
synchronized(internalClassCache) {
|
||||
internalClassCache[string] = clazz
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun close(){
|
||||
fun close() {
|
||||
if (internalClassLoader is URLClassLoader) {
|
||||
(internalClassLoader as URLClassLoader).close()
|
||||
}
|
||||
@ -135,24 +135,25 @@ internal class PluginClassLoader(
|
||||
file: File,
|
||||
private val pluginsLoader: PluginsLoader,
|
||||
parent: ClassLoader
|
||||
) :AdaptiveURLClassLoader(file,parent){
|
||||
) : AdaptiveURLClassLoader(file, parent) {
|
||||
|
||||
override fun findClass(name: String): Class<*> {
|
||||
return findClass(name,true)
|
||||
return findClass(name, true)
|
||||
}
|
||||
|
||||
fun findClass(name: String, global: Boolean = true): Class<*>{
|
||||
return classesCache[name]?: kotlin.run {
|
||||
fun findClass(name: String, global: Boolean = true): Class<*> {
|
||||
return classesCache[name] ?: kotlin.run {
|
||||
var clazz: Class<*>? = null
|
||||
if (global) {
|
||||
clazz = pluginsLoader.findClassByName(name)
|
||||
}
|
||||
if(clazz == null) {
|
||||
if (clazz == null) {
|
||||
clazz = loadClass(name)//这里应该是find, 如果不行就要改
|
||||
}
|
||||
pluginsLoader.addClassCache(name, clazz)
|
||||
this.addClassCache(name, clazz)
|
||||
clazz
|
||||
this.addClassCache(name, clazz)
|
||||
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
|
||||
clazz!! // compiler bug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2020 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("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS")
|
||||
|
||||
package net.mamoe.mirai.console.setting
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import net.mamoe.mirai.console.setting.internal.cast
|
||||
import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl
|
||||
import net.mamoe.mirai.console.setting.internal.valueImpl
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import java.util.*
|
||||
import kotlin.internal.LowPriorityInOverloadResolution
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
|
||||
// TODO: 2020/6/21 move to JvmPlugin to inherit SettingStorage and CoroutineScope for saving
|
||||
// Shows public APIs such as deciding when to auto-save.
|
||||
abstract class Setting : SettingImpl() {
|
||||
|
||||
operator fun <T> SerializerAwareValue<T>.provideDelegate(
|
||||
thisRef: Any?,
|
||||
property: KProperty<*>
|
||||
): SerializerAwareValue<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
valueNodes.add(Node(property as KProperty<T>, this, this.serializer))
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation for [Setting] including:
|
||||
* - Reflection on Kotlin properties and Java fields
|
||||
* - Auto-saving
|
||||
*/
|
||||
// TODO move to internal package.
|
||||
internal abstract class SettingImpl {
|
||||
internal class Node<T>(
|
||||
val property: KProperty<T>,
|
||||
val value: Value<T>,
|
||||
val updaterSerializer: KSerializer<Unit>
|
||||
)
|
||||
|
||||
internal val valueNodes: MutableList<Node<*>> = Collections.synchronizedList(mutableListOf())
|
||||
|
||||
/**
|
||||
* flatten
|
||||
*/
|
||||
internal fun onValueChanged(value: Value<*>) {
|
||||
// TODO: 2020/6/22
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// region Setting.value primitives CODEGEN ////
|
||||
|
||||
// TODO: 2020/6/19 CODEGEN
|
||||
|
||||
fun Setting.value(default: Int): SerializableValue<Int> = valueImpl(default)
|
||||
|
||||
//// endregion Setting.value primitives CODEGEN ////
|
||||
|
||||
|
||||
/**
|
||||
* Creates a [Value] with reified type.
|
||||
*
|
||||
* @param T reified param type T.
|
||||
* Supports only primitives, Kotlin built-in collections,
|
||||
* and classes that are serializable with Kotlinx.serialization
|
||||
* (typically annotated with [kotlinx.serialization.Serializable])
|
||||
*/
|
||||
@LowPriorityInOverloadResolution
|
||||
@OptIn(ExperimentalStdlibApi::class) // stable in 1.4
|
||||
inline fun <reified T> Setting.valueReified(default: T): SerializableValue<T> = valueFromKTypeImpl(typeOf<T>()).cast()
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
fun <T> Setting.valueFromKType(type: KType): SerializableValue<T> = valueFromKTypeImpl(type).cast()
|
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2020 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("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused", "NOTHING_TO_INLINE")
|
||||
|
||||
package net.mamoe.mirai.console.setting
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import net.mamoe.mirai.console.setting.internal.map
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* Represents a observable, immutable value wrapping.
|
||||
*
|
||||
* The value can be modified by delegation just like Kotlin's `var`, however it can also be done by the user, e.g. changing using the UI frontend.
|
||||
*
|
||||
* Some frequently used types are specially treated with performance enhancement by codegen.
|
||||
*
|
||||
* @see PrimitiveValue
|
||||
* @see CompositeValue
|
||||
*/
|
||||
interface Value<T> {
|
||||
var value: T
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically returned by [Setting.value] functions.
|
||||
*/
|
||||
class SerializableValue<T>(
|
||||
delegate: Value<T>,
|
||||
/**
|
||||
* The serializer used to update and dump [delegate]
|
||||
*/
|
||||
override val serializer: KSerializer<Unit>
|
||||
) : Value<T> by delegate, SerializerAwareValue<T>
|
||||
|
||||
fun <T> Value<T>.serializableValueWith(
|
||||
serializer: KSerializer<T>
|
||||
): SerializableValue<T> {
|
||||
return SerializableValue(this, serializer.map(serializer = { this.value }, deserializer = { this.value = it }))
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SerializableValue
|
||||
*/
|
||||
interface SerializerAwareValue<T> : Value<T> {
|
||||
val serializer: KSerializer<Unit>
|
||||
}
|
||||
|
||||
inline operator fun <T> Value<T>.getValue(mySetting: Any?, property: KProperty<*>): T = value
|
||||
inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
/**
|
||||
* The serializer for a specific kind of [Value].
|
||||
*/
|
||||
typealias ValueSerializer<T> = KSerializer<Value<T>>
|
||||
|
||||
/**
|
||||
* Represents a observable *primitive* value wrapping.
|
||||
*
|
||||
* 9 types that are considered *primitive*:
|
||||
* - Integers: [Byte], [Short], [Int], [Long]
|
||||
* - Floating: [Float], [Double]
|
||||
* - [Boolean]
|
||||
* - [Char], [String]
|
||||
*
|
||||
* Note: The values are actually *boxed* because of the generic type T.
|
||||
* *Primitive* indicates only it is one of the 9 types mentioned above.
|
||||
*/
|
||||
interface PrimitiveValue<T> : Value<T>
|
||||
|
||||
|
||||
//// region PrimitiveValues CODEGEN ////
|
||||
|
||||
/**
|
||||
* Represents a non-null [Byte] value.
|
||||
*/
|
||||
interface ByteValue : PrimitiveValue<Byte>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Short] value.
|
||||
*/
|
||||
interface ShortValue : PrimitiveValue<Short>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Int] value.
|
||||
*/
|
||||
interface IntValue : PrimitiveValue<Int>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Long] value.
|
||||
*/
|
||||
interface LongValue : PrimitiveValue<Long>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Float] value.
|
||||
*/
|
||||
interface FloatValue : PrimitiveValue<Float>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Double] value.
|
||||
*/
|
||||
interface DoubleValue : PrimitiveValue<Double>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Char] value.
|
||||
*/
|
||||
interface CharValue : PrimitiveValue<Char>
|
||||
|
||||
/**
|
||||
* Represents a non-null [Boolean] value.
|
||||
*/
|
||||
interface BooleanValue : PrimitiveValue<Boolean>
|
||||
|
||||
/**
|
||||
* Represents a non-null [String] value.
|
||||
*/
|
||||
interface StringValue : PrimitiveValue<String>
|
||||
|
||||
|
||||
//// endregion PrimitiveValues CODEGEN ////
|
||||
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
interface CompositeValue<T> : Value<T>
|
||||
|
||||
|
||||
/**
|
||||
* Superclass of [CompositeListValue], [PrimitiveListValue].
|
||||
*/
|
||||
interface ListValue<E> : CompositeValue<List<E>>
|
||||
|
||||
/**
|
||||
* Elements can by anything, wrapped as [Value].
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface CompositeListValue<E> : ListValue<E>
|
||||
|
||||
/**
|
||||
* Elements can only be primitives, not wrapped.
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface PrimitiveListValue<E> : ListValue<E>
|
||||
|
||||
|
||||
//// region PrimitiveListValue CODEGEN ////
|
||||
|
||||
interface PrimitiveIntListValue : PrimitiveListValue<Int>
|
||||
interface PrimitiveLongListValue : PrimitiveListValue<Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveListValue CODEGEN ////
|
||||
|
||||
|
||||
/**
|
||||
* Superclass of [CompositeSetValue], [PrimitiveSetValue].
|
||||
*/
|
||||
interface SetValue<E> : CompositeValue<Set<E>>
|
||||
|
||||
/**
|
||||
* Elements can by anything, wrapped as [Value].
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface CompositeSetValue<E> : SetValue<E>
|
||||
|
||||
/**
|
||||
* Elements can only be primitives, not wrapped.
|
||||
* @param E is not primitive types.
|
||||
*/
|
||||
interface PrimitiveSetValue<E> : SetValue<E>
|
||||
|
||||
|
||||
//// region PrimitiveSetValue CODEGEN ////
|
||||
|
||||
interface PrimitiveIntSetValue : PrimitiveSetValue<Int>
|
||||
interface PrimitiveLongSetValue : PrimitiveSetValue<Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveSetValue CODEGEN ////
|
||||
|
||||
|
||||
/**
|
||||
* Superclass of [CompositeMapValue], [PrimitiveMapValue].
|
||||
*/
|
||||
interface MapValue<K, V> : CompositeValue<Map<K, V>>
|
||||
|
||||
interface CompositeMapValue<K, V> : MapValue<K, V>
|
||||
|
||||
interface PrimitiveMapValue<K, V> : MapValue<K, V>
|
||||
|
||||
|
||||
//// region PrimitiveMapValue CODEGEN ////
|
||||
|
||||
interface PrimitiveIntIntMapValue : PrimitiveMapValue<Int, Int>
|
||||
interface PrimitiveIntLongMapValue : PrimitiveMapValue<Int, Long>
|
||||
// TODO + codegen
|
||||
|
||||
//// endregion PrimitiveSetValue CODEGEN ////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2020 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("unused")
|
||||
|
||||
package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import net.mamoe.mirai.console.setting.*
|
||||
|
||||
|
||||
// type inference bug
|
||||
internal fun <T> Setting.createCompositeSetValueImpl(tToValue: (T) -> Value<T>): CompositeSetValueImpl<T> {
|
||||
return object : CompositeSetValueImpl<T>(tToValue) {
|
||||
override fun onChanged() {
|
||||
this@createCompositeSetValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class CompositeSetValueImpl<T>(
|
||||
tToValue: (T) -> Value<T> // should override onChanged
|
||||
) : CompositeSetValue<T> {
|
||||
private val internalSet: MutableSet<Value<T>> = mutableSetOf()
|
||||
|
||||
private var _value: Set<T> = internalSet.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
||||
|
||||
override var value: Set<T>
|
||||
get() = _value
|
||||
set(v) {
|
||||
if (_value != v) {
|
||||
onChanged()
|
||||
_value = v
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun onChanged()
|
||||
}
|
||||
|
||||
|
||||
// type inference bug
|
||||
internal fun <T> Setting.createCompositeListValueImpl(tToValue: (T) -> Value<T>): CompositeListValueImpl<T> {
|
||||
return object : CompositeListValueImpl<T>(tToValue) {
|
||||
override fun onChanged() {
|
||||
this@createCompositeListValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class CompositeListValueImpl<T>(
|
||||
tToValue: (T) -> Value<T> // should override onChanged
|
||||
) : CompositeListValue<T> {
|
||||
private val internalList: MutableList<Value<T>> = mutableListOf()
|
||||
|
||||
private var _value: List<T> = internalList.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
||||
|
||||
override var value: List<T>
|
||||
get() = _value
|
||||
set(v) {
|
||||
if (_value != v) {
|
||||
onChanged()
|
||||
_value = v
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun onChanged()
|
||||
}
|
||||
|
||||
// workaround to a type inference bug
|
||||
internal fun <K, V> Setting.createCompositeMapValueImpl(
|
||||
kToValue: (K) -> Value<K>,
|
||||
vToValue: (V) -> Value<V>
|
||||
): CompositeMapValueImpl<K, V> {
|
||||
return object : CompositeMapValueImpl<K, V>(kToValue, vToValue) {
|
||||
override fun onChanged() {
|
||||
this@createCompositeMapValueImpl.onValueChanged(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class CompositeMapValueImpl<K, V>(
|
||||
kToValue: (K) -> Value<K>, // should override onChanged
|
||||
vToValue: (V) -> Value<V> // should override onChanged
|
||||
) : CompositeMapValue<K, V> {
|
||||
private val internalList: MutableMap<Value<K>, Value<V>> = mutableMapOf()
|
||||
|
||||
private var _value: Map<K, V> =
|
||||
internalList.shadowMap({ it.value }, kToValue, { it.value }, vToValue).observable { onChanged() }
|
||||
override var value: Map<K, V>
|
||||
get() = _value
|
||||
set(v) {
|
||||
if (_value != v) {
|
||||
onChanged()
|
||||
_value = v
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun onChanged()
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2020 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("NOTHING_TO_INLINE")
|
||||
|
||||
package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.builtins.*
|
||||
import net.mamoe.mirai.console.setting.SerializableValue
|
||||
import net.mamoe.mirai.console.setting.Setting
|
||||
import net.mamoe.mirai.console.setting.serializableValueWith
|
||||
import net.mamoe.mirai.console.setting.valueFromKType
|
||||
import net.mamoe.yamlkt.YamlDynamicSerializer
|
||||
import net.mamoe.yamlkt.YamlNullableDynamicSerializer
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
|
||||
@PublishedApi
|
||||
@Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE", "UNCHECKED_CAST")
|
||||
internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> {
|
||||
val classifier = type.classifier
|
||||
require(classifier is KClass<*>)
|
||||
|
||||
if (classifier.isPrimitiveOrBuiltInSerializableValue()) {
|
||||
TODO("是基础类型, 可以直接创建 ValueImpl. ")
|
||||
}
|
||||
|
||||
// 复合类型
|
||||
|
||||
when (classifier) {
|
||||
Map::class -> {
|
||||
val keyClass = type.arguments[0].type?.classifier
|
||||
require(keyClass is KClass<*>)
|
||||
|
||||
val valueClass = type.arguments[1].type?.classifier
|
||||
require(valueClass is KClass<*>)
|
||||
|
||||
if (keyClass.isPrimitiveOrBuiltInSerializableValue() && valueClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||
// PrimitiveIntIntMap
|
||||
// ...
|
||||
TODO()
|
||||
} else {
|
||||
return createCompositeMapValueImpl<Any?, Any?>(
|
||||
kToValue = { valueFromKType(type.arguments[0].type!!) },
|
||||
vToValue = { valueFromKType(type.arguments[1].type!!) }
|
||||
).serializableValueWith(serializerMirai(type) as KSerializer<Map<Any?, Any?>>) // erased
|
||||
}
|
||||
}
|
||||
List::class -> {
|
||||
val elementClass = type.arguments[0].type?.classifier
|
||||
require(elementClass is KClass<*>)
|
||||
|
||||
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||
// PrimitiveIntList
|
||||
// ...
|
||||
TODO()
|
||||
} else {
|
||||
return createCompositeListValueImpl<Any?> { valueFromKType(type.arguments[0].type!!) }
|
||||
.serializableValueWith(serializerMirai(type) as KSerializer<List<Any?>>)
|
||||
}
|
||||
}
|
||||
Set::class -> {
|
||||
val elementClass = type.arguments[0].type?.classifier
|
||||
require(elementClass is KClass<*>)
|
||||
|
||||
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||
// PrimitiveIntSet
|
||||
// ...
|
||||
TODO()
|
||||
} else {
|
||||
return createCompositeSetValueImpl<Any?> { valueFromKType(type.arguments[0].type!!) }
|
||||
.serializableValueWith(serializerMirai(type) as KSerializer<Set<Any?>>)
|
||||
}
|
||||
}
|
||||
else -> error("Custom composite value is not supported yet (${classifier.qualifiedName})")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean {
|
||||
return false // debug
|
||||
when (this) {
|
||||
Byte::class, Short::class, Int::class, Long::class,
|
||||
Boolean::class,
|
||||
Char::class, String::class,
|
||||
Pair::class, Triple::class
|
||||
-> return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal inline fun <R, T> T.cast(): R = this as R
|
||||
|
||||
/**
|
||||
* Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
|
||||
* Copyright 2017-2020 JetBrains s.r.o.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST", "NO_REFLECTION_IN_CLASS_PATH", "UNSUPPORTED", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
@OptIn(ImplicitReflectionSerializer::class)
|
||||
internal fun serializerMirai(type: KType): KSerializer<Any?> {
|
||||
fun serializerByKTypeImpl(type: KType): KSerializer<Any> {
|
||||
val rootClass = when (val t = type.classifier) {
|
||||
is KClass<*> -> t
|
||||
else -> error("Only KClass supported as classifier, got $t")
|
||||
} as KClass<Any>
|
||||
|
||||
val typeArguments = type.arguments
|
||||
.map { requireNotNull(it.type) { "Star projections are not allowed, had $it instead" } }
|
||||
return when {
|
||||
typeArguments.isEmpty() -> rootClass.serializer()
|
||||
else -> {
|
||||
val serializers = typeArguments
|
||||
.map(::serializer)
|
||||
// Array is not supported, see KT-32839
|
||||
when (rootClass) {
|
||||
List::class, MutableList::class, ArrayList::class -> ListSerializer(serializers[0])
|
||||
HashSet::class -> SetSerializer(serializers[0])
|
||||
Set::class, MutableSet::class, LinkedHashSet::class -> SetSerializer(serializers[0])
|
||||
HashMap::class -> MapSerializer(serializers[0], serializers[1])
|
||||
Map::class, MutableMap::class, LinkedHashMap::class -> MapSerializer(serializers[0], serializers[1])
|
||||
Map.Entry::class -> MapEntrySerializer(serializers[0], serializers[1])
|
||||
Pair::class -> PairSerializer(serializers[0], serializers[1])
|
||||
Triple::class -> TripleSerializer(serializers[0], serializers[1], serializers[2])
|
||||
/* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
|
||||
else -> {
|
||||
if (isReferenceArray(type, rootClass)) {
|
||||
return ArraySerializer(typeArguments[0].classifier as KClass<Any>, serializers[0]).cast()
|
||||
}
|
||||
requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
|
||||
"Can't find a method to construct serializer for type ${rootClass.simpleName()}. " +
|
||||
"Make sure this class is marked as @Serializable or provide serializer explicitly."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.cast()
|
||||
}
|
||||
|
||||
val result = serializerByKTypeImpl(type)
|
||||
return if (type.isMarkedNullable) result.nullable else result.cast()
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import net.mamoe.mirai.console.setting.IntValue
|
||||
|
||||
|
||||
//// region PrimitiveValues CODEGEN ////
|
||||
|
||||
// TODO: 2020/6/21 CODEGEN
|
||||
|
||||
internal abstract class IntValueImpl : IntValue {
|
||||
constructor()
|
||||
constructor(default: Int) {
|
||||
_value = default
|
||||
}
|
||||
|
||||
private var _value: Int? = null
|
||||
|
||||
override var value: Int
|
||||
get() = _value ?: throw IllegalStateException("IntValue should be initialized before get.")
|
||||
set(v) {
|
||||
if (v != this._value) {
|
||||
this._value = v
|
||||
onChanged()
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun onChanged()
|
||||
}
|
||||
|
||||
//// endregion PrimitiveValues CODEGEN ////
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import net.mamoe.mirai.console.setting.SerializableValue
|
||||
import net.mamoe.mirai.console.setting.Setting
|
||||
|
||||
|
||||
//// region Setting.value primitives impl CODEGEN ////
|
||||
|
||||
// TODO: 2020/6/21 CODEGEN
|
||||
|
||||
internal fun Setting.valueImpl(default: Int): SerializableValue<Int> {
|
||||
val instance = object : IntValueImpl(default) {
|
||||
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||
}
|
||||
return SerializableValue(instance, Int.serializer().map(
|
||||
serializer = { instance.value },
|
||||
deserializer = { instance.value = it }
|
||||
))
|
||||
}
|
||||
|
||||
//// endregion Setting.value primitives impl CODEGEN ////
|
@ -7,6 +7,8 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:Suppress("DuplicatedCode")
|
||||
|
||||
package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||
@ -14,7 +16,89 @@ import kotlinx.serialization.serializer
|
||||
import net.mamoe.yamlkt.Yaml
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal fun <E, R> MutableList<E>.shadowMap(transform: (E) -> R, transformBack: (R) -> E): MutableList<R> {
|
||||
internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
|
||||
crossinline kTransform: (K) -> KR,
|
||||
crossinline kTransformBack: (KR) -> K,
|
||||
crossinline vTransform: (V) -> VR,
|
||||
crossinline vTransformBack: (VR) -> V
|
||||
): MutableMap<KR, VR> {
|
||||
return object : MutableMap<KR, VR> {
|
||||
override val size: Int get() = this@shadowMap.size
|
||||
override fun containsKey(key: KR): Boolean = this@shadowMap.containsKey(key.let(kTransformBack))
|
||||
override fun containsValue(value: VR): Boolean = this@shadowMap.containsValue(value.let(vTransformBack))
|
||||
override fun get(key: KR): VR? = this@shadowMap[key.let(kTransformBack)]?.let(vTransform)
|
||||
override fun isEmpty(): Boolean = this@shadowMap.isEmpty()
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<KR, VR>>
|
||||
get() = this@shadowMap.entries.shadowMap(
|
||||
transform = { entry: MutableMap.MutableEntry<K, V> ->
|
||||
object : MutableMap.MutableEntry<KR, VR> {
|
||||
override val key: KR get() = entry.key.let(kTransform)
|
||||
override val value: VR get() = entry.value.let(vTransform)
|
||||
override fun setValue(newValue: VR): VR =
|
||||
entry.setValue(newValue.let(vTransformBack)).let(vTransform)
|
||||
}
|
||||
} as ((MutableMap.MutableEntry<K, V>) -> MutableMap.MutableEntry<KR, VR>), // type inference bug
|
||||
transformBack = { entry ->
|
||||
object : MutableMap.MutableEntry<K, V> {
|
||||
override val key: K get() = entry.key.let(kTransformBack)
|
||||
override val value: V get() = entry.value.let(vTransformBack)
|
||||
override fun setValue(newValue: V): V =
|
||||
entry.setValue(newValue.let(vTransform)).let(vTransformBack)
|
||||
}
|
||||
}
|
||||
)
|
||||
override val keys: MutableSet<KR>
|
||||
get() = this@shadowMap.keys.shadowMap(kTransform, kTransformBack)
|
||||
override val values: MutableCollection<VR>
|
||||
get() = this@shadowMap.values.shadowMap(vTransform, vTransformBack)
|
||||
|
||||
override fun clear() = this@shadowMap.clear()
|
||||
override fun put(key: KR, value: VR): VR? =
|
||||
this@shadowMap.put(key.let(kTransformBack), value.let(vTransformBack))?.let(vTransform)
|
||||
|
||||
override fun putAll(from: Map<out KR, VR>) {
|
||||
from.forEach { (kr, vr) ->
|
||||
this@shadowMap[kr.let(kTransformBack)] = vr.let(vTransformBack)
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(key: KR): VR? = this@shadowMap.remove(key.let(kTransformBack))?.let(vTransform)
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <E, R> MutableCollection<E>.shadowMap(
|
||||
crossinline transform: (E) -> R,
|
||||
crossinline transformBack: (R) -> E
|
||||
): MutableCollection<R> {
|
||||
return object : MutableCollection<R> {
|
||||
override val size: Int get() = this@shadowMap.size
|
||||
|
||||
override fun contains(element: R): Boolean = this@shadowMap.any { it.let(transform) == element }
|
||||
override fun containsAll(elements: Collection<R>): Boolean = elements.all(::contains)
|
||||
override fun isEmpty(): Boolean = this@shadowMap.isEmpty()
|
||||
override fun iterator(): MutableIterator<R> = object : MutableIterator<R> {
|
||||
private val delegate = this@shadowMap.iterator()
|
||||
override fun hasNext(): Boolean = delegate.hasNext()
|
||||
override fun next(): R = delegate.next().let(transform)
|
||||
override fun remove() = delegate.remove()
|
||||
}
|
||||
|
||||
override fun add(element: R): Boolean = this@shadowMap.add(element.let(transformBack))
|
||||
|
||||
override fun addAll(elements: Collection<R>): Boolean = this@shadowMap.addAll(elements.map(transformBack))
|
||||
override fun clear() = this@shadowMap.clear()
|
||||
|
||||
override fun remove(element: R): Boolean = this@shadowMap.removeIf { it.let(transform) == element }
|
||||
override fun removeAll(elements: Collection<R>): Boolean = elements.all(::remove)
|
||||
override fun retainAll(elements: Collection<R>): Boolean = this@shadowMap.retainAll(elements.map(transformBack))
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <E, R> MutableList<E>.shadowMap(
|
||||
crossinline transform: (E) -> R,
|
||||
crossinline transformBack: (R) -> E
|
||||
): MutableList<R> {
|
||||
return object : MutableList<R> {
|
||||
override val size: Int get() = this@shadowMap.size
|
||||
|
||||
@ -78,7 +162,10 @@ internal fun <E, R> MutableList<E>.shadowMap(transform: (E) -> R, transformBack:
|
||||
}
|
||||
|
||||
|
||||
internal fun <E, R> MutableSet<E>.shadowMap(transform: (E) -> R, transformBack: (R) -> E): MutableSet<R> {
|
||||
internal inline fun <E, R> MutableSet<E>.shadowMap(
|
||||
crossinline transform: (E) -> R,
|
||||
crossinline transformBack: (R) -> E
|
||||
): MutableSet<R> {
|
||||
return object : MutableSet<R> {
|
||||
override val size: Int get() = this@shadowMap.size
|
||||
|
||||
@ -102,7 +189,7 @@ internal fun <E, R> MutableSet<E>.shadowMap(transform: (E) -> R, transformBack:
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> dynamicList(supplier: () -> List<T>): List<T> {
|
||||
internal inline fun <T> dynamicList(crossinline supplier: () -> List<T>): List<T> {
|
||||
return object : List<T> {
|
||||
override val size: Int get() = supplier().size
|
||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||
@ -118,7 +205,7 @@ internal fun <T> dynamicList(supplier: () -> List<T>): List<T> {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> dynamicSet(supplier: () -> Set<T>): Set<T> {
|
||||
internal inline fun <T> dynamicSet(crossinline supplier: () -> Set<T>): Set<T> {
|
||||
return object : Set<T> {
|
||||
override val size: Int get() = supplier().size
|
||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||
@ -129,7 +216,7 @@ internal fun <T> dynamicSet(supplier: () -> Set<T>): Set<T> {
|
||||
}
|
||||
|
||||
|
||||
internal fun <T> dynamicMutableList(supplier: () -> MutableList<T>): MutableList<T> {
|
||||
internal inline fun <T> dynamicMutableList(crossinline supplier: () -> MutableList<T>): MutableList<T> {
|
||||
return object : MutableList<T> {
|
||||
override val size: Int get() = supplier().size
|
||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||
@ -156,7 +243,7 @@ internal fun <T> dynamicMutableList(supplier: () -> MutableList<T>): MutableList
|
||||
}
|
||||
|
||||
|
||||
internal fun <T> dynamicMutableSet(supplier: () -> MutableSet<T>): MutableSet<T> {
|
||||
internal inline fun <T> dynamicMutableSet(crossinline supplier: () -> MutableSet<T>): MutableSet<T> {
|
||||
return object : MutableSet<T> {
|
||||
override val size: Int get() = supplier().size
|
||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||
@ -172,6 +259,23 @@ internal fun <T> dynamicMutableSet(supplier: () -> MutableSet<T>): MutableSet<T>
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST", "USELESS_CAST") // type inference bug
|
||||
internal inline fun <K, V> MutableMap<K, V>.observable(crossinline onChanged: () -> Unit): MutableMap<K, V> {
|
||||
return object : MutableMap<K, V>, Map<K, V> by (this as Map<K, V>) {
|
||||
override val keys: MutableSet<K>
|
||||
get() = this@observable.keys.observable(onChanged)
|
||||
override val values: MutableCollection<V>
|
||||
get() = this@observable.values.observable(onChanged)
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() = this@observable.entries.observable(onChanged)
|
||||
|
||||
override fun clear() = this@observable.clear().also { onChanged() }
|
||||
override fun put(key: K, value: V): V? = this@observable.put(key, value).also { onChanged() }
|
||||
override fun putAll(from: Map<out K, V>) = this@observable.putAll(from).also { onChanged() }
|
||||
override fun remove(key: K): V? = this@observable.remove(key).also { onChanged() }
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> Unit): MutableList<T> {
|
||||
return object : MutableList<T> {
|
||||
override val size: Int get() = this@observable.size
|
||||
@ -234,6 +338,31 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <T> MutableCollection<T>.observable(crossinline onChanged: () -> Unit): MutableCollection<T> {
|
||||
return object : MutableCollection<T> {
|
||||
override val size: Int get() = this@observable.size
|
||||
override fun contains(element: T): Boolean = this@observable.contains(element)
|
||||
override fun containsAll(elements: Collection<T>): Boolean = this@observable.containsAll(elements)
|
||||
override fun isEmpty(): Boolean = this@observable.isEmpty()
|
||||
override fun iterator(): MutableIterator<T> = object : MutableIterator<T> {
|
||||
private val delegate = this@observable.iterator()
|
||||
override fun hasNext(): Boolean = delegate.hasNext()
|
||||
override fun next(): T = delegate.next()
|
||||
override fun remove() = delegate.remove().also { onChanged() }
|
||||
}
|
||||
|
||||
override fun add(element: T): Boolean = this@observable.add(element).also { onChanged() }
|
||||
override fun addAll(elements: Collection<T>): Boolean = this@observable.addAll(elements).also { onChanged() }
|
||||
override fun clear() = this@observable.clear().also { onChanged() }
|
||||
override fun remove(element: T): Boolean = this@observable.remove(element).also { onChanged() }
|
||||
override fun removeAll(elements: Collection<T>): Boolean =
|
||||
this@observable.removeAll(elements).also { onChanged() }
|
||||
|
||||
override fun retainAll(elements: Collection<T>): Boolean =
|
||||
this@observable.retainAll(elements).also { onChanged() }
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Unit): MutableSet<T> {
|
||||
return object : MutableSet<T> {
|
||||
override val size: Int get() = this@observable.size
|
||||
|
@ -10,16 +10,9 @@
|
||||
package net.mamoe.mirai.console.setting.internal
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
import net.mamoe.yamlkt.Yaml
|
||||
import net.mamoe.yamlkt.YamlConfiguration
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
|
||||
internal object SettingSerializerMark
|
||||
|
||||
internal val KProperty<*>.serialNameOrPropertyName: String get() = this.findAnnotation<SerialName>()?.value ?: this.name
|
||||
|
||||
internal inline fun <E> KSerializer<E>.bind(
|
@ -18,8 +18,9 @@ object TestCompositeCommand : CompositeCommand(
|
||||
"groupManagement", "grpMgn"
|
||||
) {
|
||||
@SubCommand
|
||||
suspend fun CommandSender.mute(image: Image, target: Member, seconds: Int) {
|
||||
suspend fun CommandSender.mute(image: Image, target: Member, seconds: Int): Boolean {
|
||||
target.mute(seconds)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.setting
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class SettingTest {
|
||||
|
||||
class MySetting : Setting() {
|
||||
val int by value(1)
|
||||
val map by valueReified(mapOf("" to ""))
|
||||
val map2 by valueReified(mapOf("" to mapOf("" to mapOf("" to ""))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPrimitive() {
|
||||
|
||||
}
|
||||
}
|
115
build.gradle.kts
115
build.gradle.kts
@ -1,33 +1,15 @@
|
||||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
import kotlin.math.pow
|
||||
|
||||
tasks.withType(JavaCompile::class.java) {
|
||||
options.encoding = "UTF8"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
maven(url = "https://mirrors.huaweicloud.com/repository/maven")
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath("com.github.jengelman.gradle.plugins:shadow:5.2.0")
|
||||
classpath("org.jetbrains.kotlin:kotlin-serialization:${Versions.Kotlin.stdlib}")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.stdlib}")
|
||||
classpath("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4") // don"t use any other.
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = "net.mamoe"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
maven(url = "https://mirrors.huaweicloud.com/repository/maven")
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
@ -35,97 +17,8 @@ allprojects {
|
||||
|
||||
subprojects {
|
||||
afterEvaluate {
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
val kotlin =
|
||||
(this as ExtensionAware).extensions.getByName("kotlin") as? org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||
?: return@afterEvaluate
|
||||
apply<MiraiConsoleBuildPlugin>()
|
||||
|
||||
tasks.getByName("shadowJar") {
|
||||
doLast {
|
||||
this.outputs.files.forEach {
|
||||
if (it.nameWithoutExtension.endsWith("-all")) {
|
||||
val output = File(
|
||||
it.path.substringBeforeLast(File.separator) + File.separator + it.nameWithoutExtension.substringBeforeLast(
|
||||
"-all"
|
||||
) + "." + it.extension
|
||||
)
|
||||
|
||||
println("Renaming to ${output.path}")
|
||||
if (output.exists()) {
|
||||
output.delete()
|
||||
}
|
||||
|
||||
it.renameTo(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val githubUpload by tasks.creating {
|
||||
group = "mirai"
|
||||
dependsOn(tasks.getByName("shadowJar"))
|
||||
|
||||
doFirst {
|
||||
timeout.set(java.time.Duration.ofHours(3))
|
||||
findLatestFile()?.let { (_, file) ->
|
||||
val filename = file.name
|
||||
println("Uploading file $filename")
|
||||
runCatching {
|
||||
upload.GitHub.upload(
|
||||
file,
|
||||
"https://api.github.com/repos/mamoe/mirai-repo/contents/shadow/${project.name}/$filename",
|
||||
project
|
||||
)
|
||||
}.exceptionOrNull()?.let {
|
||||
System.err.println("GitHub Upload failed")
|
||||
it.printStackTrace() // force show stacktrace
|
||||
throw it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val cuiCloudUpload by tasks.creating {
|
||||
group = "mirai"
|
||||
dependsOn(tasks.getByName("shadowJar"))
|
||||
|
||||
doFirst {
|
||||
timeout.set(java.time.Duration.ofHours(3))
|
||||
findLatestFile()?.let { (_, file) ->
|
||||
val filename = file.name
|
||||
println("Uploading file $filename")
|
||||
runCatching {
|
||||
upload.CuiCloud.upload(
|
||||
file,
|
||||
project
|
||||
)
|
||||
}.exceptionOrNull()?.let {
|
||||
System.err.println("CuiCloud Upload failed")
|
||||
it.printStackTrace() // force show stacktrace
|
||||
throw it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
setJavaCompileTarget()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Project.findLatestFile(): Map.Entry<String, File> {
|
||||
return File(projectDir, "build/libs").walk()
|
||||
.filter { it.isFile }
|
||||
.onEach { println("all files=$it") }
|
||||
.filter { it.name.matches(Regex("""${project.name}-[0-9][0-9]*(\.[0-9]*)*.*\.jar""")) }
|
||||
.onEach { println("matched file: ${it.name}") }
|
||||
.associateBy { it.nameWithoutExtension.substringAfterLast('-') }
|
||||
.onEach { println("versions: $it") }
|
||||
.maxBy { (version, file) ->
|
||||
version.split('.').let {
|
||||
if (it.size == 2) it + "0"
|
||||
else it
|
||||
}.reversed().foldIndexed(0) { index: Int, acc: Int, s: String ->
|
||||
acc + 100.0.pow(index).toInt() * (s.toIntOrNull() ?: 0)
|
||||
}
|
||||
} ?: error("cannot find any file to upload")
|
||||
}
|
||||
}
|
@ -3,7 +3,10 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
@ -24,4 +27,11 @@ dependencies {
|
||||
api(ktor("client-core", "1.3.2"))
|
||||
api(ktor("client-cio", "1.3.2"))
|
||||
api(ktor("client-json", "1.3.2"))
|
||||
|
||||
//api(gradleApi())
|
||||
//compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
|
||||
compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
|
||||
//runtimeOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
|
||||
|
||||
api("com.github.jengelman.gradle.plugins:shadow:6.0.0")
|
||||
}
|
115
buildSrc/src/main/kotlin/MiraiConsoleBuildPlugin.kt
Normal file
115
buildSrc/src/main/kotlin/MiraiConsoleBuildPlugin.kt
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2020 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("UnstableApiUsage")
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.creating
|
||||
import java.io.File
|
||||
import kotlin.math.pow
|
||||
|
||||
class MiraiConsoleBuildPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) = target.run {
|
||||
apply<ShadowPlugin>()
|
||||
|
||||
if (tasks.none { it.name == "shadowJar" }) {
|
||||
return@run
|
||||
}
|
||||
|
||||
tasks.getByName("shadowJar") {
|
||||
doLast {
|
||||
this.outputs.files.forEach {
|
||||
if (it.nameWithoutExtension.endsWith("-all")) {
|
||||
val output = File(
|
||||
it.path.substringBeforeLast(File.separator) + File.separator + it.nameWithoutExtension.substringBeforeLast(
|
||||
"-all"
|
||||
) + "." + it.extension
|
||||
)
|
||||
|
||||
println("Renaming to ${output.path}")
|
||||
if (output.exists()) {
|
||||
output.delete()
|
||||
}
|
||||
|
||||
it.renameTo(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.creating {
|
||||
group = "mirai"
|
||||
dependsOn(tasks.getByName("shadowJar"))
|
||||
|
||||
doFirst {
|
||||
timeout.set(java.time.Duration.ofHours(3))
|
||||
findLatestFile().let { (_, file) ->
|
||||
val filename = file.name
|
||||
println("Uploading file $filename")
|
||||
runCatching {
|
||||
upload.GitHub.upload(
|
||||
file,
|
||||
"https://api.github.com/repos/mamoe/mirai-repo/contents/shadow/${project.name}/$filename",
|
||||
project
|
||||
)
|
||||
}.exceptionOrNull()?.let {
|
||||
System.err.println("GitHub Upload failed")
|
||||
it.printStackTrace() // force show stacktrace
|
||||
throw it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.creating {
|
||||
group = "mirai"
|
||||
dependsOn(tasks.getByName("shadowJar"))
|
||||
|
||||
doFirst {
|
||||
timeout.set(java.time.Duration.ofHours(3))
|
||||
findLatestFile().let { (_, file) ->
|
||||
val filename = file.name
|
||||
println("Uploading file $filename")
|
||||
runCatching {
|
||||
upload.CuiCloud.upload(
|
||||
file,
|
||||
project
|
||||
)
|
||||
}.exceptionOrNull()?.let {
|
||||
System.err.println("CuiCloud Upload failed")
|
||||
it.printStackTrace() // force show stacktrace
|
||||
throw it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.findLatestFile(): Map.Entry<String, File> {
|
||||
return File(projectDir, "build/libs").walk()
|
||||
.filter { it.isFile }
|
||||
.onEach { println("all files=$it") }
|
||||
.filter { it.name.matches(Regex("""${project.name}-[0-9][0-9]*(\.[0-9]*)*.*\.jar""")) }
|
||||
.onEach { println("matched file: ${it.name}") }
|
||||
.associateBy { it.nameWithoutExtension.substringAfterLast('-') }
|
||||
.onEach { println("versions: $it") }
|
||||
.maxBy { (version, _) ->
|
||||
version.split('.').let {
|
||||
if (it.size == 2) it + "0"
|
||||
else it
|
||||
}.reversed().foldIndexed(0) { index: Int, acc: Int, s: String ->
|
||||
acc + 100.0.pow(index).toInt() * (s.toIntOrNull() ?: 0)
|
||||
}
|
||||
} ?: error("cannot find any file to upload")
|
||||
}
|
45
buildSrc/src/main/kotlin/SetCompileTargetPlugin.kt
Normal file
45
buildSrc/src/main/kotlin/SetCompileTargetPlugin.kt
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*/
|
||||
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
fun Any.reflectMethod(name: String, vararg params: KClass<out Any>): Pair<Any, Method> {
|
||||
return this to this::class.java.getMethod(name, *params.map { it.java }.toTypedArray())
|
||||
}
|
||||
|
||||
operator fun Pair<Any, Method>.invoke(vararg args: Any?): Any? {
|
||||
return second.invoke(first, *args)
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE") // or error
|
||||
fun Project.setJavaCompileTarget() {
|
||||
tasks.filter { it.name in arrayOf("compileKotlin", "compileTestKotlin") }.forEach { task ->
|
||||
task
|
||||
.reflectMethod("getKotlinOptions")()!!
|
||||
.reflectMethod("setJvmTarget", String::class)("1.8")
|
||||
}
|
||||
|
||||
|
||||
kotlin.runCatching { // apply only when java plugin is available
|
||||
(extensions.getByName("java") as JavaPluginExtension).run {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile::class.java) {
|
||||
options.encoding = "UTF8"
|
||||
}
|
||||
}
|
||||
}
|
@ -8,18 +8,18 @@
|
||||
*/
|
||||
|
||||
object Versions {
|
||||
object Mirai {
|
||||
const val core = "1.0.0"
|
||||
const val console = "0.5.1"
|
||||
const val consoleGraphical = "0.0.7"
|
||||
const val consoleTerminal = "0.1.0"
|
||||
const val consolePure = "0.1.0"
|
||||
}
|
||||
const val core = "1.1-EA"
|
||||
const val console = "0.5.1"
|
||||
const val consoleGraphical = "0.0.7"
|
||||
const val consoleTerminal = "0.1.0"
|
||||
const val consolePure = "0.1.0"
|
||||
|
||||
object Kotlin {
|
||||
const val stdlib = "1.3.72"
|
||||
const val coroutines = "1.3.7"
|
||||
const val serialization = "0.20.0"
|
||||
const val ktor = "1.3.2"
|
||||
}
|
||||
const val kotlin = "1.3.72"
|
||||
const val coroutines = "1.3.7"
|
||||
const val serialization = "0.20.0"
|
||||
const val ktor = "1.3.2"
|
||||
|
||||
const val androidGradle = "3.6.2"
|
||||
|
||||
const val bintray = "1.8.4"
|
||||
}
|
@ -5,7 +5,7 @@ import org.gradle.kotlin.dsl.DependencyHandlerScope
|
||||
fun DependencyHandlerScope.kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version"
|
||||
|
||||
@Suppress("unused")
|
||||
fun DependencyHandlerScope.ktor(id: String, version: String = Versions.Kotlin.ktor) = "io.ktor:ktor-$id:$version"
|
||||
fun DependencyHandlerScope.ktor(id: String, version: String = Versions.ktor) = "io.ktor:ktor-$id:$version"
|
||||
|
||||
@Suppress("unused")
|
||||
fun DependencyHandler.compileAndRuntime(any: Any) {
|
||||
|
@ -29,17 +29,17 @@ version = Versions.Mirai.consoleGraphical
|
||||
description = "Graphical frontend for mirai-console"
|
||||
|
||||
dependencies {
|
||||
compileOnly("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
||||
compileOnly("net.mamoe:mirai-core:${Versions.core}")
|
||||
implementation(project(":mirai-console"))
|
||||
|
||||
api(group = "no.tornado", name = "tornadofx", version = "1.7.19")
|
||||
api(group = "com.jfoenix", name = "jfoenix", version = "9.0.8")
|
||||
|
||||
testApi(project(":mirai-console"))
|
||||
testApi(kotlinx("coroutines-core", Versions.Kotlin.coroutines))
|
||||
testApi(kotlinx("coroutines-core", Versions.coroutines))
|
||||
testApi(group = "org.yaml", name = "snakeyaml", version = "1.25")
|
||||
testApi("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
||||
testApi("net.mamoe:mirai-core:${Versions.core}")
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
@ -47,7 +47,7 @@ kotlin {
|
||||
all {
|
||||
|
||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||
languageSettings.progressiveMode = true
|
||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||
}
|
||||
|
@ -1,22 +1,18 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
kotlin("plugin.serialization")
|
||||
kotlin("jvm") version Versions.kotlin
|
||||
kotlin("plugin.serialization") version Versions.kotlin
|
||||
id("java")
|
||||
`maven-publish`
|
||||
id("com.jfrog.bintray")
|
||||
id("com.jfrog.bintray") version Versions.bintray
|
||||
}
|
||||
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings.enableLanguageFeature("InlineClasses")
|
||||
|
||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||
languageSettings.progressiveMode = true
|
||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
||||
@ -25,31 +21,19 @@ kotlin {
|
||||
}
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
compileOnly(project(":mirai-console"))
|
||||
compileOnly("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
||||
compileOnly(kotlin("stdlib")) // embedded by core
|
||||
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
||||
dependencies {
|
||||
implementation("org.jline:jline:3.15.0")
|
||||
implementation("org.fusesource.jansi:jansi:1.18")
|
||||
|
||||
compileAndRuntime(project(":mirai-console"))
|
||||
compileAndRuntime("net.mamoe:mirai-core:${Versions.core}")
|
||||
compileAndRuntime(kotlin("stdlib")) // embedded by core
|
||||
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||
testApi(project(":mirai-console"))
|
||||
}
|
||||
|
||||
version = Versions.Mirai.consolePure
|
||||
version = Versions.consolePure
|
||||
|
||||
description = "Console Pure CLI frontend for mirai"
|
||||
|
||||
val compileKotlin: KotlinCompile by tasks
|
||||
compileKotlin.kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
val compileTestKotlin: KotlinCompile by tasks
|
||||
compileTestKotlin.kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
tasks.withType(JavaCompile::class.java) {
|
||||
options.encoding = "UTF8"
|
||||
}
|
||||
description = "Console Pure CLI frontend for mirai"
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.pure
|
||||
|
||||
import org.jline.reader.LineReader
|
||||
import org.jline.reader.LineReaderBuilder
|
||||
import org.jline.reader.impl.completer.NullCompleter
|
||||
import org.jline.terminal.Terminal
|
||||
import org.jline.terminal.TerminalBuilder
|
||||
|
||||
object ConsoleUtils {
|
||||
|
||||
val lineReader: LineReader
|
||||
val terminal: Terminal
|
||||
|
||||
init {
|
||||
|
||||
val dumb = System.getProperty("java.class.path")
|
||||
.contains("idea_rt.jar") || System.getProperty("mirai.idea") !== null
|
||||
|
||||
terminal = TerminalBuilder.builder()
|
||||
.dumb(dumb)
|
||||
.build()
|
||||
lineReader = LineReaderBuilder.builder()
|
||||
.terminal(terminal)
|
||||
.completer(NullCompleter())
|
||||
.build()
|
||||
}
|
||||
}
|
@ -9,20 +9,90 @@
|
||||
|
||||
package net.mamoe.mirai.console.pure
|
||||
|
||||
import kotlinx.coroutines.delay
|
||||
//import net.mamoe.mirai.console.command.CommandManager
|
||||
//import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.command.CommandManager
|
||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.console.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.utils.DefaultLoginSolver
|
||||
import net.mamoe.mirai.utils.LoginSolver
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.PlatformLogger
|
||||
import org.fusesource.jansi.Ansi
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.concurrent.thread
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
private val ANSI_RESET = Ansi().reset().toString()
|
||||
|
||||
internal val LoggerCreator: (identity: String?) -> MiraiLogger = {
|
||||
PlatformLogger(identity = it, output = { line ->
|
||||
ConsoleUtils.lineReader.printAbove(line + ANSI_RESET)
|
||||
})
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
||||
private val globalLogger = LoggerCreator("Mirai")
|
||||
private val cachedLoggers = ConcurrentHashMap<String, MiraiLogger>()
|
||||
|
||||
// companion object {
|
||||
// ANSI color codes
|
||||
const val COLOR_RED = "\u001b[38;5;196m"
|
||||
const val COLOR_CYAN = "\u001b[38;5;87m"
|
||||
const val COLOR_GREEN = "\u001b[38;5;82m"
|
||||
|
||||
// use a dark yellow(more like orange) instead of light one to save Solarized-light users
|
||||
const val COLOR_YELLOW = "\u001b[38;5;220m"
|
||||
const val COLOR_GREY = "\u001b[38;5;244m"
|
||||
const val COLOR_BLUE = "\u001b[38;5;27m"
|
||||
const val COLOR_NAVY = "\u001b[38;5;24m" // navy uniform blue
|
||||
const val COLOR_PINK = "\u001b[38;5;207m"
|
||||
const val COLOR_RESET = "\u001b[39;49m"
|
||||
// }
|
||||
|
||||
val sdf by lazy {
|
||||
SimpleDateFormat("HH:mm:ss")
|
||||
}
|
||||
|
||||
|
||||
override fun loggerFor(identity: String?): MiraiLogger {
|
||||
identity?.apply {
|
||||
return cachedLoggers.computeIfAbsent(this, LoggerCreator)
|
||||
}
|
||||
return globalLogger
|
||||
}
|
||||
|
||||
override fun prePushBot(identity: Long) {
|
||||
}
|
||||
|
||||
override fun pushBot(bot: Bot) {
|
||||
}
|
||||
|
||||
override suspend fun requestInput(hint: String): String {
|
||||
if (hint.isNotEmpty()) {
|
||||
ConsoleUtils.lineReader.printAbove(
|
||||
Ansi.ansi()
|
||||
.fgCyan().a(sdf.format(Date()))
|
||||
.fgMagenta().a(hint)
|
||||
.toString()
|
||||
)
|
||||
}
|
||||
return ConsoleUtils.lineReader.readLine("> ")
|
||||
}
|
||||
|
||||
override fun pushBotAdminStatus(identity: Long, admins: List<Long>) {
|
||||
}
|
||||
|
||||
override fun createLoginSolver(): LoginSolver {
|
||||
return DefaultLoginSolver(
|
||||
input = suspend {
|
||||
requestInput("")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
||||
private var requesting = false
|
||||
private var requestStr = ""
|
||||
@ -106,4 +176,4 @@ class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
||||
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2020 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(
|
||||
"INVISIBLE_MEMBER",
|
||||
"INVISIBLE_REFERENCE",
|
||||
"CANNOT_OVERRIDE_INVISIBLE_MEMBER",
|
||||
"INVISIBLE_SETTER",
|
||||
"INVISIBLE_GETTER",
|
||||
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER",
|
||||
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPE_WARNING"
|
||||
)
|
||||
|
||||
package net.mamoe.mirai.console.pure
|
||||
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import net.mamoe.mirai.console.IMiraiConsole
|
||||
import net.mamoe.mirai.console.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
private val delegateScope = CoroutineScope(EmptyCoroutineContext)
|
||||
|
||||
object MiraiConsolePure : IMiraiConsole {
|
||||
override val builtInPluginLoaders: List<PluginLoader<*, *>> = LinkedList()
|
||||
override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure
|
||||
override val mainLogger: MiraiLogger = DefaultLogger("Console")
|
||||
override val rootDir: File = File("./test/console").also {
|
||||
it.mkdirs()
|
||||
}
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = delegateScope.coroutineContext
|
||||
}
|
@ -7,68 +7,67 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:Suppress(
|
||||
"INVISIBLE_MEMBER",
|
||||
"INVISIBLE_REFERENCE",
|
||||
"CANNOT_OVERRIDE_INVISIBLE_MEMBER",
|
||||
"INVISIBLE_SETTER",
|
||||
"INVISIBLE_GETTER",
|
||||
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER",
|
||||
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPE_WARNING"
|
||||
)
|
||||
|
||||
package net.mamoe.mirai.console.pure
|
||||
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.command.CommandManager
|
||||
import net.mamoe.mirai.console.command.DefaultCommands
|
||||
import net.mamoe.mirai.console.plugins.PluginManager
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||
import net.mamoe.mirai.console.MiraiConsoleInitializer
|
||||
import net.mamoe.mirai.console.command.CommandExecuteStatus
|
||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||
import net.mamoe.mirai.console.command.executeCommand
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class MiraiConsolePureLoader {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun load(
|
||||
coreVersion: String,
|
||||
consoleVersion: String
|
||||
) {
|
||||
start(
|
||||
MiraiConsoleFrontEndPure(),
|
||||
coreVersion,
|
||||
consoleVersion
|
||||
)
|
||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
||||
MiraiConsole.stop()
|
||||
})
|
||||
object MiraiConsolePureLoader {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>?) {
|
||||
startup()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun startup() {
|
||||
MiraiConsoleInitializer.init(MiraiConsolePure)
|
||||
startConsoleThread()
|
||||
}
|
||||
|
||||
internal fun startConsoleThread() {
|
||||
thread(name = "Console", isDaemon = false) {
|
||||
val consoleLogger = DefaultLogger("Console")
|
||||
kotlinx.coroutines.runBlocking {
|
||||
while (true) {
|
||||
val next = MiraiConsoleFrontEndPure.requestInput("")
|
||||
consoleLogger.debug("INPUT> $next")
|
||||
val result = ConsoleCS.executeCommand(PlainText(next))
|
||||
when (result.status) {
|
||||
CommandExecuteStatus.SUCCESSFUL -> {
|
||||
}
|
||||
CommandExecuteStatus.EMPTY_COMMAND -> {
|
||||
}
|
||||
CommandExecuteStatus.FAILED -> {
|
||||
consoleLogger.error("An error occurred while executing the command: $next", result.exception)
|
||||
}
|
||||
CommandExecuteStatus.COMMAND_NOT_FOUND -> {
|
||||
consoleLogger.warning("Unknown command: ${result.commandName}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动 Console
|
||||
*/
|
||||
@JvmOverloads
|
||||
internal fun start(
|
||||
frontEnd: MiraiConsoleFrontEnd,
|
||||
coreVersion: String = "0.0.0",
|
||||
consoleVersion: String = "0.0.0",
|
||||
path: String = System.getProperty("user.dir")
|
||||
) {
|
||||
if (MiraiConsole.started) {
|
||||
return
|
||||
object ConsoleCS : ConsoleCommandSender() {
|
||||
override suspend fun sendMessage(message: Message) {
|
||||
ConsoleUtils.lineReader.printAbove(message.contentToString())
|
||||
}
|
||||
MiraiConsole.started = true
|
||||
this.path = path
|
||||
/* 初始化前端 */
|
||||
this.version = consoleVersion
|
||||
this.frontEnd = frontEnd
|
||||
this.frontEnd.pushVersion(consoleVersion, MiraiConsole.build, coreVersion)
|
||||
logger("Mirai-console now running under $path")
|
||||
logger("Get news in github: https://github.com/mamoe/mirai")
|
||||
logger("Mirai为开源项目,请自觉遵守开源项目协议")
|
||||
logger("Powered by Mamoe Technologies and contributors")
|
||||
|
||||
/* 依次启用功能 */
|
||||
DefaultCommands()
|
||||
PluginManager.loadPlugins()
|
||||
CommandManager.start()
|
||||
|
||||
/* 通知启动完成 */
|
||||
logger("Mirai-console 启动完成")
|
||||
logger("\"login qqnumber qqpassword \" to login a bot")
|
||||
logger("\"login qq号 qq密码 \" 来登录一个BOT")
|
||||
|
||||
/* 尝试从系统配置自动登录 */
|
||||
DefaultCommands.tryLoginAuto()
|
||||
}
|
@ -20,7 +20,7 @@ kotlin {
|
||||
all {
|
||||
|
||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||
languageSettings.progressiveMode = true
|
||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||
}
|
||||
@ -28,7 +28,7 @@ kotlin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
||||
compileOnly("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||
api(project(":mirai-console"))
|
||||
api(group = "com.googlecode.lanterna", name = "lanterna", version = "3.0.2")
|
||||
}
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
#Wed Mar 04 22:27:09 CST 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -1,72 +0,0 @@
|
||||
pluginManagement {
|
||||
resolutionStrategy {
|
||||
eachPlugin {
|
||||
switch (requested.id.id) {
|
||||
case "org.jetbrains.kotlin.multiplatform": useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}"); break
|
||||
case "com.android.library": useModule("com.android.tools.build:gradle:${requested.version}"); break
|
||||
case "com.jfrog.bintray": useModule("com.jfrog.bintray.gradle:gradle-bintray-plugin:${requested.version}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
maven { url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies" }
|
||||
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
|
||||
maven { url 'https://plugins.gradle.org/m2/' }
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'mirai-console'
|
||||
|
||||
def onlyBackEnd = true
|
||||
|
||||
include(':mirai-console')
|
||||
project(':mirai-console').dir = file("backend/mirai-console")
|
||||
|
||||
include(':codegen')
|
||||
project(':codegen').dir = file("backend/codegen")
|
||||
|
||||
|
||||
if (!onlyBackEnd) {
|
||||
|
||||
include(':mirai-console-pure')
|
||||
project(':mirai-console-pure').dir = file("frontend/mirai-console-pure")
|
||||
|
||||
include(':mirai-console-terminal')
|
||||
project(':mirai-console-terminal').dir = file("frontend/mirai-console-terminal")
|
||||
|
||||
try {
|
||||
def javaVersion = System.getProperty("java.version")
|
||||
def versionPos = javaVersion.indexOf(".")
|
||||
def javaVersionNum = javaVersion.substring(0, 1).toInteger()
|
||||
|
||||
if (javaVersion.startsWith("1.")) {
|
||||
javaVersionNum = javaVersion.substring(2, 3).toInteger()
|
||||
} else {
|
||||
if (versionPos == -1) versionPos = javaVersion.indexOf("-")
|
||||
if (versionPos == -1) {
|
||||
println("jdk version unknown")
|
||||
} else {
|
||||
javaVersionNum = javaVersion.substring(0, versionPos).toInteger()
|
||||
}
|
||||
}
|
||||
if (javaVersionNum >= 9) {
|
||||
include(':mirai-console-graphical')
|
||||
project(':mirai-console-graphical').dir = file("frontend/mirai-console-graphical")
|
||||
} else {
|
||||
println("jdk版本为 " + javaVersionNum)
|
||||
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用JDK 9以上版本引入模块 `:mirai-console-graphical`\n")
|
||||
}
|
||||
|
||||
} catch (Exception ignored) {
|
||||
println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enableFeaturePreview('GRADLE_METADATA')
|
53
settings.gradle.kts
Normal file
53
settings.gradle.kts
Normal file
@ -0,0 +1,53 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
resolutionStrategy {
|
||||
eachPlugin {
|
||||
val version = requested.version
|
||||
when (requested.id.id) {
|
||||
"org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${version}")
|
||||
"org.jetbrains.kotlin.plugin.serialization" -> useModule("org.jetbrains.kotlin:kotlin-serialization:${version}")
|
||||
"com.jfrog.bintray" -> useModule("com.jfrog.bintray.gradle:gradle-bintray-plugin:$version")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "mirai-console"
|
||||
|
||||
val disableOldFrontEnds = true
|
||||
|
||||
fun includeProject(projectPath: String, path: String? = null) {
|
||||
include(projectPath)
|
||||
if (path != null) project(projectPath).projectDir = file(path)
|
||||
}
|
||||
|
||||
includeProject(":mirai-console", "backend/mirai-console")
|
||||
includeProject(":mirai-console.codegen", "backend/codegen")
|
||||
includeProject(":mirai-console-pure", "frontend/mirai-console-pure")
|
||||
|
||||
@Suppress("ConstantConditionIf")
|
||||
if (!disableOldFrontEnds) {
|
||||
includeProject(":mirai-console-terminal", "frontend/mirai-console-terminal")
|
||||
|
||||
val jdkVersion = kotlin.runCatching {
|
||||
System.getProperty("java.version").let { v ->
|
||||
v.toIntOrNull() ?: v.removePrefix("1.").substringBefore("-").toIntOrNull()
|
||||
}
|
||||
}.getOrNull() ?: -1
|
||||
|
||||
println("JDK version: $jdkVersion")
|
||||
|
||||
if (jdkVersion >= 9) {
|
||||
includeProject(":mirai-console-graphical", "frontend/mirai-console-graphical")
|
||||
} else {
|
||||
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用 JDK 9 以上版本引入模块 `:mirai-console-graphical`\n")
|
||||
}
|
||||
}
|
||||
|
||||
enableFeaturePreview("GRADLE_METADATA")
|
Loading…
Reference in New Issue
Block a user