From afc30c53579a6c6fcbb58cafb26e0a585362cb7f Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 19 Jun 2020 04:26:29 +0800 Subject: [PATCH 01/32] Values infrastructure --- .../mamoe/mirai/console/setting/Setting.kt | 62 ++++++++ .../net/mamoe/mirai/console/setting/Value.kt | 142 ++++++++++++++++++ .../setting/internal/ValueCreatorsImpl.kt | 61 ++++++++ .../setting/internal/ValueDeclarationsImpl.kt | 47 ++++++ 4 files changed, 312 insertions(+) create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt new file mode 100644 index 000000000..c6d68e2cf --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -0,0 +1,62 @@ +/* + * 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 net.mamoe.mirai.console.setting.internal.cast +import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl +import kotlin.internal.LowPriorityInOverloadResolution +import kotlin.reflect.KProperty +import kotlin.reflect.typeOf + + +// Shows public APIs such as deciding when to auto-save. +abstract class Setting : SettingImpl() + +/** + * Internal implementation for [Setting] including: + * - Reflection on Kotlin properties and Java fields + * - Auto-saving + */ +// TODO move to internal package. +internal abstract class SettingImpl { + private class Node( + val property: KProperty, + val value: Value, + val serializer: ValueSerializer + ) + + private val valueNodes: List> = kotlin.run { + TODO("reflection") + } +} + + +//// region Setting.value primitives CODEGEN START //// + +// TODO: 2020/6/19 CODEGEN + +fun Setting.value(value: Int): IntValue = TODO("codegen") + +//// endregion Setting.value primitives CODEGEN END //// + + +/** + * Creates a [Value] with [default]. + * + * @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 Setting.value(default: T): Value = valueFromKTypeImpl(typeOf()).cast() \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt new file mode 100644 index 000000000..cdedff4b1 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -0,0 +1,142 @@ +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") + +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.utils.MiraiExperimentalAPI +import kotlin.internal.LowPriorityInOverloadResolution +import kotlin.reflect.typeOf + +/** + * 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 { + var value: T +} + +/** + * The serializer for a specific kind of [Value]. + */ +typealias ValueSerializer = KSerializer> + +/** + * Represents a observable *primitive* value wrapping. + * + * 8 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 8 types mentioned above. + */ +interface PrimitiveValue : Value + +interface MutablePrimitiveValue : Value + + +//// region PrimitiveValue CODEGEN START //// + +// TODO: 2020/6/19 CODEGEN + +/** + * Represents a non-null [Int] value. + */ +interface IntValue : PrimitiveValue + +//// endregion PrimitiveValue CODEGEN END //// + + +@MiraiExperimentalAPI +interface CompositeValue : Value + +/** + * Superclass of [CompositeListValue], [PrimitiveListValue]. + */ +interface ListValue : CompositeValue> + +/** + * Elements can by anything, wrapped as [Value]. + * @param T is not primitive types. + */ +interface CompositeListValue : ListValue> + +/** + * Elements can only be primitives, not wrapped. + * @param T is not primitive types. + */ +interface PrimitiveListValue : ListValue + + +//// region PrimitiveListValue CODEGEN START //// + +interface PrimitiveIntListValue : PrimitiveListValue +interface PrimitiveLongListValue : PrimitiveListValue +// TODO + codegen + +//// endregion PrimitiveListValue CODEGEN END //// + + +/** + * Superclass of [CompositeSetValue], [PrimitiveSetValue]. + */ +interface SetValue : CompositeValue> + +/** + * Elements can by anything, wrapped as [Value]. + * @param T is not primitive types. + */ +interface CompositeSetValue : SetValue> + +/** + * Elements can only be primitives, not wrapped. + * @param T is not primitive types. + */ +interface PrimitiveSetValue : SetValue + + +//// region PrimitiveSetValue CODEGEN START //// + +interface PrimitiveIntSetValue : PrimitiveSetValue +interface PrimitiveLongSetValue : PrimitiveSetValue +// TODO + codegen + +//// endregion PrimitiveSetValue CODEGEN END //// + + +/** + * Superclass of [CompositeMapValue], [PrimitiveMapValue]. + */ +interface MapValue : CompositeValue> + +interface CompositeMapValue : MapValue, Value> + +interface PrimitiveMapValue : MapValue + + +//// region PrimitiveMapValue CODEGEN START //// + +interface PrimitiveIntIntMapValue : PrimitiveMapValue +interface PrimitiveIntLongMapValue : PrimitiveMapValue +// TODO + codegen + +//// endregion PrimitiveSetValue CODEGEN END //// + + + + + + + + + diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt new file mode 100644 index 000000000..e6d80c495 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt @@ -0,0 +1,61 @@ +/* + * 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 net.mamoe.mirai.console.setting.Setting +import net.mamoe.mirai.console.setting.Value +import kotlin.reflect.KClass +import kotlin.reflect.KType +import kotlin.reflect.full.isSubclassOf + + +@PublishedApi +internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { + require(type.classifier is KClass<*>) + + if (type.classifier.isPrimitiveOrBuiltInSerializableValue()) { + TODO("是基础类型, 可以直接创建 ValueImpl. ") + } + + // 复合类型 + + when { + type.classifier.isSubclassOf(Map::class) -> { + + TODO() + } + type.classifier.isSubclassOf(List::class) -> { + + TODO() + } + type.classifier.isSubclassOf(Set::class) -> { + TODO() + } + else -> error("Custom composite value is not supported yet (${type.classifier.qualifiedName})") + } +} + +internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean { + 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 T.cast(): R = this as R \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt new file mode 100644 index 000000000..ce7a68627 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt @@ -0,0 +1,47 @@ +/* + * 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.CompositeListValue +import net.mamoe.mirai.console.setting.IntValue +import net.mamoe.mirai.console.setting.Value + +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() +} + +internal abstract class CompositeListValueImpl( + val tToValue: (T) -> Value +) : CompositeListValue { + private var _value: List> = mutableListOf() + override var value: List> + get() = _value + set(v) { + _value = v + } +} \ No newline at end of file From ae20a8d1807ecd69cac36342adb4729ebe824126 Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 19 Jun 2020 13:22:29 +0800 Subject: [PATCH 02/32] Fix typo --- .../main/kotlin/net/mamoe/mirai/console/setting/Value.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index cdedff4b1..895d18754 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -3,11 +3,7 @@ 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.utils.MiraiExperimentalAPI -import kotlin.internal.LowPriorityInOverloadResolution -import kotlin.reflect.typeOf /** * Represents a observable, immutable value wrapping. @@ -31,7 +27,7 @@ typealias ValueSerializer = KSerializer> /** * Represents a observable *primitive* value wrapping. * - * 8 types that are considered *primitive*: + * 9 types that are considered *primitive*: * - Integers: [Byte], [Short], [Int], [Long] * - Floating: [Float], [Double] * - [Boolean] @@ -42,8 +38,6 @@ typealias ValueSerializer = KSerializer> */ interface PrimitiveValue : Value -interface MutablePrimitiveValue : Value - //// region PrimitiveValue CODEGEN START //// From e7c9029364558f57960e188aa872dcccb8e83ef3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 19 Jun 2020 13:23:08 +0800 Subject: [PATCH 03/32] Add missing copyright --- .../main/kotlin/net/mamoe/mirai/console/setting/Value.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index 895d18754..58424dfe2 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -1,3 +1,12 @@ +/* + * 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") package net.mamoe.mirai.console.setting From 5528de0721e1f9c2dc075d780d05c1eaf1ad9ab3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 19 Jun 2020 13:23:26 +0800 Subject: [PATCH 04/32] Fix typo --- .../src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index 58424dfe2..09b860e0c 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -43,7 +43,7 @@ typealias ValueSerializer = KSerializer> * - [Char], [String] * * Note: The values are actually *boxed* because of the generic type T. - * *Primitive* indicates only it is one of the 8 types mentioned above. + * *Primitive* indicates only it is one of the 9 types mentioned above. */ interface PrimitiveValue : Value From 4b58c763857330704f3726e0b61d6f41effce767 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 20 Jun 2020 20:08:22 +0800 Subject: [PATCH 05/32] Add codegen DSL --- .../console/codegen/setting/SettingCodegen.kt | 11 ++++ .../net/mamoe/mirai/console/codegen/util.kt | 54 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt create mode 100644 backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt new file mode 100644 index 000000000..9c97af271 --- /dev/null +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt @@ -0,0 +1,11 @@ +/* + * 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.setting + diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt new file mode 100644 index 000000000..172819f94 --- /dev/null +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt @@ -0,0 +1,54 @@ +/* + * 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 + +import java.io.File + +fun codegen(targetFile: String, regionName: String, block: StringBuilder.() -> Unit) { + //// region PrimitiveValue CODEGEN START //// + //// region PrimitiveValue CODEGEN END //// + + targetFile.findFileSmart().also { + println("Codegen target: ${it.absolutePath}") + }.apply { + writeText( + readText() + .replace(Regex("""//// region $regionName CODEGEN START ////([\s\S]*?)//// endregion $regionName CODEGEN END ////""")) { + val code = StringBuilder().apply(block).toString() + """ + |//// region $regionName CODEGEN START //// + | + |$code + | + |//// endregion $regionName CODEGEN END //// + """.trimMargin() + } + ) + } +} + +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" } +} + +fun main() { + codegen("Value.kt", "PrimitiveValue") { + + } +} \ No newline at end of file From ce49e27e9548a890434838492e1ed5a69dae782d Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 20 Jun 2020 20:08:26 +0800 Subject: [PATCH 06/32] Fix build --- .../console/plugin/internal/PluginsLoader.kt | 29 ++++++++++--------- .../setting/internal/ValueCreatorsImpl.kt | 14 ++++----- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt index 1e59e5c75..a9a3d9f85 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt @@ -16,7 +16,7 @@ import java.net.URLClassLoader internal class PluginsLoader(private val parentClassLoader: ClassLoader) { private val loggerName = "PluginsLoader" private val pluginLoaders = linkedMapOf() - private val classesCache = mutableMapOf>() + private val classesCache = mutableMapOf>() private val logger = MiraiConsole.newLogger(loggerName) /** @@ -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>() + private val internalClassCache = mutableMapOf>() - internal val classesCache:Map> + internal val classesCache: Map> 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 + @Suppress("UNNECESSARY_NOT_NULL_ASSERTION") + clazz!! // compiler bug } } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt index e6d80c495..ad4d1ef05 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt @@ -15,32 +15,32 @@ import net.mamoe.mirai.console.setting.Setting import net.mamoe.mirai.console.setting.Value import kotlin.reflect.KClass import kotlin.reflect.KType -import kotlin.reflect.full.isSubclassOf @PublishedApi internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { - require(type.classifier is KClass<*>) + val classifier = type.classifier + require(classifier is KClass<*>) - if (type.classifier.isPrimitiveOrBuiltInSerializableValue()) { + if (classifier.isPrimitiveOrBuiltInSerializableValue()) { TODO("是基础类型, 可以直接创建 ValueImpl. ") } // 复合类型 when { - type.classifier.isSubclassOf(Map::class) -> { + classifier == Map::class -> { TODO() } - type.classifier.isSubclassOf(List::class) -> { + classifier == List::class -> { TODO() } - type.classifier.isSubclassOf(Set::class) -> { + classifier == Set::class -> { TODO() } - else -> error("Custom composite value is not supported yet (${type.classifier.qualifiedName})") + else -> error("Custom composite value is not supported yet (${classifier.qualifiedName})") } } From 67014edc314859e9eb25b0c63d36395491380e5b Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Sat, 20 Jun 2020 20:44:17 +0800 Subject: [PATCH 07/32] Fix type mismatch --- .../net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt index 1e59e5c75..bf95f9bd0 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt @@ -153,6 +153,6 @@ internal class PluginClassLoader( pluginsLoader.addClassCache(name, clazz) this.addClassCache(name, clazz) clazz - } + }!! } } From a21740ed3c34724f1395af592b09f496d8efdb23 Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Sat, 20 Jun 2020 20:44:53 +0800 Subject: [PATCH 08/32] Suppress SMARTCAST_IMPOSSIBLE --- .../mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt index e6d80c495..eece6fca3 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt @@ -19,6 +19,7 @@ import kotlin.reflect.full.isSubclassOf @PublishedApi +@Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE") internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { require(type.classifier is KClass<*>) From 4d69ae617fdee02f869a7c874c1bb86f6ab25615 Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Sat, 20 Jun 2020 20:46:00 +0800 Subject: [PATCH 09/32] Fix wrong initialization order --- .../net/mamoe/mirai/console/MiraiConsole.kt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 3669f780f..5b9fe51fc 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -15,7 +15,6 @@ import kotlinx.io.charsets.Charset import net.mamoe.mirai.Bot 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 @@ -24,17 +23,23 @@ import java.io.File import java.io.PrintStream import kotlin.coroutines.CoroutineContext -/** - * mirai 控制台实例. - */ -object MiraiConsole : CoroutineScope, IMiraiConsole { - private lateinit var instance: IMiraiConsole +internal object MiraiConsoleInitializer { + internal lateinit var instance: IMiraiConsole /** 由前端调用 */ internal fun init(instance: IMiraiConsole) { this.instance = instance } +} + +/** + * mirai 控制台实例. + */ +object MiraiConsole : CoroutineScope, IMiraiConsole { + private val instance: IMiraiConsole + get() = MiraiConsoleInitializer.instance + /** * `mirai-console` build 号 */ From 5e95348baef3fb9c387968134827b8068ae0422a Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Sat, 20 Jun 2020 20:46:20 +0800 Subject: [PATCH 10/32] Update build.gradle.kts --- frontend/mirai-console-pure/build.gradle.kts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/frontend/mirai-console-pure/build.gradle.kts b/frontend/mirai-console-pure/build.gradle.kts index c0ce1e6a7..1605c2d96 100644 --- a/frontend/mirai-console-pure/build.gradle.kts +++ b/frontend/mirai-console-pure/build.gradle.kts @@ -25,10 +25,23 @@ kotlin { } } } + +var debugging = true + dependencies { - compileOnly(project(":mirai-console")) - compileOnly("net.mamoe:mirai-core:${Versions.Mirai.core}") - compileOnly(kotlin("stdlib")) // embedded by core + fun import0(dep: Any) { + if (debugging) { + implementation(dep) + } else { + compileOnly(dep) + } + } + import0("org.jline:jline:3.15.0") + import0("org.fusesource.jansi:jansi:1.18") + + import0(project(":mirai-console")) + import0("net.mamoe:mirai-core:${Versions.Mirai.core}") + import0(kotlin("stdlib")) // embedded by core testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}") testApi(project(":mirai-console")) From b37f7bbb5f2744a576279f4725c15519e880c3cf Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Sat, 20 Jun 2020 20:47:59 +0800 Subject: [PATCH 11/32] Mirai Console Front End Pure --- .../mamoe/mirai/console/pure/ConsoleUtils.kt | 37 ++++++ .../console/pure/MiraiConsoleFrontEndPure.kt | 78 +++++++++++- .../mirai/console/pure/MiraiConsolePure.kt | 49 ++++++++ .../console/pure/MiraiConsolePureLoader.kt | 114 +++++++++--------- 4 files changed, 217 insertions(+), 61 deletions(-) create mode 100644 frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt create mode 100644 frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt new file mode 100644 index 000000000..a363e5e03 --- /dev/null +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt @@ -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() + } +} \ No newline at end of file diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt index e000b7a7d..39f329382 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt @@ -9,20 +9,86 @@ 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.console.MiraiConsoleFrontEnd import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.DefaultLoginSolver import net.mamoe.mirai.utils.LoginSolver import net.mamoe.mirai.utils.MiraiLogger +import org.fusesource.jansi.Ansi import java.text.SimpleDateFormat import java.util.* -import kotlin.concurrent.thread +import java.util.concurrent.ConcurrentHashMap + +@Suppress("unused") +object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { + private val globalLogger = DefaultLogger("Mirai") + private val cachedLoggers = ConcurrentHashMap() + + // 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, DefaultLogger) + } + return globalLogger + } + + override fun prePushBot(identity: Long) { + } + + override fun pushBot(bot: Bot) { + } + + override fun pushVersion(consoleVersion: String, consoleBuild: String, coreVersion: String) { + } + + 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) { + } + + override fun createLoginSolver(): LoginSolver { + return DefaultLoginSolver( + input = suspend { + requestInput("") + } + ) + } + +} + +/* class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { private var requesting = false private var requestStr = "" @@ -106,4 +172,4 @@ class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { } - +*/ diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt new file mode 100644 index 000000000..5e0ab01a9 --- /dev/null +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt @@ -0,0 +1,49 @@ +/* + * 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 build: String = "UNKNOWN" + override val builtInPluginLoaders: List> = LinkedList() + override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure + override val mainLogger: MiraiLogger = DefaultLogger("Console") + override val rootDir: File = File("./test/console").also { + it.mkdirs() + } + override val version: String + get() = "UNKNOWN" + override val coroutineContext: CoroutineContext + get() = delegateScope.coroutineContext +} \ No newline at end of file diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt index d5a144a5c..72dd8c6fa 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt @@ -7,68 +7,72 @@ * 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.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 net.mamoe.mirai.utils.PlatformLogger +import org.fusesource.jansi.Ansi 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?) { + startup() + } +} + +private val ANSI_RESET = Ansi().reset().toString() + +internal fun overrideLoggingSystem() { + DefaultLogger = { + PlatformLogger(identity = it, output = { line -> + ConsoleUtils.lineReader.printAbove(line + ANSI_RESET) + }) + } +} + +internal fun startup() { + overrideLoggingSystem() + 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") + kotlin.runCatching { + if (!ConsoleCS.executeCommand(PlainText(next))) { // No such command + consoleLogger.warning("Unknown command: " + next.split(' ')[0]) + } + }.onFailure { + consoleLogger.error("Exception in executing command: $next", it) + } + } } } } -/** - * 启动 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() } \ No newline at end of file From 6afa6af4a14fdb045c2d7a407b2900f6204ad289 Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Sat, 20 Jun 2020 21:16:06 +0800 Subject: [PATCH 12/32] Fix test --- .../kotlin/net/mamoe/mirai/console/command/TestComposite.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestComposite.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestComposite.kt index c1cfe009f..133eb62db 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestComposite.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestComposite.kt @@ -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 } } From 754811ddaa6651c4b4e2eb016ed8bbb0bcc2d060 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 20 Jun 2020 22:54:27 +0800 Subject: [PATCH 13/32] Add codegen framework --- .../mamoe/mirai/console/codegen/Codegen.kt | 98 +++++++++++++++++ .../mirai/console/codegen/JSettingCodegen.kt | 32 +++--- .../mirai/console/codegen/SettingCodegen.kt | 40 +++++++ .../codegen/SettingValueUseSiteCodegen.kt | 32 +++--- .../mirai/console/codegen/ValueImplCodegen.kt | 38 +++---- .../mirai/console/codegen/ValuesCodegen.kt | 38 +++---- .../console/codegen/setting/SettingCodegen.kt | 11 -- .../net/mamoe/mirai/console/codegen/util.kt | 100 +++++++++++++++--- 8 files changed, 296 insertions(+), 93 deletions(-) create mode 100644 backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt create mode 100644 backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt delete mode 100644 backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt new file mode 100644 index 000000000..f79214b89 --- /dev/null +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt @@ -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 ?: "") { + override fun invoke(p1: String): String = block(p1) + } +} + +class CodegenScope : MutableList 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) { + 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) { + add(Replacer { + it.replace(Regex("""//// region $regionName CODEGEN START ////([\s\S]*?)//// endregion $regionName CODEGEN END ////""")) { + val code = CodegenScope().apply { (this@invoke as Codegen).invoke(*ktTypes.toTypedArray()) }.applyTo("") + """ + |//// region $regionName CODEGEN START //// + | + |$code + | + |//// endregion $regionName CODEGEN END //// + """.trimMargin() + } + }) + } + + @DslMarker + annotation class CodegenDsl +} + +@DslMarker +annotation class RegionCodegenDsl + +interface DefaultInvoke { + val defaultInvokeArgs: List +} + +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) = ktType.forEach { apply(it) } +} + +fun StringBuilder.appendKCode(@Language("kt") ktCode: String): StringBuilder = append(kCode(ktCode)).appendLine() diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/JSettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/JSettingCodegen.kt index fff3f18ae..885a7e898 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/JSettingCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/JSettingCodegen.kt @@ -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()) } } }) diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt new file mode 100644 index 000000000..d6ac306e1 --- /dev/null +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt @@ -0,0 +1,40 @@ +/* + * 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 SettingCodegen { + object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke { + override val defaultInvokeArgs: List + get() = KtType.Primitives + KtString + + override fun StringBuilder.apply(ktType: KtType) { + @Suppress("ClassName") + appendKCode( + """ + /** + * Represents a non-null [$ktType] value. + */ + interface ${ktType}Value : PrimitiveValue<$ktType> + """ + ) + } + } + +} + +object ValueKtCodegen { + @JvmStatic + fun main(args: Array) { + codegen("Value.kt") { + SettingCodegen.PrimitiveValuesCodegen() + } + } +} + diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt index 36af092a4..561bb40c9 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingValueUseSiteCodegen.kt @@ -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 Setting.value(default: T): Value { diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt index b4c0014a3..f9e94702f 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueImplCodegen.kt @@ -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( diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt index 018f7242e..4920d6754 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValuesCodegen.kt @@ -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 : ReadWriteProperty { } """ ) - appendln() + appendLine() // PRIMITIVES @@ -127,7 +127,7 @@ sealed class Value : ReadWriteProperty { appendln(template) } - appendln() + appendLine() for (number in OTHER_PRIMITIVES) { val template = """ @@ -137,7 +137,7 @@ sealed class Value : ReadWriteProperty { appendln(template) } - appendln() + appendLine() // ARRAYS @@ -154,7 +154,7 @@ sealed class Value : ReadWriteProperty { sealed class PrimitiveArrayValue : ArrayValue() """ ) - appendln() + appendLine() for (number in (NUMBERS + OTHER_PRIMITIVES).filterNot { it == "String" }) { appendln( @@ -164,10 +164,10 @@ sealed class Value : ReadWriteProperty { } """ ) - appendln() + appendLine() } - appendln() + appendLine() // TYPED ARRAYS @@ -178,7 +178,7 @@ sealed class Value : ReadWriteProperty { } """ ) - appendln() + appendLine() for (number in (NUMBERS + OTHER_PRIMITIVES)) { appendln( @@ -188,7 +188,7 @@ sealed class Value : ReadWriteProperty { ) } - appendln() + appendLine() // TYPED LISTS / SETS for (collectionName in listOf("List", "Set")) { @@ -207,14 +207,14 @@ sealed class Value : ReadWriteProperty { appendln(template) } - appendln() + appendLine() // SETTING appendln( """ abstract class Setting${collectionName}Value internal constructor() : Value<${collectionName}>(), ${collectionName} """ ) - appendln() + appendLine() } // SETTING VALUE @@ -225,7 +225,7 @@ sealed class Value : ReadWriteProperty { """ ) - appendln() + appendLine() // MUTABLE LIST / MUTABLE SET for (collectionName in listOf("List", "Set")) { @@ -235,7 +235,7 @@ sealed class Value : ReadWriteProperty { """ ) - appendln() + appendLine() for (number in (NUMBERS + OTHER_PRIMITIVES)) { appendln( @@ -245,17 +245,17 @@ sealed class Value : ReadWriteProperty { ) } - appendln() + appendLine() // SETTING appendln( """ abstract class MutableSetting${collectionName}Value internal constructor() : Value>(), Mutable${collectionName} """ ) - appendln() + appendLine() } - appendln() + appendLine() // DYNAMIC appendln( diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt deleted file mode 100644 index 9c97af271..000000000 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/setting/SettingCodegen.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * 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.setting - diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt index 172819f94..247a8ced0 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt @@ -7,11 +7,91 @@ * 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 -fun codegen(targetFile: String, regionName: String, block: StringBuilder.() -> Unit) { + +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 { + 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 START //// //// region PrimitiveValue CODEGEN END //// @@ -19,17 +99,11 @@ fun codegen(targetFile: String, regionName: String, block: StringBuilder.() -> U println("Codegen target: ${it.absolutePath}") }.apply { writeText( - readText() - .replace(Regex("""//// region $regionName CODEGEN START ////([\s\S]*?)//// endregion $regionName CODEGEN END ////""")) { - val code = StringBuilder().apply(block).toString() - """ - |//// region $regionName CODEGEN START //// - | - |$code - | - |//// endregion $regionName CODEGEN END //// - """.trimMargin() + CodegenScope().apply(block).also { list -> + list.forEach { + println("Applying replacement: $it") } + }.applyTo(readText()) ) } } @@ -48,7 +122,7 @@ fun String.findFileSmart(): File = kotlin.run { } fun main() { - codegen("Value.kt", "PrimitiveValue") { - + codegen("Value.kt") { + SettingCodegen.PrimitiveValuesCodegen() } } \ No newline at end of file From f5d9f4a67e723f84983892ccdea9d3683daa456e Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 20 Jun 2020 22:55:07 +0800 Subject: [PATCH 14/32] Rearrange build scripts --- backend/codegen/build.gradle.kts | 8 +- backend/mirai-console/build.gradle.kts | 16 ++- build.gradle.kts | 113 +---------------- buildSrc/build.gradle.kts | 8 ++ .../main/kotlin/MiraiConsoleBuildPlugin.kt | 115 ++++++++++++++++++ buildSrc/src/main/kotlin/Versions.kt | 26 ++-- .../src/main/kotlin/dependencyExtensions.kt | 2 +- .../mirai-console-graphical/build.gradle.kts | 8 +- frontend/mirai-console-pure/build.gradle.kts | 4 +- .../mirai-console-terminal/build.gradle.kts | 2 +- settings.gradle | 72 ----------- settings.gradle.kts | 67 ++++++++++ 12 files changed, 225 insertions(+), 216 deletions(-) create mode 100644 buildSrc/src/main/kotlin/MiraiConsoleBuildPlugin.kt delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/backend/codegen/build.gradle.kts b/backend/codegen/build.gradle.kts index 574abfe7f..0869d2a10 100644 --- a/backend/codegen/build.gradle.kts +++ b/backend/codegen/build.gradle.kts @@ -1,8 +1,8 @@ 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") } @@ -12,6 +12,8 @@ kotlin { languageSettings.useExperimentalAnnotation("kotlin.Experimental") languageSettings.useExperimentalAnnotation("kotlin.OptIn") 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,7 +23,7 @@ kotlin { } dependencies { - api(kotlin("stdlib")) + api(kotlin("stdlib-jdk8", "1.4-M2")) } val compileKotlin: KotlinCompile by tasks diff --git a/backend/mirai-console/build.gradle.kts b/backend/mirai-console/build.gradle.kts index 97178d3fe..14d759c33 100644 --- a/backend/mirai-console/build.gradle.kts +++ b/backend/mirai-console/build.gradle.kts @@ -2,16 +2,14 @@ import upload.Bintray 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 +54,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")) diff --git a/build.gradle.kts b/build.gradle.kts index ad1429f2e..53ffc7e38 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,27 +1,9 @@ @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" @@ -35,97 +17,6 @@ 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 - - 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 - } - } - } - - } + apply() } -} - - -fun Project.findLatestFile(): Map.Entry { - 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") -} +} \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index a0b4b2f9b..c71abcbab 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -3,7 +3,10 @@ plugins { } repositories { + mavenLocal() jcenter() + maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") + mavenCentral() } kotlin { @@ -24,4 +27,9 @@ 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") + + api("com.github.jengelman.gradle.plugins:shadow:6.0.0") } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/MiraiConsoleBuildPlugin.kt b/buildSrc/src/main/kotlin/MiraiConsoleBuildPlugin.kt new file mode 100644 index 000000000..2df6c68ab --- /dev/null +++ b/buildSrc/src/main/kotlin/MiraiConsoleBuildPlugin.kt @@ -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 { + override fun apply(target: Project) = target.run { + apply() + + 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 { + 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") +} diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 6647de79e..f80aaee49 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -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.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" - 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" } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/dependencyExtensions.kt b/buildSrc/src/main/kotlin/dependencyExtensions.kt index 03bee26e5..5a9f08d92 100644 --- a/buildSrc/src/main/kotlin/dependencyExtensions.kt +++ b/buildSrc/src/main/kotlin/dependencyExtensions.kt @@ -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) { diff --git a/frontend/mirai-console-graphical/build.gradle.kts b/frontend/mirai-console-graphical/build.gradle.kts index c9e6de907..cb6168895 100644 --- a/frontend/mirai-console-graphical/build.gradle.kts +++ b/frontend/mirai-console-graphical/build.gradle.kts @@ -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 { diff --git a/frontend/mirai-console-pure/build.gradle.kts b/frontend/mirai-console-pure/build.gradle.kts index c0ce1e6a7..fffa14ed1 100644 --- a/frontend/mirai-console-pure/build.gradle.kts +++ b/frontend/mirai-console-pure/build.gradle.kts @@ -27,10 +27,10 @@ kotlin { } dependencies { compileOnly(project(":mirai-console")) - compileOnly("net.mamoe:mirai-core:${Versions.Mirai.core}") + compileOnly("net.mamoe:mirai-core:${Versions.core}") compileOnly(kotlin("stdlib")) // embedded by core - testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}") + testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}") testApi(project(":mirai-console")) } diff --git a/frontend/mirai-console-terminal/build.gradle.kts b/frontend/mirai-console-terminal/build.gradle.kts index 101775f61..27af40004 100644 --- a/frontend/mirai-console-terminal/build.gradle.kts +++ b/frontend/mirai-console-terminal/build.gradle.kts @@ -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") } diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index d63876b77..000000000 --- a/settings.gradle +++ /dev/null @@ -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') \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..6bdfadcac --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,67 @@ +pluginManagement { + repositories { + maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") + maven(url = "https://mirrors.huaweicloud.com/repository/maven") + jcenter() + mavenCentral() + } + + resolutionStrategy { + eachPlugin { + val version = requested.version + when (requested.id.id) { + "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${version}") + } + } + } +} + +rootProject.name = "mirai-console" + +val onlyBackEnd = true + +include(":mirai-console") +project(":mirai-console").projectDir = file("backend/mirai-console") + +include(":codegen") +project(":codegen").projectDir = file("backend/codegen") + +@Suppress("ConstantConditionIf") +if (!onlyBackEnd) { + + include(":mirai-console-pure") + project(":mirai-console-pure").projectDir = file("frontend/mirai-console-pure") + + include(":mirai-console-terminal") + project(":mirai-console-terminal").projectDir = file("frontend/mirai-console-terminal") + + try { + val javaVersion = System.getProperty("java.version") + var versionPos = javaVersion.indexOf(".") + var javaVersionNum = javaVersion.substring(0, 1).toInt() + + if (javaVersion.startsWith("1.")) { + javaVersionNum = javaVersion.substring(2, 3).toInt() + } else { + if (versionPos == -1) versionPos = javaVersion.indexOf("-") + if (versionPos == -1) { + println("jdk version unknown") + } else { + javaVersionNum = javaVersion.substring(0, versionPos).toInt() + } + } + if (javaVersionNum >= 9) { + include(":mirai-console-graphical") + project(":mirai-console-graphical").projectDir = file("frontend/mirai-console-graphical") + } else { + println("JDK 版本为 $javaVersionNum") + println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用JDK 9以上版本引入模块 `:mirai-console-graphical`\n") + } + + } catch (ignored: Exception) { + println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`") + } +} + + +enableFeaturePreview("GRADLE_METADATA") \ No newline at end of file From febe4d9d5230e4df1844bd491530c7f664c41f9b Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 20 Jun 2020 22:55:18 +0800 Subject: [PATCH 15/32] PrimitiveValues codegen --- .../net/mamoe/mirai/console/setting/Value.kt | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index 09b860e0c..14d29c8e8 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -48,16 +48,55 @@ typealias ValueSerializer = KSerializer> interface PrimitiveValue : Value -//// region PrimitiveValue CODEGEN START //// +//// region PrimitiveValues CODEGEN START //// -// TODO: 2020/6/19 CODEGEN +/** + * Represents a non-null [Byte] value. + */ +interface ByteValue : PrimitiveValue + +/** + * Represents a non-null [Short] value. + */ +interface ShortValue : PrimitiveValue /** * Represents a non-null [Int] value. */ interface IntValue : PrimitiveValue -//// endregion PrimitiveValue CODEGEN END //// +/** + * Represents a non-null [Long] value. + */ +interface LongValue : PrimitiveValue + +/** + * Represents a non-null [Float] value. + */ +interface FloatValue : PrimitiveValue + +/** + * Represents a non-null [Double] value. + */ +interface DoubleValue : PrimitiveValue + +/** + * Represents a non-null [Char] value. + */ +interface CharValue : PrimitiveValue + +/** + * Represents a non-null [Boolean] value. + */ +interface BooleanValue : PrimitiveValue + +/** + * Represents a non-null [String] value. + */ +interface StringValue : PrimitiveValue + + +//// endregion PrimitiveValues CODEGEN END //// @MiraiExperimentalAPI From e0c16000017e3718438d18c1f4bb4b41b7c0e933 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 20 Jun 2020 23:23:19 +0800 Subject: [PATCH 16/32] Optimize codegen --- .../net/mamoe/mirai/console/codegen/Codegen.kt | 6 +++--- .../net/mamoe/mirai/console/codegen/util.kt | 4 ++-- .../net/mamoe/mirai/console/setting/Setting.kt | 4 ++-- .../net/mamoe/mirai/console/setting/Value.kt | 18 +++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt index f79214b89..cc1486ef2 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/Codegen.kt @@ -53,14 +53,14 @@ class CodegenScope : MutableList by mutableListOf() { @RegionCodegenDsl operator fun RegionCodegen.invoke(ktTypes: Collection) { add(Replacer { - it.replace(Regex("""//// region $regionName CODEGEN START ////([\s\S]*?)//// endregion $regionName CODEGEN END ////""")) { + 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 START //// + |//// region $regionName CODEGEN //// | |$code | - |//// endregion $regionName CODEGEN END //// + |//// endregion $regionName CODEGEN //// """.trimMargin() } }) diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt index 247a8ced0..1d2b9da28 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt @@ -92,8 +92,8 @@ 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 START //// - //// region PrimitiveValue CODEGEN END //// + //// region PrimitiveValue CODEGEN //// + //// region PrimitiveValue CODEGEN //// targetFile.findFileSmart().also { println("Codegen target: ${it.absolutePath}") diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt index c6d68e2cf..2d32ddefc 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -40,13 +40,13 @@ internal abstract class SettingImpl { } -//// region Setting.value primitives CODEGEN START //// +//// region Setting.value primitives CODEGEN //// // TODO: 2020/6/19 CODEGEN fun Setting.value(value: Int): IntValue = TODO("codegen") -//// endregion Setting.value primitives CODEGEN END //// +//// endregion Setting.value primitives CODEGEN //// /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index 14d29c8e8..8dee45afd 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused") package net.mamoe.mirai.console.setting @@ -48,7 +48,7 @@ typealias ValueSerializer = KSerializer> interface PrimitiveValue : Value -//// region PrimitiveValues CODEGEN START //// +//// region PrimitiveValues CODEGEN //// /** * Represents a non-null [Byte] value. @@ -96,7 +96,7 @@ interface BooleanValue : PrimitiveValue interface StringValue : PrimitiveValue -//// endregion PrimitiveValues CODEGEN END //// +//// endregion PrimitiveValues CODEGEN //// @MiraiExperimentalAPI @@ -120,13 +120,13 @@ interface CompositeListValue : ListValue> interface PrimitiveListValue : ListValue -//// region PrimitiveListValue CODEGEN START //// +//// region PrimitiveListValue CODEGEN //// interface PrimitiveIntListValue : PrimitiveListValue interface PrimitiveLongListValue : PrimitiveListValue // TODO + codegen -//// endregion PrimitiveListValue CODEGEN END //// +//// endregion PrimitiveListValue CODEGEN //// /** @@ -147,13 +147,13 @@ interface CompositeSetValue : SetValue> interface PrimitiveSetValue : SetValue -//// region PrimitiveSetValue CODEGEN START //// +//// region PrimitiveSetValue CODEGEN //// interface PrimitiveIntSetValue : PrimitiveSetValue interface PrimitiveLongSetValue : PrimitiveSetValue // TODO + codegen -//// endregion PrimitiveSetValue CODEGEN END //// +//// endregion PrimitiveSetValue CODEGEN //// /** @@ -166,13 +166,13 @@ interface CompositeMapValue : MapValue, Value> interface PrimitiveMapValue : MapValue -//// region PrimitiveMapValue CODEGEN START //// +//// region PrimitiveMapValue CODEGEN //// interface PrimitiveIntIntMapValue : PrimitiveMapValue interface PrimitiveIntLongMapValue : PrimitiveMapValue // TODO + codegen -//// endregion PrimitiveSetValue CODEGEN END //// +//// endregion PrimitiveSetValue CODEGEN //// From 9fb167ee602662960931c0c6dd798007d40b7d4a Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 00:44:02 +0800 Subject: [PATCH 17/32] Fix build --- backend/codegen/build.gradle.kts | 20 +----- build.gradle.kts | 4 +- buildSrc/build.gradle.kts | 4 +- .../src/main/kotlin/SetCompileTargetPlugin.kt | 45 ++++++++++++++ frontend/mirai-console-pure/build.gradle.kts | 22 +------ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle.kts | 62 +++++++------------ 7 files changed, 79 insertions(+), 80 deletions(-) create mode 100644 buildSrc/src/main/kotlin/SetCompileTargetPlugin.kt diff --git a/backend/codegen/build.gradle.kts b/backend/codegen/build.gradle.kts index 0869d2a10..93e6cd2f7 100644 --- a/backend/codegen/build.gradle.kts +++ b/backend/codegen/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { kotlin("jvm") version "1.4-M2" kotlin("plugin.serialization") version "1.4-M2" @@ -23,21 +21,5 @@ kotlin { } dependencies { - api(kotlin("stdlib-jdk8", "1.4-M2")) -} - -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")) } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 53ffc7e38..e747edcae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,8 +8,8 @@ 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() } @@ -18,5 +18,7 @@ allprojects { subprojects { afterEvaluate { apply() + + setJavaCompileTarget() } } \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c71abcbab..0473f2f16 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -28,8 +28,10 @@ dependencies { api(ktor("client-cio", "1.3.2")) api(ktor("client-json", "1.3.2")) - api(gradleApi()) + //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") } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/SetCompileTargetPlugin.kt b/buildSrc/src/main/kotlin/SetCompileTargetPlugin.kt new file mode 100644 index 000000000..8910359a3 --- /dev/null +++ b/buildSrc/src/main/kotlin/SetCompileTargetPlugin.kt @@ -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): Pair { + return this to this::class.java.getMethod(name, *params.map { it.java }.toTypedArray()) +} + +operator fun Pair.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" + } + } +} \ No newline at end of file diff --git a/frontend/mirai-console-pure/build.gradle.kts b/frontend/mirai-console-pure/build.gradle.kts index 68d4824a1..0fc200fae 100644 --- a/frontend/mirai-console-pure/build.gradle.kts +++ b/frontend/mirai-console-pure/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { kotlin("jvm") version Versions.kotlin kotlin("plugin.serialization") version Versions.kotlin @@ -45,22 +43,6 @@ dependencies { 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" -} \ No newline at end of file +description = "Console Pure CLI frontend for mirai" \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 77f95ee0c..1ee034fe0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/settings.gradle.kts b/settings.gradle.kts index 6bdfadcac..17c9a06a2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,8 @@ pluginManagement { repositories { - maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") - maven(url = "https://mirrors.huaweicloud.com/repository/maven") + mavenLocal() jcenter() + maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") mavenCentral() } @@ -11,6 +11,8 @@ pluginManagement { 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") } } } @@ -18,50 +20,34 @@ pluginManagement { rootProject.name = "mirai-console" -val onlyBackEnd = true +val disableOldFrontEnds = true -include(":mirai-console") -project(":mirai-console").projectDir = file("backend/mirai-console") +fun includeProject(projectPath: String, path: String? = null) { + include(projectPath) + if (path != null) project(projectPath).projectDir = file(path) +} -include(":codegen") -project(":codegen").projectDir = file("backend/codegen") +includeProject(":mirai-console", "backend/mirai-console") +includeProject(":codegen", "backend/codegen") +includeProject(":mirai-console-pure", "frontend/mirai-console-pure") @Suppress("ConstantConditionIf") -if (!onlyBackEnd) { +if (!disableOldFrontEnds) { + includeProject(":mirai-console-terminal", "frontend/mirai-console-terminal") - include(":mirai-console-pure") - project(":mirai-console-pure").projectDir = file("frontend/mirai-console-pure") - - include(":mirai-console-terminal") - project(":mirai-console-terminal").projectDir = file("frontend/mirai-console-terminal") - - try { - val javaVersion = System.getProperty("java.version") - var versionPos = javaVersion.indexOf(".") - var javaVersionNum = javaVersion.substring(0, 1).toInt() - - if (javaVersion.startsWith("1.")) { - javaVersionNum = javaVersion.substring(2, 3).toInt() - } else { - if (versionPos == -1) versionPos = javaVersion.indexOf("-") - if (versionPos == -1) { - println("jdk version unknown") - } else { - javaVersionNum = javaVersion.substring(0, versionPos).toInt() - } - } - if (javaVersionNum >= 9) { - include(":mirai-console-graphical") - project(":mirai-console-graphical").projectDir = file("frontend/mirai-console-graphical") - } else { - println("JDK 版本为 $javaVersionNum") - println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用JDK 9以上版本引入模块 `:mirai-console-graphical`\n") + val jdkVersion = kotlin.runCatching { + System.getProperty("java.version").let { v -> + v.toIntOrNull() ?: v.removePrefix("1.").substringBefore("-").toIntOrNull() } + }.getOrNull() ?: -1 - } catch (ignored: Exception) { - println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`") + 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") \ No newline at end of file From 514183e79353ff1207de31bacc8f4d96e1ccd767 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 00:47:52 +0800 Subject: [PATCH 18/32] Fix warnings --- backend/codegen/build.gradle.kts | 2 +- frontend/mirai-console-graphical/build.gradle.kts | 2 +- frontend/mirai-console-pure/build.gradle.kts | 2 +- frontend/mirai-console-terminal/build.gradle.kts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/codegen/build.gradle.kts b/backend/codegen/build.gradle.kts index 93e6cd2f7..78077df4a 100644 --- a/backend/codegen/build.gradle.kts +++ b/backend/codegen/build.gradle.kts @@ -8,7 +8,7 @@ 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" diff --git a/frontend/mirai-console-graphical/build.gradle.kts b/frontend/mirai-console-graphical/build.gradle.kts index cb6168895..12bbba3b6 100644 --- a/frontend/mirai-console-graphical/build.gradle.kts +++ b/frontend/mirai-console-graphical/build.gradle.kts @@ -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") } diff --git a/frontend/mirai-console-pure/build.gradle.kts b/frontend/mirai-console-pure/build.gradle.kts index 0fc200fae..b26245fd1 100644 --- a/frontend/mirai-console-pure/build.gradle.kts +++ b/frontend/mirai-console-pure/build.gradle.kts @@ -12,7 +12,7 @@ kotlin { 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") diff --git a/frontend/mirai-console-terminal/build.gradle.kts b/frontend/mirai-console-terminal/build.gradle.kts index 27af40004..cea7f593a 100644 --- a/frontend/mirai-console-terminal/build.gradle.kts +++ b/frontend/mirai-console-terminal/build.gradle.kts @@ -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") } From 3743d9230e1240236cc7a4be41e637da5d0bdba3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 13:32:40 +0800 Subject: [PATCH 19/32] Rename :coregen to :mirai-console.codegen --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 17c9a06a2..4283675f6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,7 +28,7 @@ fun includeProject(projectPath: String, path: String? = null) { } includeProject(":mirai-console", "backend/mirai-console") -includeProject(":codegen", "backend/codegen") +includeProject(":mirai-console.codegen", "backend/codegen") includeProject(":mirai-console-pure", "frontend/mirai-console-pure") @Suppress("ConstantConditionIf") From 907b2ad9465c18f221ed6556d7d6c48e1f344ffe Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 13:43:28 +0800 Subject: [PATCH 20/32] Update codegen, rearrange entry point --- .../{SettingCodegen.kt => ValueKtCodegen.kt} | 25 ++++++++++--------- .../net/mamoe/mirai/console/codegen/util.kt | 6 ----- 2 files changed, 13 insertions(+), 18 deletions(-) rename backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/{SettingCodegen.kt => ValueKtCodegen.kt} (66%) diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueKtCodegen.kt similarity index 66% rename from backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt rename to backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueKtCodegen.kt index d6ac306e1..5f44ba567 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/SettingCodegen.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueKtCodegen.kt @@ -9,27 +9,28 @@ package net.mamoe.mirai.console.codegen -object SettingCodegen { - object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke { - override val defaultInvokeArgs: List - get() = KtType.Primitives + KtString - override fun StringBuilder.apply(ktType: KtType) { - @Suppress("ClassName") - appendKCode( - """ +object ValueKtCodegen { + object SettingCodegen { + object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke { + override val defaultInvokeArgs: List + get() = KtType.Primitives + KtString + + override fun StringBuilder.apply(ktType: KtType) { + @Suppress("ClassName") + appendKCode( + """ /** * Represents a non-null [$ktType] value. */ interface ${ktType}Value : PrimitiveValue<$ktType> """ - ) + ) + } } + } -} - -object ValueKtCodegen { @JvmStatic fun main(args: Array) { codegen("Value.kt") { diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt index 1d2b9da28..241f971cf 100644 --- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt +++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/util.kt @@ -119,10 +119,4 @@ fun String.findFileSmart(): File = kotlin.run { } }.also { require(it.exists()) { "file doesn't exist" } -} - -fun main() { - codegen("Value.kt") { - SettingCodegen.PrimitiveValuesCodegen() - } } \ No newline at end of file From 16cba3a87d88d1a7e35601968acb102b4c376c33 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 13:44:37 +0800 Subject: [PATCH 21/32] Update core version --- buildSrc/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index f80aaee49..050457830 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -8,7 +8,7 @@ */ object Versions { - const val core = "1.0.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" From 7ac1d94db9dbfe7cceaefc372606ab95ee9d3454 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 14:24:17 +0800 Subject: [PATCH 22/32] Add build constant auto-fill --- backend/mirai-console/build.gradle.kts | 29 +++++++++++++++++++ .../net/mamoe/mirai/console/MiraiConsole.kt | 26 +++++++++++------ .../mirai/console/MiraiConsoleFrontEnd.kt | 13 --------- .../console/pure/MiraiConsoleFrontEndPure.kt | 3 -- .../mirai/console/pure/MiraiConsolePure.kt | 3 -- 5 files changed, 46 insertions(+), 28 deletions(-) diff --git a/backend/mirai-console/build.gradle.kts b/backend/mirai-console/build.gradle.kts index 14d759c33..94a66ed5e 100644 --- a/backend/mirai-console/build.gradle.kts +++ b/backend/mirai-console/build.gradle.kts @@ -1,4 +1,6 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import upload.Bintray +import java.text.SimpleDateFormat import java.util.* plugins { @@ -74,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()}) // ${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 diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 5b9fe51fc..168d2d568 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -13,6 +13,8 @@ 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.utils.DefaultLogger @@ -21,6 +23,7 @@ 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 { @@ -33,26 +36,34 @@ internal object MiraiConsoleInitializer { } +internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants) + @JvmStatic + val buildDate: Date = Date(1592720608995) // 2020-06-21 14:23:28 + const val version: String = "0.5.1" +} + /** * mirai 控制台实例. */ object MiraiConsole : CoroutineScope, IMiraiConsole { + val pluginCenter: PluginCenter get() = CuiPluginCenter + 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 运行路径 @@ -89,9 +100,6 @@ object MiraiConsole : CoroutineScope, IMiraiConsole { // 前端使用 internal interface IMiraiConsole : CoroutineScope { - val build: String - val version: String - /** * Console 运行路径 */ diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt index f94a8eaea..48043cb76 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt @@ -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] */ diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt index 39f329382..850bff7a5 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt @@ -60,9 +60,6 @@ object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { override fun pushBot(bot: Bot) { } - override fun pushVersion(consoleVersion: String, consoleBuild: String, coreVersion: String) { - } - override suspend fun requestInput(hint: String): String { if (hint.isNotEmpty()) { ConsoleUtils.lineReader.printAbove( diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt index 5e0ab01a9..0cb890027 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt @@ -35,15 +35,12 @@ import kotlin.coroutines.EmptyCoroutineContext private val delegateScope = CoroutineScope(EmptyCoroutineContext) object MiraiConsolePure : IMiraiConsole { - override val build: String = "UNKNOWN" override val builtInPluginLoaders: List> = LinkedList() override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure override val mainLogger: MiraiLogger = DefaultLogger("Console") override val rootDir: File = File("./test/console").also { it.mkdirs() } - override val version: String - get() = "UNKNOWN" override val coroutineContext: CoroutineContext get() = delegateScope.coroutineContext } \ No newline at end of file From 4ce4c025ee8cae981bca2c107b0fd67f704a9810 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 15:27:19 +0800 Subject: [PATCH 23/32] Implement composite Values --- .../net/mamoe/mirai/console/MiraiConsole.kt | 2 +- .../mamoe/mirai/console/setting/Setting.kt | 17 ++- .../net/mamoe/mirai/console/setting/Value.kt | 31 ++-- .../setting/internal/ValueCreatorsImpl.kt | 39 ++++- .../setting/internal/ValueDeclarationsImpl.kt | 94 ++++++++++-- .../setting/internal/collectionUtil.kt | 141 +++++++++++++++++- .../mirai/console/setting/SettingTest.kt | 20 +++ 7 files changed, 308 insertions(+), 36 deletions(-) create mode 100644 backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 168d2d568..f63f56688 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -38,7 +38,7 @@ internal object MiraiConsoleInitializer { internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants) @JvmStatic - val buildDate: Date = Date(1592720608995) // 2020-06-21 14:23:28 + val buildDate: Date = Date(1592723625351) // 2020-06-21 15:13:45 const val version: String = "0.5.1" } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt index 2d32ddefc..153d78982 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -13,11 +13,14 @@ package net.mamoe.mirai.console.setting import net.mamoe.mirai.console.setting.internal.cast import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl +import net.mamoe.mirai.utils.MiraiExperimentalAPI 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() @@ -37,6 +40,13 @@ internal abstract class SettingImpl { private val valueNodes: List> = kotlin.run { TODO("reflection") } + + /** + * flatten + */ + internal fun onValueChanged(value: Value<*>) { + + } } @@ -50,7 +60,7 @@ fun Setting.value(value: Int): IntValue = TODO("codegen") /** - * Creates a [Value] with [default]. + * Creates a [Value] with reified type. * * @param T reified param type T. * Supports only primitives, Kotlin built-in collections, @@ -59,4 +69,7 @@ fun Setting.value(value: Int): IntValue = TODO("codegen") */ @LowPriorityInOverloadResolution @OptIn(ExperimentalStdlibApi::class) // stable in 1.4 -inline fun Setting.value(default: T): Value = valueFromKTypeImpl(typeOf()).cast() \ No newline at end of file +inline fun Setting.valueReified(default: T): Value = valueFromKTypeImpl(typeOf()).cast() + +@MiraiExperimentalAPI +fun Setting.valueFromKType(type: KType): Value = valueFromKTypeImpl(type).cast() \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index 8dee45afd..3383e532e 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -102,28 +102,29 @@ interface StringValue : PrimitiveValue @MiraiExperimentalAPI interface CompositeValue : Value + /** * Superclass of [CompositeListValue], [PrimitiveListValue]. */ -interface ListValue : CompositeValue> +interface ListValue : CompositeValue> /** * Elements can by anything, wrapped as [Value]. - * @param T is not primitive types. + * @param E is not primitive types. */ -interface CompositeListValue : ListValue> +interface CompositeListValue : ListValue /** * Elements can only be primitives, not wrapped. - * @param T is not primitive types. + * @param E is not primitive types. */ -interface PrimitiveListValue : ListValue +interface PrimitiveListValue : ListValue //// region PrimitiveListValue CODEGEN //// -interface PrimitiveIntListValue : PrimitiveListValue -interface PrimitiveLongListValue : PrimitiveListValue +interface PrimitiveIntListValue : PrimitiveListValue +interface PrimitiveLongListValue : PrimitiveListValue // TODO + codegen //// endregion PrimitiveListValue CODEGEN //// @@ -132,25 +133,25 @@ interface PrimitiveLongListValue : PrimitiveListValue /** * Superclass of [CompositeSetValue], [PrimitiveSetValue]. */ -interface SetValue : CompositeValue> +interface SetValue : CompositeValue> /** * Elements can by anything, wrapped as [Value]. - * @param T is not primitive types. + * @param E is not primitive types. */ -interface CompositeSetValue : SetValue> +interface CompositeSetValue : SetValue /** * Elements can only be primitives, not wrapped. - * @param T is not primitive types. + * @param E is not primitive types. */ -interface PrimitiveSetValue : SetValue +interface PrimitiveSetValue : SetValue //// region PrimitiveSetValue CODEGEN //// -interface PrimitiveIntSetValue : PrimitiveSetValue -interface PrimitiveLongSetValue : PrimitiveSetValue +interface PrimitiveIntSetValue : PrimitiveSetValue +interface PrimitiveLongSetValue : PrimitiveSetValue // TODO + codegen //// endregion PrimitiveSetValue CODEGEN //// @@ -161,7 +162,7 @@ interface PrimitiveLongSetValue : PrimitiveSetValue */ interface MapValue : CompositeValue> -interface CompositeMapValue : MapValue, Value> +interface CompositeMapValue : MapValue interface PrimitiveMapValue : MapValue diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt index e837c8eb1..8d1187d8a 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt @@ -13,6 +13,7 @@ package net.mamoe.mirai.console.setting.internal import net.mamoe.mirai.console.setting.Setting import net.mamoe.mirai.console.setting.Value +import net.mamoe.mirai.console.setting.valueFromKType import kotlin.reflect.KClass import kotlin.reflect.KType @@ -31,21 +32,53 @@ internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { when { classifier == Map::class -> { + val keyClass = type.arguments[0].type?.classifier + require(keyClass is KClass<*>) - TODO() + val valueClass = type.arguments[1].type?.classifier + require(valueClass is KClass<*>) + + if (keyClass.isPrimitiveOrBuiltInSerializableValue() && valueClass.isPrimitiveOrBuiltInSerializableValue()) { + // PrimitiveIntIntMap + // ... + TODO() + } else { + return createCompositeMapValueImpl( + kToValue = { valueFromKType(type.arguments[0].type!!) }, + vToValue = { valueFromKType(type.arguments[1].type!!) } + ) + } } classifier == List::class -> { + val elementClass = type.arguments[0].type?.classifier + require(elementClass is KClass<*>) - TODO() + if (elementClass.isPrimitiveOrBuiltInSerializableValue()) { + // PrimitiveIntList + // ... + TODO() + } else { + return createCompositeListValueImpl { valueFromKType(type.arguments[0].type!!) } + } } classifier == Set::class -> { - TODO() + val elementClass = type.arguments[0].type?.classifier + require(elementClass is KClass<*>) + + if (elementClass.isPrimitiveOrBuiltInSerializableValue()) { + // PrimitiveIntSet + // ... + TODO() + } else { + return createCompositeSetValueImpl { valueFromKType(type.arguments[0].type!!) } + } } 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, diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt index ce7a68627..c4726e915 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt @@ -11,9 +11,7 @@ package net.mamoe.mirai.console.setting.internal -import net.mamoe.mirai.console.setting.CompositeListValue -import net.mamoe.mirai.console.setting.IntValue -import net.mamoe.mirai.console.setting.Value +import net.mamoe.mirai.console.setting.* internal abstract class IntValueImpl : IntValue { constructor() @@ -35,13 +33,91 @@ internal abstract class IntValueImpl : IntValue { protected abstract fun onChanged() } -internal abstract class CompositeListValueImpl( - val tToValue: (T) -> Value -) : CompositeListValue { - private var _value: List> = mutableListOf() - override var value: List> +// type inference bug +internal fun Setting.createCompositeSetValueImpl(tToValue: (T) -> Value): CompositeSetValueImpl { + return object : CompositeSetValueImpl(tToValue) { + override fun onChanged() { + this@createCompositeSetValueImpl.onValueChanged(this) + } + } +} + +internal abstract class CompositeSetValueImpl( + tToValue: (T) -> Value // should override onChanged +) : CompositeSetValue { + private val internalSet: MutableSet> = mutableSetOf() + + private var _value: Set = internalSet.shadowMap({ it.value }, tToValue).observable { onChanged() } + + override var value: Set get() = _value set(v) { - _value = v + if (_value != v) { + onChanged() + _value = v + } } + + protected abstract fun onChanged() +} + + +// type inference bug +internal fun Setting.createCompositeListValueImpl(tToValue: (T) -> Value): CompositeListValueImpl { + return object : CompositeListValueImpl(tToValue) { + override fun onChanged() { + this@createCompositeListValueImpl.onValueChanged(this) + } + } +} + +internal abstract class CompositeListValueImpl( + tToValue: (T) -> Value // should override onChanged +) : CompositeListValue { + private val internalList: MutableList> = mutableListOf() + + private var _value: List = internalList.shadowMap({ it.value }, tToValue).observable { onChanged() } + + override var value: List + get() = _value + set(v) { + if (_value != v) { + onChanged() + _value = v + } + } + + protected abstract fun onChanged() +} + +// workaround to a type inference bug +internal fun Setting.createCompositeMapValueImpl( + kToValue: (K) -> Value, + vToValue: (V) -> Value +): CompositeMapValueImpl { + return object : CompositeMapValueImpl(kToValue, vToValue) { + override fun onChanged() { + this@createCompositeMapValueImpl.onValueChanged(this) + } + } +} + +internal abstract class CompositeMapValueImpl( + kToValue: (K) -> Value, // should override onChanged + vToValue: (V) -> Value // should override onChanged +) : CompositeMapValue { + private val internalList: MutableMap, Value> = mutableMapOf() + + private var _value: Map = + internalList.shadowMap({ it.value }, kToValue, { it.value }, vToValue).observable { onChanged() } + override var value: Map + get() = _value + set(v) { + if (_value != v) { + onChanged() + _value = v + } + } + + protected abstract fun onChanged() } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/collectionUtil.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/collectionUtil.kt index c686d2fdb..75208385a 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/collectionUtil.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/collectionUtil.kt @@ -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 MutableList.shadowMap(transform: (E) -> R, transformBack: (R) -> E): MutableList { +internal inline fun MutableMap.shadowMap( + crossinline kTransform: (K) -> KR, + crossinline kTransformBack: (KR) -> K, + crossinline vTransform: (V) -> VR, + crossinline vTransformBack: (VR) -> V +): MutableMap { + return object : MutableMap { + 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> + get() = this@shadowMap.entries.shadowMap( + transform = { entry: MutableMap.MutableEntry -> + object : MutableMap.MutableEntry { + 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) -> MutableMap.MutableEntry), // type inference bug + transformBack = { entry -> + object : MutableMap.MutableEntry { + 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 + get() = this@shadowMap.keys.shadowMap(kTransform, kTransformBack) + override val values: MutableCollection + 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) { + 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 MutableCollection.shadowMap( + crossinline transform: (E) -> R, + crossinline transformBack: (R) -> E +): MutableCollection { + return object : MutableCollection { + 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): Boolean = elements.all(::contains) + override fun isEmpty(): Boolean = this@shadowMap.isEmpty() + override fun iterator(): MutableIterator = object : MutableIterator { + 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): 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): Boolean = elements.all(::remove) + override fun retainAll(elements: Collection): Boolean = this@shadowMap.retainAll(elements.map(transformBack)) + } +} + +internal inline fun MutableList.shadowMap( + crossinline transform: (E) -> R, + crossinline transformBack: (R) -> E +): MutableList { return object : MutableList { override val size: Int get() = this@shadowMap.size @@ -78,7 +162,10 @@ internal fun MutableList.shadowMap(transform: (E) -> R, transformBack: } -internal fun MutableSet.shadowMap(transform: (E) -> R, transformBack: (R) -> E): MutableSet { +internal inline fun MutableSet.shadowMap( + crossinline transform: (E) -> R, + crossinline transformBack: (R) -> E +): MutableSet { return object : MutableSet { override val size: Int get() = this@shadowMap.size @@ -102,7 +189,7 @@ internal fun MutableSet.shadowMap(transform: (E) -> R, transformBack: } } -internal fun dynamicList(supplier: () -> List): List { +internal inline fun dynamicList(crossinline supplier: () -> List): List { return object : List { override val size: Int get() = supplier().size override fun contains(element: T): Boolean = supplier().contains(element) @@ -118,7 +205,7 @@ internal fun dynamicList(supplier: () -> List): List { } } -internal fun dynamicSet(supplier: () -> Set): Set { +internal inline fun dynamicSet(crossinline supplier: () -> Set): Set { return object : Set { override val size: Int get() = supplier().size override fun contains(element: T): Boolean = supplier().contains(element) @@ -129,7 +216,7 @@ internal fun dynamicSet(supplier: () -> Set): Set { } -internal fun dynamicMutableList(supplier: () -> MutableList): MutableList { +internal inline fun dynamicMutableList(crossinline supplier: () -> MutableList): MutableList { return object : MutableList { override val size: Int get() = supplier().size override fun contains(element: T): Boolean = supplier().contains(element) @@ -156,7 +243,7 @@ internal fun dynamicMutableList(supplier: () -> MutableList): MutableList } -internal fun dynamicMutableSet(supplier: () -> MutableSet): MutableSet { +internal inline fun dynamicMutableSet(crossinline supplier: () -> MutableSet): MutableSet { return object : MutableSet { override val size: Int get() = supplier().size override fun contains(element: T): Boolean = supplier().contains(element) @@ -172,6 +259,23 @@ internal fun dynamicMutableSet(supplier: () -> MutableSet): MutableSet } } +@Suppress("UNCHECKED_CAST", "USELESS_CAST") // type inference bug +internal inline fun MutableMap.observable(crossinline onChanged: () -> Unit): MutableMap { + return object : MutableMap, Map by (this as Map) { + override val keys: MutableSet + get() = this@observable.keys.observable(onChanged) + override val values: MutableCollection + get() = this@observable.values.observable(onChanged) + override val entries: MutableSet> + 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) = this@observable.putAll(from).also { onChanged() } + override fun remove(key: K): V? = this@observable.remove(key).also { onChanged() } + } +} + internal inline fun MutableList.observable(crossinline onChanged: () -> Unit): MutableList { return object : MutableList { override val size: Int get() = this@observable.size @@ -234,6 +338,31 @@ internal inline fun MutableList.observable(crossinline onChanged: () -> U } } +internal inline fun MutableCollection.observable(crossinline onChanged: () -> Unit): MutableCollection { + return object : MutableCollection { + override val size: Int get() = this@observable.size + override fun contains(element: T): Boolean = this@observable.contains(element) + override fun containsAll(elements: Collection): Boolean = this@observable.containsAll(elements) + override fun isEmpty(): Boolean = this@observable.isEmpty() + override fun iterator(): MutableIterator = object : MutableIterator { + 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): 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): Boolean = + this@observable.removeAll(elements).also { onChanged() } + + override fun retainAll(elements: Collection): Boolean = + this@observable.retainAll(elements).also { onChanged() } + } +} + internal inline fun MutableSet.observable(crossinline onChanged: () -> Unit): MutableSet { return object : MutableSet { override val size: Int get() = this@observable.size diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt new file mode 100644 index 000000000..370edeb1b --- /dev/null +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt @@ -0,0 +1,20 @@ +/* + * 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 { + + @Test + fun testPrimitive() { + + } +} \ No newline at end of file From ecd41bc4e02a9e44bfc4f45f8177ef4b097f7981 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 15:38:47 +0800 Subject: [PATCH 24/32] Rearrange files --- .../mamoe/mirai/console/setting/Setting.kt | 3 +- ...larationsImpl.kt => CompositeValueImpl.kt} | 19 --------- ...mpl.kt => Setting.value composite impl.kt} | 0 .../internal/_PrimitiveValueDeclareations.kt | 39 +++++++++++++++++++ .../setting/internal/_Setting.value.kt | 24 ++++++++++++ .../{internal.kt => serializerUtil.kt} | 0 6 files changed, 65 insertions(+), 20 deletions(-) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/{ValueDeclarationsImpl.kt => CompositeValueImpl.kt} (87%) rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/{ValueCreatorsImpl.kt => Setting.value composite impl.kt} (100%) create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclareations.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/{internal.kt => serializerUtil.kt} (100%) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt index 153d78982..923a4d890 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -13,6 +13,7 @@ package net.mamoe.mirai.console.setting 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 kotlin.internal.LowPriorityInOverloadResolution import kotlin.reflect.KProperty @@ -54,7 +55,7 @@ internal abstract class SettingImpl { // TODO: 2020/6/19 CODEGEN -fun Setting.value(value: Int): IntValue = TODO("codegen") +fun Setting.value(default: Int): IntValue = valueImpl(default) //// endregion Setting.value primitives CODEGEN //// diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/CompositeValueImpl.kt similarity index 87% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/CompositeValueImpl.kt index c4726e915..1b611fe9d 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueDeclarationsImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/CompositeValueImpl.kt @@ -13,25 +13,6 @@ package net.mamoe.mirai.console.setting.internal import net.mamoe.mirai.console.setting.* -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() -} // type inference bug internal fun Setting.createCompositeSetValueImpl(tToValue: (T) -> Value): CompositeSetValueImpl { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt similarity index 100% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/ValueCreatorsImpl.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclareations.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclareations.kt new file mode 100644 index 000000000..650200b97 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_PrimitiveValueDeclareations.kt @@ -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 //// diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt new file mode 100644 index 000000000..76e8e5331 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt @@ -0,0 +1,24 @@ +/* + * 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 +import net.mamoe.mirai.console.setting.Setting + + +//// region Setting.value primitives impl CODEGEN //// + +// TODO: 2020/6/21 CODEGEN + +internal fun Setting.valueImpl(default: Int): IntValue = object : IntValueImpl(default) { + override fun onChanged() = this@valueImpl.onValueChanged(this) +} + +//// endregion Setting.value primitives impl CODEGEN //// diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt similarity index 100% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/internal.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt From 2c09f1d82da52c1ebc57f90aad5f000b1c9512f6 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 21 Jun 2020 22:48:34 +0800 Subject: [PATCH 25/32] value delegating --- .../net/mamoe/mirai/console/setting/Setting.kt | 14 +++++++++++--- .../net/mamoe/mirai/console/setting/Value.kt | 8 +++++++- .../console/setting/internal/serializerUtil.kt | 5 ----- .../net/mamoe/mirai/console/setting/SettingTest.kt | 6 ++++++ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt index 923a4d890..cac3cace6 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -23,7 +23,15 @@ 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() +abstract class Setting : SettingImpl() { + + operator fun Value.provideDelegate(thisRef: Any?, property: KProperty<*>): Value { + @Suppress("UNCHECKED_CAST") + valueNodes.add(Node(property as KProperty, value as Value, TODO())) + // TODO: 2020/6/21 track on + return this + } +} /** * Internal implementation for [Setting] including: @@ -32,13 +40,13 @@ abstract class Setting : SettingImpl() */ // TODO move to internal package. internal abstract class SettingImpl { - private class Node( + internal class Node( val property: KProperty, val value: Value, val serializer: ValueSerializer ) - private val valueNodes: List> = kotlin.run { + internal val valueNodes: MutableList> = kotlin.run { TODO("reflection") } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index 3383e532e..270914b40 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -7,12 +7,13 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused") +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused", "NOTHING_TO_INLINE") package net.mamoe.mirai.console.setting import kotlinx.serialization.KSerializer import net.mamoe.mirai.utils.MiraiExperimentalAPI +import kotlin.reflect.KProperty /** * Represents a observable, immutable value wrapping. @@ -28,6 +29,11 @@ interface Value { var value: T } +inline operator fun Value.getValue(mySetting: Any?, property: KProperty<*>): T = value +inline operator fun Value.setValue(mySetting: Any?, property: KProperty<*>, value: T) { + this.value = value +} + /** * The serializer for a specific kind of [Value]. */ diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt index b054b31b8..1abad6b95 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt @@ -10,11 +10,6 @@ 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 diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt index 370edeb1b..011486cc5 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt @@ -13,6 +13,12 @@ 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() { From 4f418e7a0b07b2a29642c569ca1008326595ca6a Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Mon, 22 Jun 2020 12:14:03 +0800 Subject: [PATCH 26/32] Initialize MiraiConsole when MiraiConsoleInitializer.init called --- .../src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index f63f56688..7cf716a36 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -32,6 +32,7 @@ internal object MiraiConsoleInitializer { /** 由前端调用 */ internal fun init(instance: IMiraiConsole) { this.instance = instance + MiraiConsole.initialize() } } @@ -95,6 +96,10 @@ object MiraiConsole : CoroutineScope, IMiraiConsole { @MiraiExperimentalAPI fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity) + + internal fun initialize() { + // Only for initialize + } } From b3f846ed1660dd501ed4d94ec87e3f31f5ff29fc Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Mon, 22 Jun 2020 12:30:36 +0800 Subject: [PATCH 27/32] Update auto-fill --- backend/mirai-console/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/mirai-console/build.gradle.kts b/backend/mirai-console/build.gradle.kts index 94a66ed5e..c04b32633 100644 --- a/backend/mirai-console/build.gradle.kts +++ b/backend/mirai-console/build.gradle.kts @@ -85,7 +85,7 @@ tasks { file.writeText(file.readText() .replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) { """ - val buildDate: Date = Date(${System.currentTimeMillis()}) // ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").apply { + val buildDate: Date = Date(${System.currentTimeMillis()}L) // ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").apply { timeZone = TimeZone.getTimeZone("GMT+8") }.format(Date())} """.trimIndent() From 2620d323e634d474b1daab22d86970387a1dfb9e Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Mon, 22 Jun 2020 12:32:33 +0800 Subject: [PATCH 28/32] Change logger loading method --- .../console/pure/MiraiConsoleFrontEndPure.kt | 15 +++++++++++---- .../mirai/console/pure/MiraiConsolePureLoader.kt | 10 ---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt index 850bff7a5..e8dc2ef2e 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt @@ -13,18 +13,26 @@ package net.mamoe.mirai.console.pure //import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsoleFrontEnd -import net.mamoe.mirai.utils.DefaultLogger 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 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 = DefaultLogger("Mirai") + private val globalLogger = LoggerCreator("Mirai") private val cachedLoggers = ConcurrentHashMap() // companion object { @@ -49,7 +57,7 @@ object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { override fun loggerFor(identity: String?): MiraiLogger { identity?.apply { - return cachedLoggers.computeIfAbsent(this, DefaultLogger) + return cachedLoggers.computeIfAbsent(this, LoggerCreator) } return globalLogger } @@ -82,7 +90,6 @@ object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { } ) } - } /* diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt index 72dd8c6fa..5d0e58f2d 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt @@ -36,18 +36,8 @@ object MiraiConsolePureLoader { } } -private val ANSI_RESET = Ansi().reset().toString() - -internal fun overrideLoggingSystem() { - DefaultLogger = { - PlatformLogger(identity = it, output = { line -> - ConsoleUtils.lineReader.printAbove(line + ANSI_RESET) - }) - } -} internal fun startup() { - overrideLoggingSystem() MiraiConsoleInitializer.init(MiraiConsolePure) startConsoleThread() } From 64d13f0a1956ca20d127fd35faed77a40ef7cce9 Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Mon, 22 Jun 2020 12:49:02 +0800 Subject: [PATCH 29/32] Update command execute result --- .../net/mamoe/mirai/console/MiraiConsole.kt | 2 +- .../mirai/console/command/CommandManager.kt | 57 ++++++++++++++++--- frontend/mirai-console-pure/build.gradle.kts | 19 ++----- .../console/pure/MiraiConsolePureLoader.kt | 19 ++++--- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 7cf716a36..aa40060db 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -39,7 +39,7 @@ internal object MiraiConsoleInitializer { internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants) @JvmStatic - val buildDate: Date = Date(1592723625351) // 2020-06-21 15:13:45 + val buildDate: Date = Date(1592799753404L) // 2020-06-22 12:22:33 const val version: String = "0.5.1" } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt index 2a5cca566..7cf78b6ae 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt @@ -138,8 +138,10 @@ fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock { * * @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(' ') }) @@ -154,8 +156,10 @@ internal inline fun List.dropToTypedArray(n: Int): Array = Arr * * @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,44 @@ 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 -} \ No newline at end of file + 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 + ) +} + +/** + * 命令的执行返回 + */ +class CommandExecuteResult( + val status: CommandExecuteStatus, + val exception: Throwable? = null, + val command: Command? = null, + val commandName: String? = null +) { + /** + * 命令的执行状态 + */ + enum class CommandExecuteStatus { + SUCCESSFUL, FAILED, COMMAND_NOT_FOUND, EMPTY_COMMAND + } + +} +typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus diff --git a/frontend/mirai-console-pure/build.gradle.kts b/frontend/mirai-console-pure/build.gradle.kts index b26245fd1..ea7d4c798 100644 --- a/frontend/mirai-console-pure/build.gradle.kts +++ b/frontend/mirai-console-pure/build.gradle.kts @@ -22,22 +22,13 @@ kotlin { } } -var debugging = true - dependencies { - fun import0(dep: Any) { - if (debugging) { - implementation(dep) - } else { - compileOnly(dep) - } - } - import0("org.jline:jline:3.15.0") - import0("org.fusesource.jansi:jansi:1.18") + implementation("org.jline:jline:3.15.0") + implementation("org.fusesource.jansi:jansi:1.18") - import0(project(":mirai-console")) - import0("net.mamoe:mirai-core:${Versions.core}") - import0(kotlin("stdlib")) // embedded by core + 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")) diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt index 5d0e58f2d..ad142caa5 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt @@ -20,13 +20,12 @@ package net.mamoe.mirai.console.pure 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 net.mamoe.mirai.utils.PlatformLogger -import org.fusesource.jansi.Ansi import kotlin.concurrent.thread object MiraiConsolePureLoader { @@ -49,12 +48,18 @@ internal fun startConsoleThread() { while (true) { val next = MiraiConsoleFrontEndPure.requestInput("") consoleLogger.debug("INPUT> $next") - kotlin.runCatching { - if (!ConsoleCS.executeCommand(PlainText(next))) { // No such command - consoleLogger.warning("Unknown command: " + next.split(' ')[0]) + 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}") } - }.onFailure { - consoleLogger.error("Exception in executing command: $next", it) } } } From 68c01427659b1db08f410a790eb46adbc6ee32c8 Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Mon, 22 Jun 2020 13:12:32 +0800 Subject: [PATCH 30/32] Update JCommandManager; Add KDoc --- .../console/command/JCommandManager.java | 8 +++---- .../mirai/console/command/CommandManager.kt | 23 +++++++++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java index e9e803446..58d922319 100644 --- a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java +++ b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java @@ -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 executeCommandAsync(final @NotNull CoroutineScope scope, final @NotNull CommandSender sender, final @NotNull Object... args) { + public static CompletableFuture 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"); diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt index 7cf78b6ae..56d980cda 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt @@ -134,7 +134,7 @@ fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock { * Java 调用方式: ` CommandManager.executeCommand(Command)` * * @param messages 接受 [String] 或 [Message], 其他对象将会被 [Any.toString] - * @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配 + * @see CommandExecuteResult * * @see JCommandManager.executeCommand Java 方法 */ @@ -152,7 +152,7 @@ internal inline fun List.dropToTypedArray(n: Int): Array = Arr /** * 解析并执行一个指令 - * @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配 + * @see CommandExecuteResult * * @see JCommandManager.executeCommand Java 方法 */ @@ -192,6 +192,14 @@ internal suspend inline fun CommandSender.executeCommandInternal( /** * 命令的执行返回 + * + * @param status 命令最终执行状态 + * @param exception 命令执行时发生的错误(如果有) + * @param command 尝试执行的命令 (status = SUCCESSFUL | FAILED) + * @param commandName 尝试执行的命令的名字 (status != EMPTY_COMMAND) + * + * + * @see CommandExecuteStatus */ class CommandExecuteResult( val status: CommandExecuteStatus, @@ -201,10 +209,21 @@ class CommandExecuteResult( ) { /** * 命令的执行状态 + * + * 当为 [SUCCESSFUL] 的时候,代表命令执行成功 + * + * 当为 [FAILED] 的时候, 代表命令执行出现了错误 + * + * 当为 [COMMAND_NOT_FOUND] 的时候,代表没有匹配的命令 + * + * 当为 [EMPTY_COMMAND] 的时候, 代表尝试执行 "" + * */ enum class CommandExecuteStatus { SUCCESSFUL, FAILED, COMMAND_NOT_FOUND, EMPTY_COMMAND } } + +@Suppress("RemoveRedundantQualifierName") typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus From 14d698651a5c5cc6d5e694af2e61c5524e3f717b Mon Sep 17 00:00:00 2001 From: Him188 Date: Mon, 22 Jun 2020 13:50:34 +0800 Subject: [PATCH 31/32] Introduce SerializableValue, SerializerAwareValue --- .../mamoe/mirai/console/setting/Setting.kt | 20 ++++++++++--------- .../net/mamoe/mirai/console/setting/Value.kt | 18 +++++++++++++++++ .../setting/internal/_Setting.value.kt | 13 +++++++++--- .../setting/internal/serializerUtil.kt | 2 -- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt index cac3cace6..af9709d68 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -11,10 +11,12 @@ 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 @@ -25,10 +27,12 @@ import kotlin.reflect.typeOf // Shows public APIs such as deciding when to auto-save. abstract class Setting : SettingImpl() { - operator fun Value.provideDelegate(thisRef: Any?, property: KProperty<*>): Value { + operator fun SerializerAwareValue.provideDelegate( + thisRef: Any?, + property: KProperty<*> + ): SerializerAwareValue { @Suppress("UNCHECKED_CAST") - valueNodes.add(Node(property as KProperty, value as Value, TODO())) - // TODO: 2020/6/21 track on + valueNodes.add(Node(property as KProperty, this, this.serializer)) return this } } @@ -43,18 +47,16 @@ internal abstract class SettingImpl { internal class Node( val property: KProperty, val value: Value, - val serializer: ValueSerializer + val updaterSerializer: KSerializer ) - internal val valueNodes: MutableList> = kotlin.run { - TODO("reflection") - } + internal val valueNodes: MutableList> = Collections.synchronizedList(mutableListOf()) /** * flatten */ internal fun onValueChanged(value: Value<*>) { - + // TODO: 2020/6/22 } } @@ -63,7 +65,7 @@ internal abstract class SettingImpl { // TODO: 2020/6/19 CODEGEN -fun Setting.value(default: Int): IntValue = valueImpl(default) +fun Setting.value(default: Int): SerializableValue = valueImpl(default) //// endregion Setting.value primitives CODEGEN //// diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index 270914b40..0458bfab6 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -29,6 +29,24 @@ interface Value { var value: T } +/** + * Typically returned by [Setting.value] functions. + */ +class SerializableValue( + delegate: Value, + /** + * The serializer used to update and dump [delegate] + */ + override val serializer: KSerializer +) : Value by delegate, SerializerAwareValue + +/** + * @see SerializableValue + */ +interface SerializerAwareValue : Value { + val serializer: KSerializer +} + inline operator fun Value.getValue(mySetting: Any?, property: KProperty<*>): T = value inline operator fun Value.setValue(mySetting: Any?, property: KProperty<*>, value: T) { this.value = value diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt index 76e8e5331..019b42489 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_Setting.value.kt @@ -9,7 +9,8 @@ package net.mamoe.mirai.console.setting.internal -import net.mamoe.mirai.console.setting.IntValue +import kotlinx.serialization.builtins.serializer +import net.mamoe.mirai.console.setting.SerializableValue import net.mamoe.mirai.console.setting.Setting @@ -17,8 +18,14 @@ import net.mamoe.mirai.console.setting.Setting // TODO: 2020/6/21 CODEGEN -internal fun Setting.valueImpl(default: Int): IntValue = object : IntValueImpl(default) { - override fun onChanged() = this@valueImpl.onValueChanged(this) +internal fun Setting.valueImpl(default: Int): SerializableValue { + 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 //// diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt index 1abad6b95..454544929 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/serializerUtil.kt @@ -13,8 +13,6 @@ import kotlinx.serialization.* import kotlin.reflect.KProperty import kotlin.reflect.full.findAnnotation -internal object SettingSerializerMark - internal val KProperty<*>.serialNameOrPropertyName: String get() = this.findAnnotation()?.value ?: this.name internal inline fun KSerializer.bind( From 1f0b7e4f0164d43d8d6f76ffca42583cf81568af Mon Sep 17 00:00:00 2001 From: Him188 Date: Mon, 22 Jun 2020 14:00:45 +0800 Subject: [PATCH 32/32] Support Any type in valueReified --- .../mamoe/mirai/console/setting/Setting.kt | 4 +- .../net/mamoe/mirai/console/setting/Value.kt | 7 ++ .../internal/Setting.value composite impl.kt | 74 ++++++++++++++++--- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt index af9709d68..8999c61c5 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt @@ -80,7 +80,7 @@ fun Setting.value(default: Int): SerializableValue = valueImpl(default) */ @LowPriorityInOverloadResolution @OptIn(ExperimentalStdlibApi::class) // stable in 1.4 -inline fun Setting.valueReified(default: T): Value = valueFromKTypeImpl(typeOf()).cast() +inline fun Setting.valueReified(default: T): SerializableValue = valueFromKTypeImpl(typeOf()).cast() @MiraiExperimentalAPI -fun Setting.valueFromKType(type: KType): Value = valueFromKTypeImpl(type).cast() \ No newline at end of file +fun Setting.valueFromKType(type: KType): SerializableValue = valueFromKTypeImpl(type).cast() \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt index 0458bfab6..7a3d7b6e4 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt @@ -12,6 +12,7 @@ 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 @@ -40,6 +41,12 @@ class SerializableValue( override val serializer: KSerializer ) : Value by delegate, SerializerAwareValue +fun Value.serializableValueWith( + serializer: KSerializer +): SerializableValue { + return SerializableValue(this, serializer.map(serializer = { this.value }, deserializer = { this.value = it })) +} + /** * @see SerializableValue */ diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt index 8d1187d8a..83f29ea69 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/Setting.value composite impl.kt @@ -11,16 +11,21 @@ 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.Value +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") -internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { +@Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE", "UNCHECKED_CAST") +internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> { val classifier = type.classifier require(classifier is KClass<*>) @@ -30,8 +35,8 @@ internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { // 复合类型 - when { - classifier == Map::class -> { + when (classifier) { + Map::class -> { val keyClass = type.arguments[0].type?.classifier require(keyClass is KClass<*>) @@ -46,10 +51,10 @@ internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { return createCompositeMapValueImpl( kToValue = { valueFromKType(type.arguments[0].type!!) }, vToValue = { valueFromKType(type.arguments[1].type!!) } - ) + ).serializableValueWith(serializerMirai(type) as KSerializer>) // erased } } - classifier == List::class -> { + List::class -> { val elementClass = type.arguments[0].type?.classifier require(elementClass is KClass<*>) @@ -59,9 +64,10 @@ internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { TODO() } else { return createCompositeListValueImpl { valueFromKType(type.arguments[0].type!!) } + .serializableValueWith(serializerMirai(type) as KSerializer>) } } - classifier == Set::class -> { + Set::class -> { val elementClass = type.arguments[0].type?.classifier require(elementClass is KClass<*>) @@ -71,6 +77,7 @@ internal fun Setting.valueFromKTypeImpl(type: KType): Value<*> { TODO() } else { return createCompositeSetValueImpl { valueFromKType(type.arguments[0].type!!) } + .serializableValueWith(serializerMirai(type) as KSerializer>) } } else -> error("Custom composite value is not supported yet (${classifier.qualifiedName})") @@ -92,4 +99,53 @@ internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean { @PublishedApi @Suppress("UNCHECKED_CAST") -internal inline fun T.cast(): R = this as R \ No newline at end of file +internal inline fun 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 { + fun serializerByKTypeImpl(type: KType): KSerializer { + val rootClass = when (val t = type.classifier) { + is KClass<*> -> t + else -> error("Only KClass supported as classifier, got $t") + } as KClass + + 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, 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() +}