Merge remote-tracking branch 'origin/master'

This commit is contained in:
Him188 2020-11-16 08:03:03 +08:00
commit 2b0fa30c35
15 changed files with 150 additions and 77 deletions

View File

@ -32,6 +32,7 @@ dependencies {
smartImplementation(yamlkt) smartImplementation(yamlkt)
smartImplementation(`jetbrains-annotations`) smartImplementation(`jetbrains-annotations`)
smartImplementation(`caller-finder`)
smartApi(`kotlinx-coroutines-jdk8`) smartApi(`kotlinx-coroutines-jdk8`)
testApi(`mirai-core-qqandroid`) testApi(`mirai-core-qqandroid`)

View File

@ -102,29 +102,31 @@ public object BuiltInCommands {
@Handler @Handler
public suspend fun CommandSender.handle() { public suspend fun CommandSender.handle() {
kotlin.runCatching { GlobalScope.launch {
closingLock.withLock { kotlin.runCatching {
sendMessage("Stopping mirai-console") closingLock.withLock {
kotlin.runCatching { if (!MiraiConsole.isActive) return@withLock
runIgnoreException<CancellationException> { MiraiConsole.job.cancelAndJoin() } sendMessage("Stopping mirai-console")
}.fold( kotlin.runCatching {
onSuccess = { MiraiConsole.job.cancelAndJoin()
runIgnoreException<EventCancelledException> { sendMessage("mirai-console stopped successfully.") } }.fold(
}, onSuccess = {
onFailure = { runIgnoreException<EventCancelledException> { sendMessage("mirai-console stopped successfully.") }
if (it is CancellationException) return@fold },
@OptIn(ConsoleInternalApi::class) onFailure = {
MiraiConsole.mainLogger.error("Exception in stop", it) @OptIn(ConsoleInternalApi::class)
runIgnoreException<EventCancelledException> { MiraiConsole.mainLogger.error("Exception in stop", it)
sendMessage( runIgnoreException<EventCancelledException> {
it.localizedMessage ?: it.message ?: it.toString() sendMessage(
) it.localizedMessage ?: it.message ?: it.toString()
)
}
} }
} )
) }
} }.exceptionOrNull()?.let(MiraiConsole.mainLogger::error)
}.exceptionOrNull()?.let(MiraiConsole.mainLogger::error) exitProcess(0)
exitProcess(0) }
} }
} }

View File

@ -14,8 +14,8 @@ import java.time.Instant
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants) internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
@JvmStatic @JvmStatic
val buildDate: Instant = Instant.ofEpochSecond(1604041264) val buildDate: Instant = Instant.ofEpochSecond(1605147625)
const val versionConst: String = "1.0-RC-1" const val versionConst: String = "1.0-RC2-dev-4"
@JvmStatic @JvmStatic
val version: SemVersion = SemVersion(versionConst) val version: SemVersion = SemVersion(versionConst)

View File

@ -11,6 +11,9 @@
package net.mamoe.mirai.console.internal.util package net.mamoe.mirai.console.internal.util
import io.github.karlatemp.caller.StackFrame
import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl
internal inline fun <reified E : Throwable, R> runIgnoreException(block: () -> R): R? { internal inline fun <reified E : Throwable, R> runIgnoreException(block: () -> R): R? {
try { try {
return block() return block()
@ -29,18 +32,9 @@ internal inline fun <reified E : Throwable> runIgnoreException(block: () -> Unit
} }
} }
internal fun getCallerClassloader(): ClassLoader? { internal fun StackFrame.findLoader(): ClassLoader? {
classInstance?.let { return it.classLoader }
return runCatching { return runCatching {
/* BuiltInJvmPluginLoaderImpl.classLoaders.firstOrNull { it.findClass(className, true) != null }
java.base/java.lang.Thread.getStackTrace(Thread.java:1598)
net.mamoe.mirai.console.internal.util.CommonUtils.getCallerClassloader(CommonUtils.kt:37)
net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription$Companion.loadFromResource$default(JvmPluginDescription.kt:67)
net.mamoe.mirai.console.KotlinP.<init>(TestMiraiConosle.kt:34)
net.mamoe.mirai.console.KotlinP.<clinit>(TestMiraiConosle.kt:34)
net.mamoe.mirai.console.TestMiraiConosleKt.main(TestMiraiConosle.kt:37)
net.mamoe.mirai.console.TestMiraiConosleKt.main(TestMiraiConosle.kt)
*/
val traces = Thread.currentThread().stackTrace
Class.forName(traces[3].className).classLoader
}.getOrNull() }.getOrNull()
} }

View File

@ -11,10 +11,12 @@
package net.mamoe.mirai.console.plugin.jvm package net.mamoe.mirai.console.plugin.jvm
import io.github.karlatemp.caller.CallerFinder
import io.github.karlatemp.caller.StackFrame
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.console.compiler.common.ResolveContext import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.* import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.*
import net.mamoe.mirai.console.internal.util.getCallerClassloader import net.mamoe.mirai.console.internal.util.findLoader
import net.mamoe.mirai.console.plugin.description.PluginDependency import net.mamoe.mirai.console.plugin.description.PluginDependency
import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.description.PluginDescription
import net.mamoe.mirai.console.util.SemVersion import net.mamoe.mirai.console.util.SemVersion
@ -65,13 +67,13 @@ public interface JvmPluginDescription : PluginDescription {
* [pluginClassloader] 读取资源文件 [filename] 并以 YAML 格式解析为 [SimpleJvmPluginDescription] * [pluginClassloader] 读取资源文件 [filename] 并以 YAML 格式解析为 [SimpleJvmPluginDescription]
* *
* @param filename [ClassLoader.getResourceAsStream] 的参数 `name` * @param filename [ClassLoader.getResourceAsStream] 的参数 `name`
* @param pluginClassloader 默认通过 [Thread.getStackTrace] 获取调用方 [Class] 然后获取其 [Class.getClassLoader]. * @param pluginClassloader 默认通过 [CallerFinder.getCaller] 获取调用方 [StackFrame] 然后获取其 [Class.getClassLoader].
*/ */
@JvmOverloads // @JvmOverloads // compiler error
@JvmStatic @JvmStatic
public fun loadFromResource( public fun loadFromResource(
filename: String = "plugin.yml", filename: String = "plugin.yml",
pluginClassloader: ClassLoader = getCallerClassloader() ?: error("Cannot find caller classloader, please specify manually."), pluginClassloader: ClassLoader = CallerFinder.getCaller()?.findLoader() ?: error("Cannot find caller classloader, please specify manually."),
): JvmPluginDescription { ): JvmPluginDescription {
val stream = pluginClassloader.getResourceAsStream(filename) ?: error("Cannot find plugin description resource '$filename'") val stream = pluginClassloader.getResourceAsStream(filename) ?: error("Cannot find plugin description resource '$filename'")

View File

@ -94,21 +94,16 @@ internal constructor(
*/ */
val rule: String, val rule: String,
) { ) {
init {
kotlin.runCatching {
parseRangeRequirement(rule)
}.onFailure {
throw java.lang.IllegalArgumentException("Syntax error: $rule", it)
}
}
@Transient @Transient
private val impl = SemVersionInternal.parseRangeRequirement(rule) internal val impl = kotlin.runCatching {
SemVersionInternal.parseRangeRequirement(rule)
}.getOrElse {
throw java.lang.IllegalArgumentException("Syntax error: $rule", it)
}
/** 在 [version] 满足此要求时返回 true */ /** 在 [version] 满足此要求时返回 true */
public fun test(version: SemVersion): Boolean { public fun test(version: SemVersion): Boolean = impl.test(version)
return impl.test(version)
}
/** /**
* 序列化为字符串, [rule]. 从字符串反序列化, [parseRangeRequirement]. * 序列化为字符串, [rule]. 从字符串反序列化, [parseRangeRequirement].

View File

@ -43,6 +43,16 @@ internal class TestSemVersion {
assert("1.0.0-rc.1".sem() < "1.0.0".sem()) assert("1.0.0-rc.1".sem() < "1.0.0".sem())
} }
@Test
internal fun testRequirementCopy() {
fun SemVersion.Requirement.check(a: SemVersion.Requirement.() -> SemVersion.Requirement) {
assert(a().impl !== this.impl)
}
SemVersion.parseRangeRequirement("1.0").check { copy() }
SemVersion.parseRangeRequirement("1.0").check { copy("2.0") }
SemVersion.parseRangeRequirement("1.0").check { copy("1.0") }
}
@Test @Test
internal fun testRequirement() { internal fun testRequirement() {
fun SemVersion.Requirement.assert(version: String): SemVersion.Requirement { fun SemVersion.Requirement.assert(version: String): SemVersion.Requirement {

View File

@ -26,6 +26,7 @@ allprojects {
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
jcenter() jcenter()
mavenCentral() mavenCentral()
maven(url = "https://dl.bintray.com/karlatemp/misc")
} }
} }

View File

@ -11,7 +11,7 @@
object Versions { object Versions {
const val core = "1.3.3" const val core = "1.3.3"
const val console = "1.0-RC2-dev-4" const val console = "1.0-RC2-dev-6"
const val consoleGraphical = "0.0.7" const val consoleGraphical = "0.0.7"
const val consoleTerminal = console const val consoleTerminal = console
@ -63,3 +63,6 @@ const val `mirai-core-api` = "net.mamoe:mirai-core-api:${Versions.core}"
const val yamlkt = "net.mamoe.yamlkt:yamlkt:${Versions.yamlkt}" const val yamlkt = "net.mamoe.yamlkt:yamlkt:${Versions.yamlkt}"
const val `jetbrains-annotations` = "org.jetbrains:annotations:19.0.0" const val `jetbrains-annotations` = "org.jetbrains:annotations:19.0.0"
const val `caller-finder` = "io.github.karlatemp:caller:1.0.1"

View File

@ -9,10 +9,7 @@
package net.mamoe.mirai.console.terminal package net.mamoe.mirai.console.terminal
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.command.* import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
@ -30,12 +27,13 @@ internal fun startupConsoleThread() {
if (terminal is NoConsole) return if (terminal is NoConsole) return
MiraiConsole.launch(CoroutineName("Input Cancelling Daemon")) { MiraiConsole.launch(CoroutineName("Input Cancelling Daemon")) {
while (true) { while (isActive) {
delay(2000) delay(2000)
} }
}.invokeOnCompletion { }.invokeOnCompletion {
runCatching<Unit> { runCatching<Unit> {
terminal.close() // 应该仅关闭用户输入
terminal.reader().shutdown()
ConsoleInputImpl.thread.shutdownNow() ConsoleInputImpl.thread.shutdownNow()
runCatching { runCatching {
ConsoleInputImpl.executingCoroutine?.cancel(EndOfFileException()) ConsoleInputImpl.executingCoroutine?.cancel(EndOfFileException())

View File

@ -96,6 +96,9 @@ class MiraiConsoleGradlePlugin : Plugin<Project> {
compilations.forEach { compilations.forEach {
dependsOn(it.compileKotlinTask) dependsOn(it.compileKotlinTask)
from(it.output) from(it.output)
for (allKotlinSourceSet in it.allKotlinSourceSets) {
from(allKotlinSourceSet.resources)
}
} }
from(project.configurations.getByName("runtimeClasspath").copyRecursive { dependency -> from(project.configurations.getByName("runtimeClasspath").copyRecursive { dependency ->

View File

@ -10,6 +10,6 @@
package net.mamoe.mirai.console.gradle package net.mamoe.mirai.console.gradle
internal object VersionConstants { internal object VersionConstants {
const val CONSOLE_VERSION = "1.0-RC2-dev-4" // value is written here automatically during build const val CONSOLE_VERSION = "1.0-RC2-dev-6" // value is written here automatically during build
const val CORE_VERSION = "1.3.3" // value is written here automatically during build const val CORE_VERSION = "1.3.3" // value is written here automatically during build
} }

View File

@ -2,6 +2,7 @@ package org.example.myplugin
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.console.data.AutoSavePluginConfig import net.mamoe.mirai.console.data.AutoSavePluginConfig
import net.mamoe.mirai.console.data.AutoSavePluginData
import net.mamoe.mirai.console.data.value import net.mamoe.mirai.console.data.value
import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.console.permission.PermissionId
import net.mamoe.mirai.console.permission.PermissionService import net.mamoe.mirai.console.permission.PermissionService
@ -29,3 +30,9 @@ object MyPluginMain : KotlinPlugin(
} }
} }
object MyData : AutoSavePluginData("") {
val value by value("")
val value2 by value<Map<String, String>>()
}

View File

@ -18,10 +18,12 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.inspections.collections.isCalling import org.jetbrains.kotlin.idea.inspections.collections.isCalling
import org.jetbrains.kotlin.idea.refactoring.fqName.fqName import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class PluginDataValuesChecker : DeclarationChecker { class PluginDataValuesChecker : DeclarationChecker {
@ -39,22 +41,23 @@ class PluginDataValuesChecker : DeclarationChecker {
&& t is SimpleType && t is SimpleType
}.forEach { (e, callExpr) -> }.forEach { (e, callExpr) ->
val (_, type) = e val (_, type) = e
val classDescriptor = type.constructor.declarationDescriptor?.castOrNull<ClassDescriptor>() val classDescriptor = type.constructor.declarationDescriptor?.castOrNull<ClassDescriptor>() ?: return@forEach
if (canBeSerializedInternally(classDescriptor)) return@forEach
val inspectionTarget = kotlin.run { val inspectionTarget = kotlin.run {
val fqName = type.fqName ?: return@run null val fqName = type.fqName ?: return@run null
callExpr.typeArguments.find { it.typeReference?.isReferencing(fqName) == true } callExpr.typeArguments.find { it.typeReference?.isReferencing(fqName) == true }
} ?: return@forEach } ?: return@forEach
if (classDescriptor == null if (!classDescriptor.hasNoArgConstructor())
|| !classDescriptor.hasNoArgConstructor() return@forEach context.report(MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE.on(
) return@forEach context.report(MiraiConsoleErrors.NOT_CONSTRUCTABLE_TYPE.on( inspectionTarget,
inspectionTarget, callExpr,
callExpr, type.fqName?.asString().toString())
type.fqName?.asString().toString()) )
)
if (!classDescriptor.hasAnnotation(SERIALIZABLE_FQ_NAME)) // TODO: 2020/9/18 external serializers if (!classDescriptor.hasAnnotation(SERIALIZABLE_FQ_NAME))
return@forEach context.report(MiraiConsoleErrors.UNSERIALIZABLE_TYPE.on( return@forEach context.report(MiraiConsoleErrors.UNSERIALIZABLE_TYPE.on(
inspectionTarget, inspectionTarget,
classDescriptor classDescriptor
@ -62,3 +65,54 @@ class PluginDataValuesChecker : DeclarationChecker {
} }
} }
} }
private fun canBeSerializedInternally(descriptor: ClassDescriptor): Boolean {
@Suppress("UNUSED_VARIABLE") val name = when (descriptor.defaultType.getJetTypeFqName(false)) {
"kotlin.Unit" -> "UnitSerializer"
"Z", "kotlin.Boolean" -> "BooleanSerializer"
"B", "kotlin.Byte" -> "ByteSerializer"
"S", "kotlin.Short" -> "ShortSerializer"
"I", "kotlin.Int" -> "IntSerializer"
"J", "kotlin.Long" -> "LongSerializer"
"F", "kotlin.Float" -> "FloatSerializer"
"D", "kotlin.Double" -> "DoubleSerializer"
"C", "kotlin.Char" -> "CharSerializer"
"kotlin.String" -> "StringSerializer"
"kotlin.Pair" -> "PairSerializer"
"kotlin.Triple" -> "TripleSerializer"
"kotlin.collections.Collection", "kotlin.collections.List",
"kotlin.collections.ArrayList", "kotlin.collections.MutableList",
-> "ArrayListSerializer"
"kotlin.collections.Set", "kotlin.collections.LinkedHashSet", "kotlin.collections.MutableSet" -> "LinkedHashSetSerializer"
"kotlin.collections.HashSet" -> "HashSetSerializer"
"kotlin.collections.Map", "kotlin.collections.LinkedHashMap", "kotlin.collections.MutableMap" -> "LinkedHashMapSerializer"
"kotlin.collections.HashMap" -> "HashMapSerializer"
"kotlin.collections.Map.Entry" -> "MapEntrySerializer"
"kotlin.ByteArray" -> "ByteArraySerializer"
"kotlin.ShortArray" -> "ShortArraySerializer"
"kotlin.IntArray" -> "IntArraySerializer"
"kotlin.LongArray" -> "LongArraySerializer"
"kotlin.CharArray" -> "CharArraySerializer"
"kotlin.FloatArray" -> "FloatArraySerializer"
"kotlin.DoubleArray" -> "DoubleArraySerializer"
"kotlin.BooleanArray" -> "BooleanArraySerializer"
"java.lang.Boolean" -> "BooleanSerializer"
"java.lang.Byte" -> "ByteSerializer"
"java.lang.Short" -> "ShortSerializer"
"java.lang.Integer" -> "IntSerializer"
"java.lang.Long" -> "LongSerializer"
"java.lang.Float" -> "FloatSerializer"
"java.lang.Double" -> "DoubleSerializer"
"java.lang.Character" -> "CharSerializer"
"java.lang.String" -> "StringSerializer"
"java.util.Collection", "java.util.List", "java.util.ArrayList" -> "ArrayListSerializer"
"java.util.Set", "java.util.LinkedHashSet" -> "LinkedHashSetSerializer"
"java.util.HashSet" -> "HashSetSerializer"
"java.util.Map", "java.util.LinkedHashMap" -> "LinkedHashMapSerializer"
"java.util.HashMap" -> "HashMapSerializer"
"java.util.Map.Entry" -> "MapEntrySerializer"
else -> return false
}
return true
}

View File

@ -11,6 +11,7 @@ package net.mamoe.mirai.console.intellij.diagnostics
import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.progress.impl.CancellationCheck.Companion.runWithCancellationCheck
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import net.mamoe.mirai.console.compiler.common.resolve.AUTO_SERVICE import net.mamoe.mirai.console.compiler.common.resolve.AUTO_SERVICE
import net.mamoe.mirai.console.intellij.diagnostics.fix.ConfigurePluginMainServiceFix import net.mamoe.mirai.console.intellij.diagnostics.fix.ConfigurePluginMainServiceFix
@ -64,14 +65,16 @@ class PluginMainServiceNotConfiguredInspection : AbstractKotlinInspection() {
ktClass: KtClassOrObject, ktClass: KtClassOrObject,
fqName: String, fqName: String,
): Boolean { ): Boolean {
val sourceRoots = ktClass.module?.rootManager?.sourceRoots ?: return false return runWithCancellationCheck {
val services = sourceRoots.asSequence().flatMap { file -> val sourceRoots = ktClass.module?.rootManager?.sourceRoots ?: return@runWithCancellationCheck false
SERVICE_FILE_NAMES.asSequence().mapNotNull { serviceFileName -> val services = sourceRoots.asSequence().flatMap { file ->
file.findFileByRelativePath("META-INF/services/$serviceFileName") SERVICE_FILE_NAMES.asSequence().mapNotNull { serviceFileName ->
file.findFileByRelativePath("META-INF/services/$serviceFileName")
}
}
return@runWithCancellationCheck services.any { serviceFile ->
serviceFile.readAction { f -> f.inputStream.bufferedReader().use { it.readLine() }.trim() == fqName }
} }
}
return services.any { serviceFile ->
serviceFile.readAction { f -> f.inputStream.bufferedReader().use { it.readLine() }.trim() == fqName }
} }
} }
} }