From 24b38366482fe33f4767e4cfb61391f8c9273417 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 31 Mar 2020 19:45:27 +0800 Subject: [PATCH 1/5] Set java source and target compatibilities to 1.8 --- mirai-console/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mirai-console/build.gradle.kts b/mirai-console/build.gradle.kts index 8e301d2a3..1b8e89349 100644 --- a/mirai-console/build.gradle.kts +++ b/mirai-console/build.gradle.kts @@ -103,4 +103,8 @@ compileKotlin.kotlinOptions { val compileTestKotlin: KotlinCompile by tasks compileTestKotlin.kotlinOptions { jvmTarget = "1.8" +} +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } \ No newline at end of file From ea10207d97c0526da4ebcf54e385ebefb80ae350 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 2 Apr 2020 21:53:44 +0800 Subject: [PATCH 2/5] Update core dependency to 0.32.0 --- build.gradle | 44 ------------ build.gradle.kts | 26 +++++++ buildSrc/src/main/kotlin/versions.kt | 27 ++----- mirai-console-graphical/build.gradle.kts | 15 ---- .../controller/MiraiGraphicalUIController.kt | 2 +- mirai-console-terminal/build.gradle.kts | 2 +- .../mirai/console/MiraiConsoleTerminalUI.kt | 4 +- .../mirai/console/wrapper/ConsoleUpdater.kt | 9 --- .../mirai/console/wrapper/MiraiDownloader.kt | 2 +- mirai-console/build.gradle.kts | 1 - .../net/mamoe/mirai/console/MiraiConsole.kt | 71 +++---------------- .../mirai/console/center/PluginCenter.kt | 44 ++++++------ .../mamoe/mirai/console/command/Command.kt | 12 ---- .../mirai/console/command/DefaultCommands.kt | 7 +- .../mirai/console/plugins/ConfigSection.kt | 8 +-- .../mirai/console/plugins/PluginManager.kt | 2 +- .../mamoe/mirai/console/utils/BotHelper.kt | 16 ++--- 17 files changed, 86 insertions(+), 206 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 19dbd5669..000000000 --- a/build.gradle +++ /dev/null @@ -1,44 +0,0 @@ -buildscript { - repositories { - mavenLocal() - maven { url 'https://mirrors.huaweicloud.com/repository/maven' } - jcenter() - mavenCentral() - google() - maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' } - maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' } - } - - dependencies { - classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0' - classpath "org.jetbrains.kotlin:kotlin-serialization:1.4-M1" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4-M1" - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' // don't use any other. - } -} - -try { - def keyProps = new Properties() - def keyFile = file("local.properties") - if (keyFile.exists()) keyFile.withInputStream { keyProps.load(it) } - if (!keyProps.getProperty("sdk.dir", "").isEmpty()) { - project.ext.set("isAndroidSDKAvailable", true) - } else { - project.ext.set("isAndroidSDKAvailable", false) - } -} catch (Exception ignored) { -} - -allprojects { - group = "net.mamoe" - - repositories { - mavenLocal() - maven { url "https://mirrors.huaweicloud.com/repository/maven" } - jcenter() - mavenCentral() - google() - maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } - maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } - } -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..308686c34 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,26 @@ +buildscript { + repositories { + maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") + maven(url = "https://mirrors.huaweicloud.com/repository/maven") + jcenter() + mavenCentral() + } + + dependencies { + classpath("com.github.jengelman.gradle.plugins:shadow:5.2.0") + classpath("org.jetbrains.kotlin:kotlin-serialization:${Versions.Kotlin.stdlib}") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.stdlib}") + classpath("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4") // don"t use any other. + } +} + +allprojects { + group = "net.mamoe" + + repositories { + maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") + maven(url = "https://mirrors.huaweicloud.com/repository/maven") + jcenter() + mavenCentral() + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/versions.kt b/buildSrc/src/main/kotlin/versions.kt index 4b5c4f69d..7fb2952a3 100644 --- a/buildSrc/src/main/kotlin/versions.kt +++ b/buildSrc/src/main/kotlin/versions.kt @@ -11,33 +11,18 @@ import org.gradle.kotlin.dsl.DependencyHandlerScope object Versions { object Mirai { - const val core = "0.31.0" - const val console = "0.4.1" + const val core = "0.32.0" + const val console = "0.4.2" const val consoleGraphical = "0.0.5" const val consoleWrapper = "0.2.0" } object Kotlin { - const val stdlib = "1.4-M1" - const val coroutines = "1.3.5-1.4-M1" - const val atomicFU = "0.14.2-1.4-M1" - const val serialization = "0.20.0-1.4-M1" - const val ktor = "1.3.2-1.4-M1" - - const val io = "0.1.16" - const val coroutinesIo = "0.1.16" - const val dokka = "0.10.1" + const val stdlib = "1.3.71" + const val coroutines = "1.3.5" + const val serialization = "0.20.0" + const val ktor = "1.3.2" } - - object Android { - const val androidGradlePlugin = "3.5.3" - } - - object Publishing { - const val bintray = "1.8.4-jetbrains-3" - - } - } @Suppress("unused") diff --git a/mirai-console-graphical/build.gradle.kts b/mirai-console-graphical/build.gradle.kts index bf334c8c0..ff3b538db 100644 --- a/mirai-console-graphical/build.gradle.kts +++ b/mirai-console-graphical/build.gradle.kts @@ -49,21 +49,6 @@ bintray { } } -val kotlinVersion: String by rootProject.ext -val atomicFuVersion: String by rootProject.ext -val coroutinesVersion: String by rootProject.ext -val kotlinXIoVersion: String by rootProject.ext -val coroutinesIoVersion: String by rootProject.ext - -val klockVersion: String by rootProject.ext -val ktorVersion: String by rootProject.ext - -val serializationVersion: String by rootProject.ext - -fun kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version" - -fun ktor(id: String, version: String) = "io.ktor:ktor-$id:$version" - dependencies { compileOnly("net.mamoe:mirai-core-jvm:${Versions.Mirai.core}") implementation(project(":mirai-console")) diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt index 80c8f0dfd..41ed4e643 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt @@ -85,7 +85,7 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI { } override fun pushBot(bot: Bot) = Platform.runLater { - cache[bot.uin]?.bot = bot + cache[bot.id]?.bot = bot } override fun pushVersion(consoleVersion: String, consoleBuild: String, coreVersion: String) { diff --git a/mirai-console-terminal/build.gradle.kts b/mirai-console-terminal/build.gradle.kts index 0e334fffe..01a327d2d 100644 --- a/mirai-console-terminal/build.gradle.kts +++ b/mirai-console-terminal/build.gradle.kts @@ -15,7 +15,7 @@ tasks.withType() { } } dependencies { - api("net.mamoe:mirai-core-qqandroid-jvm:${Versions.Mirai.core}") + compileOnly("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}") api(project(":mirai-console")) api(group = "com.googlecode.lanterna", name = "lanterna", version = "3.0.2") } \ No newline at end of file diff --git a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt index 93bcd53e5..9db3cd724 100644 --- a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt +++ b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt @@ -97,8 +97,8 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { } override fun pushBot(bot: Bot) { - botAdminCount[bot.uin] = 0 - screens.add(bot.uin) + botAdminCount[bot.id] = 0 + screens.add(bot.id) drawFrame(this.getScreenName(currentScreenId)) if (terminal is SwingTerminalFrame) { terminal.flush() diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt index 5d846d864..70ea86de7 100644 --- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt +++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/ConsoleUpdater.kt @@ -119,13 +119,4 @@ internal object ConsoleUpdater { } } - private suspend fun downloadConsole(version: String) { - - /* - tryNTimesOrQuit(3, "Failed to download Console, please seek for help") { - Http.downloadMavenArchive("net/mamoe", getProjectName(), version) - .saveToContent("${getProjectName()}-$version.jar") - } - */ - } } \ No newline at end of file diff --git a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/MiraiDownloader.kt b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/MiraiDownloader.kt index cffbc2611..fd21da462 100644 --- a/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/MiraiDownloader.kt +++ b/mirai-console-wrapper/src/main/kotlin/net/mamoe/mirai/console/wrapper/MiraiDownloader.kt @@ -79,7 +79,7 @@ private class MiraiDownloaderImpl( val input= con.inputStream totalSize.addAndGet(con.contentLength) val outputStream = FileOutputStream(file) - var len = -1 + var len: Int val buff = ByteArray(1024) while (input.read(buff).also { len = it } != -1) { totalDownload.addAndGet(buff.size) diff --git a/mirai-console/build.gradle.kts b/mirai-console/build.gradle.kts index 1b8e89349..94fa19b3f 100644 --- a/mirai-console/build.gradle.kts +++ b/mirai-console/build.gradle.kts @@ -32,7 +32,6 @@ dependencies { testApi("net.mamoe:mirai-core-qqandroid-jvm:${Versions.Mirai.core}") testApi(kotlin("stdlib")) - testApi("org.jsoup:jsoup:1.12.1") } version = Versions.Mirai.console diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index d14b4c812..8ee5fa164 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -9,16 +9,13 @@ package net.mamoe.mirai.console -import kotlinx.coroutines.runBlocking +import kotlinx.io.charsets.Charset import net.mamoe.mirai.Bot import net.mamoe.mirai.console.command.CommandManager -import net.mamoe.mirai.console.command.CommandSender -import net.mamoe.mirai.console.command.ConsoleCommandSender import net.mamoe.mirai.console.command.DefaultCommands import net.mamoe.mirai.console.plugins.PluginManager import net.mamoe.mirai.console.utils.MiraiConsoleUI import net.mamoe.mirai.utils.SimpleLogger.LogPriority -import net.mamoe.mirai.utils.io.encodeToString import java.io.ByteArrayOutputStream import java.io.PrintStream @@ -29,6 +26,7 @@ object MiraiConsole { */ const val build = "Pkmon" lateinit var version: String + internal set /** * 获取从Console登陆上的Bot, Bots @@ -36,7 +34,7 @@ object MiraiConsole { val bots get() = Bot.instances fun getBotOrNull(uin: Long): Bot? { - return bots.asSequence().mapNotNull { it.get() }.firstOrNull { it.uin == uin } + return bots.asSequence().mapNotNull { it.get() }.firstOrNull { it.id == uin } } /** @@ -98,64 +96,12 @@ object MiraiConsole { */ fun stop() { PluginManager.disablePlugins() - CommandManager.cancel() + CommandManager.cancel() try { bots.forEach { it.get()?.close() } - } catch (ignored: Exception) { } - } - - @Suppress("RedundantSuspendModifier") // binary compatibility - @Deprecated( - "Please use CommandManager directly, this will be removed in later release", - ReplaceWith( - "CommandManager", - "net.mamoe.mirai.console.command.CommandManager" - ), - level = DeprecationLevel.ERROR - ) - object CommandProcessor { - @Deprecated( - "Please use CommandManager directly, this will be removed in later release", ReplaceWith( - "CommandManager.runConsoleCommand(command)", - "net.mamoe.mirai.console.command.CommandManager" - ), level = DeprecationLevel.ERROR - ) - suspend fun runConsoleCommand(command: String) { - CommandManager.runCommand(ConsoleCommandSender, command) - } - - @Deprecated( - "Please use CommandManager directly, this will be removed in later release", ReplaceWith( - "CommandManager.runCommand(sender, command)", - "net.mamoe.mirai.console.command.CommandManager" - ), level = DeprecationLevel.ERROR - ) - suspend fun runCommand(sender: CommandSender, command: String) { - CommandManager.runCommand(sender, command) - } - - @Deprecated( - "Please use CommandManager directly, this will be removed in later release", ReplaceWith( - "CommandManager.runCommand(command)", - "net.mamoe.mirai.console.command.CommandManager", - "net.mamoe.mirai.console.command.ConsoleCommandSender" - ), level = DeprecationLevel.ERROR - ) - fun runConsoleCommandBlocking(command: String) = - runBlocking { CommandManager.runCommand(ConsoleCommandSender, command) } - - - @Suppress("unused") - @Deprecated( - "Please use CommandManager directly, this will be removed in later release", ReplaceWith( - "CommandManager.runCommand(sender, command)", - "net.mamoe.mirai.console.command.CommandManager" - ), level = DeprecationLevel.ERROR - ) - fun runCommandBlocking(sender: CommandSender, command: String) = runBlocking { - CommandManager.runCommand(sender, command) + } catch (ignored: Exception) { } } } @@ -208,4 +154,9 @@ internal val Throwable.stacktraceString: String get() = ByteArrayOutputStream().apply { printStackTrace(PrintStream(this)) - }.use { it.toByteArray().encodeToString() } \ No newline at end of file + }.use { it.toByteArray().encodeToString() } + + +@Suppress("NOTHING_TO_INLINE") +internal inline fun ByteArray.encodeToString(charset: Charset = Charsets.UTF_8): String = + kotlinx.io.core.String(this, charset = charset) diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/PluginCenter.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/PluginCenter.kt index c246b89d9..382a0b532 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/PluginCenter.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/PluginCenter.kt @@ -2,34 +2,34 @@ package net.mamoe.mirai.console.center interface PluginCenter { - companion object{ - val Default:PluginCenter = CuiPluginCenter + companion object { + val Default: PluginCenter = CuiPluginCenter } data class PluginInsight( - val name:String, - val version:String, - val coreVersion:String, - val consoleVersion:String, - val author:String, + val name: String, + val version: String, + val coreVersion: String, + val consoleVersion: String, + val author: String, val description: String, - val tags:List, - val commands:List, + val tags: List, + val commands: List ) data class PluginInfo( - val name:String, - val version:String, - val coreVersion:String, - val consoleVersion:String, - val tags:List, - val author:String, - val contact:String, + val name: String, + val version: String, + val coreVersion: String, + val consoleVersion: String, + val tags: List, + val author: String, + val contact: String, val description: String, - val usage:String, - val vcs:String, - val commands:String, - val changeLog:List + val usage: String, + val vcs: String, + val commands: String, + val changeLog: List ) /** @@ -37,12 +37,12 @@ interface PluginCenter { * 能获取到多少由实际的PluginCenter决定 * 返回 插件名->Insight */ - suspend fun fetchPlugin(page: Int) :Map + suspend fun fetchPlugin(page: Int): Map /** * 尝试获取到某个插件by全名, case sensitive * null则没有 */ - suspend fun findPlugin(name:String):PluginInfo? + suspend fun findPlugin(name: String): PluginInfo? } diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt index 6be41951f..2eb800a0f 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt @@ -50,22 +50,10 @@ interface Command { */ inline fun Command.register(commandOwner: CommandOwner) = CommandManager.register(commandOwner,this) - -/** - * 构造并注册一个指令 - */ -@Deprecated("this will be removed in next few release") -object AnonymousCommandOwner:CommandOwner -@Deprecated("this will become internal in next few release, please use PluginBase.registerCommand() for plugin") -inline fun registerCommand(builder: CommandBuilder.() -> Unit): Command { - return CommandBuilder().apply(builder).register(AnonymousCommandOwner) -} - internal inline fun registerConsoleCommands(builder: CommandBuilder.() -> Unit):Command{ return CommandBuilder().apply(builder).register(ConsoleCommandOwner) } - inline fun PluginBase.registerCommand(builder: CommandBuilder.() -> Unit):Command{ return CommandBuilder().apply(builder).register(this.asCommandOwner()) } diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt index 64aa41784..30b7d2eac 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt @@ -19,7 +19,6 @@ import net.mamoe.mirai.console.utils.removeManager import net.mamoe.mirai.contact.sendMessage import net.mamoe.mirai.event.subscribeMessages import net.mamoe.mirai.getFriendOrNull -import net.mamoe.mirai.utils.FileBasedDeviceInfo import net.mamoe.mirai.utils.SimpleLogger import java.util.* @@ -117,7 +116,7 @@ object DefaultCommands { try { MiraiConsole.frontEnd.prePushBot(qqNumber) val bot = Bot(qqNumber, qqPassword) { - +FileBasedDeviceInfo + fileBasedDeviceInfo() this.loginSolver = MiraiConsole.frontEnd.createLoginSolver() this.botLoggerSupplier = { SimpleLogger("BOT $qqNumber]") { _, message, e -> @@ -168,10 +167,10 @@ object DefaultCommands { val bot = args[0] var find = false MiraiConsole.bots.forEach { - if (it.get()?.uin.toString().contains(bot)) { + if (it.get()?.id.toString().contains(bot)) { find = true appendMessage( - "" + it.get()?.uin + ": 在线中; 好友数量:" + it.get()?.friends?.size + "; 群组数量:" + it.get() + "" + it.get()?.id + ": 在线中; 好友数量:" + it.get()?.friends?.size + "; 群组数量:" + it.get() ?.groups?.size ) } diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/ConfigSection.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/ConfigSection.kt index b49b6ed87..b4df3025c 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/ConfigSection.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/ConfigSection.kt @@ -17,8 +17,8 @@ import com.moandjiezana.toml.Toml import com.moandjiezana.toml.TomlWriter import kotlinx.serialization.Serializable import kotlinx.serialization.UnstableDefault +import net.mamoe.mirai.console.encodeToString import net.mamoe.mirai.utils.MiraiInternalAPI -import net.mamoe.mirai.utils.io.encodeToString import org.yaml.snakeyaml.Yaml import java.io.File import java.io.InputStream @@ -486,7 +486,7 @@ abstract class FileConfigImpl internal constructor( } -@UseExperimental(MiraiInternalAPI::class) +@OptIn(MiraiInternalAPI::class) class JsonConfig internal constructor( content: String ) : FileConfigImpl(content) { @@ -513,7 +513,7 @@ class JsonConfig internal constructor( } } -@UseExperimental(MiraiInternalAPI::class) +@OptIn(MiraiInternalAPI::class) class YamlConfig internal constructor(content: String) : FileConfigImpl(content) { constructor(file: File) : this(file.readText()) { this.file = file @@ -536,7 +536,7 @@ class YamlConfig internal constructor(content: String) : FileConfigImpl(content) } -@UseExperimental(MiraiInternalAPI::class) +@OptIn(MiraiInternalAPI::class) class TomlConfig internal constructor(content: String) : FileConfigImpl(content) { constructor(file: File) : this(file.readText()) { this.file = file diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt index b8c8e0385..65a4a3175 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt @@ -16,8 +16,8 @@ import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.command.Command import net.mamoe.mirai.console.command.CommandManager import net.mamoe.mirai.console.command.CommandSender +import net.mamoe.mirai.console.encodeToString import net.mamoe.mirai.utils.SimpleLogger -import net.mamoe.mirai.utils.io.encodeToString import java.io.File import java.io.InputStream import java.lang.reflect.Constructor diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt index 38a3ee8a5..08d04a143 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt @@ -24,23 +24,23 @@ internal object BotManagers { } fun Bot.addManager(long: Long) { - BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf()) - BOT_MANAGERS[this.uin.toString()] = - (BOT_MANAGERS.getLongList(this.uin.toString()) as MutableList).apply { add(long) } + BOT_MANAGERS.putIfAbsent(this.id.toString(), mutableListOf()) + BOT_MANAGERS[this.id.toString()] = + (BOT_MANAGERS.getLongList(this.id.toString()) as MutableList).apply { add(long) } BotManagers.config.save() } fun Bot.removeManager(long: Long) { - BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf()) - BOT_MANAGERS[this.uin.toString()] = - (BOT_MANAGERS.getLongList(this.uin.toString()) as MutableList).apply { add(long) } + BOT_MANAGERS.putIfAbsent(this.id.toString(), mutableListOf()) + BOT_MANAGERS[this.id.toString()] = + (BOT_MANAGERS.getLongList(this.id.toString()) as MutableList).apply { add(long) } BotManagers.config.save() } val Bot.managers: List get() { - BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf()) - return BOT_MANAGERS.getLongList(this.uin.toString()) + BOT_MANAGERS.putIfAbsent(this.id.toString(), mutableListOf()) + return BOT_MANAGERS.getLongList(this.id.toString()) } fun Bot.checkManager(long: Long): Boolean { From f70ad5191b5f6a0a9ea7fca29eff08929c575662 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 2 Apr 2020 22:08:58 +0800 Subject: [PATCH 3/5] Cui cloud & GitHub cloud uploading --- .github/workflows/cui.yml | 48 +++++ .github/workflows/shadow.yml | 48 +++++ build.gradle.kts | 77 ++++++++ buildSrc/build.gradle.kts | 20 ++ buildSrc/src/main/kotlin/upload/CuiCloud.kt | 134 +++++++++++++ buildSrc/src/main/kotlin/upload/GitHub.kt | 178 ++++++++++++++++++ .../mamoe/mirai/console/events/Events.java | 5 +- .../mamoe/mirai/console/events/EventsImpl.kt | 16 ++ 8 files changed, 523 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/cui.yml create mode 100644 .github/workflows/shadow.yml create mode 100644 buildSrc/src/main/kotlin/upload/CuiCloud.kt create mode 100644 buildSrc/src/main/kotlin/upload/GitHub.kt diff --git a/.github/workflows/cui.yml b/.github/workflows/cui.yml new file mode 100644 index 000000000..0bbcd36eb --- /dev/null +++ b/.github/workflows/cui.yml @@ -0,0 +1,48 @@ +# This is a basic workflow to help you get started with Actions + +name: CuiCloud Publish + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + release: + types: + - created + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Gradle clean + run: ./gradlew clean + - name: Gradle build + run: ./gradlew build # if test's failed, don't publish + - name: Gradle :mirai-console:cuiCloudUpload + run: ./gradlew :mirai-console:cuiCloudUpload -Dcui_cloud_key=${{ secrets.CUI_CLOUD_KEY }} -Pcui_cloud_key=${{ secrets.CUI_CLOUD_KEY }} -Dcui_cloud_url=${{ secrets.CUI_CLOUD_URL }} -Pcui_cloud_url=${{ secrets.CUI_CLOUD_URL }} + - name: Gradle :mirai-console-qqandroid:cuiCloudUpload + run: ./gradlew :mirai-console-graphical:cuiCloudUpload -Dcui_cloud_key=${{ secrets.CUI_CLOUD_KEY }} -Pcui_cloud_key=${{ secrets.CUI_CLOUD_KEY }} -Dcui_cloud_url=${{ secrets.CUI_CLOUD_URL }} -Pcui_cloud_url=${{ secrets.CUI_CLOUD_URL }} + + +# - name: Upload artifact +# uses: actions/upload-artifact@v1.0.0 +# with: +# # Artifact name +# name: mirai-core +# # Directory containing files to upload +# path: "mirai-core/build/libs/mirai-core-*-all.jar" +# - name: Upload artifact +# uses: actions/upload-artifact@v1.0.0 +# with: +# # Artifact name +# name: mirai-core-qqandroid-all +# # Directory containing files to upload +# path: "mirai-core-qqandroid/build/libs/mirai-core-qqandroid-*-all.jar" diff --git a/.github/workflows/shadow.yml b/.github/workflows/shadow.yml new file mode 100644 index 000000000..8dbaf88c1 --- /dev/null +++ b/.github/workflows/shadow.yml @@ -0,0 +1,48 @@ +# This is a basic workflow to help you get started with Actions + +name: mirai-repo Publish + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + release: + types: + - created + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Gradle clean + run: ./gradlew clean + - name: Gradle build + run: ./gradlew build # if test's failed, don't publish + - name: Gradle :mirai-console:githubUpload + run: ./gradlew :mirai-console:githubUpload -Dgithub_token=${{ secrets.MAMOE_TOKEN }} -Pgithub_token=${{ secrets.MAMOE_TOKEN }} + - name: Gradle :mirai-console-qqandroid:githubUpload + run: ./gradlew :mirai-console-graphical:githubUpload -Dgithub_token=${{ secrets.MAMOE_TOKEN }} -Pgithub_token=${{ secrets.MAMOE_TOKEN }} + + +# - name: Upload artifact +# uses: actions/upload-artifact@v1.0.0 +# with: +# # Artifact name +# name: mirai-core +# # Directory containing files to upload +# path: "mirai-core/build/libs/mirai-core-*-all.jar" +# - name: Upload artifact +# uses: actions/upload-artifact@v1.0.0 +# with: +# # Artifact name +# name: mirai-core-qqandroid-all +# # Directory containing files to upload +# path: "mirai-core-qqandroid/build/libs/mirai-core-qqandroid-*-all.jar" diff --git a/build.gradle.kts b/build.gradle.kts index 308686c34..4709862dc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,7 @@ +@file:Suppress("UnstableApiUsage") + +import kotlin.math.pow + buildscript { repositories { maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") @@ -23,4 +27,77 @@ allprojects { jcenter() mavenCentral() } +} + +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 + + 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 + } + } + } + + } + } +} + + +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]|\.)*\.jar""")) } + .onEach { println("matched file: ${it.name}") } + .associateBy { it.nameWithoutExtension.substringAfterLast('-') } + .onEach { println("versions: $it") } + .maxBy { + it.key.split('.').foldRightIndexed(0) { index: Int, s: String, acc: Int -> + acc + 100.0.pow(2 - index).toInt() * (s.toIntOrNull() ?: 0) + } + } } \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c39a297b0..a0b4b2f9b 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -4,4 +4,24 @@ plugins { repositories { jcenter() +} + +kotlin { + sourceSets.all { + languageSettings.useExperimentalAnnotation("kotlin.Experimental") + languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn") + } +} + +dependencies { + fun kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version" + fun ktor(id: String, version: String) = "io.ktor:ktor-$id:$version" + + api("org.jsoup:jsoup:1.12.1") + + api("com.google.code.gson:gson:2.8.6") + api(kotlinx("coroutines-core", "1.3.3")) + api(ktor("client-core", "1.3.2")) + api(ktor("client-cio", "1.3.2")) + api(ktor("client-json", "1.3.2")) } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/upload/CuiCloud.kt b/buildSrc/src/main/kotlin/upload/CuiCloud.kt new file mode 100644 index 000000000..c617d2882 --- /dev/null +++ b/buildSrc/src/main/kotlin/upload/CuiCloud.kt @@ -0,0 +1,134 @@ +/* + * 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 upload + +import io.ktor.client.request.forms.MultiPartFormDataContent +import io.ktor.client.request.forms.formData +import io.ktor.client.request.post +import io.ktor.client.statement.HttpResponse +import io.ktor.http.isSuccess +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.gradle.api.Project +import org.gradle.kotlin.dsl.provideDelegate +import java.io.File +import java.util.* + +@Suppress("DEPRECATION") +object CuiCloud { + private fun getUrl(project: Project): String { + kotlin.runCatching { + @Suppress("UNUSED_VARIABLE", "LocalVariableName") + val cui_cloud_url: String by project + return cui_cloud_url + } + + System.getProperty("cui_cloud_url", null)?.let { + return it.trim() + } + File(File(System.getProperty("user.dir")).parent, "/cuiUrl.txt").let { local -> + if (local.exists()) { + return local.readText().trim() + } + } + + File(File(System.getProperty("user.dir")), "/cuiUrl.txt").let { local -> + if (local.exists()) { + return local.readText().trim() + } + } + error("cannot find url for CuiCloud") + } + + private fun getKey(project: Project): String { + kotlin.runCatching { + @Suppress("UNUSED_VARIABLE", "LocalVariableName") + val cui_cloud_key: String by project + return cui_cloud_key + } + + System.getProperty("cui_cloud_key", null)?.let { + return it.trim() + } + File(File(System.getProperty("user.dir")).parent, "/cuiToken.txt").let { local -> + if (local.exists()) { + return local.readText().trim() + } + } + + File(File(System.getProperty("user.dir")), "/cuiToken.txt").let { local -> + if (local.exists()) { + return local.readText().trim() + } + } + + error("cannot find key for CuiCloud") + } + + fun upload(file: File, project: Project) { + val cuiCloudUrl = getUrl(project) + val key = getKey(project) + + runBlocking { + uploadToCuiCloud( + cuiCloudUrl, + key, + "/mirai/${project.name}/${file.nameWithoutExtension}.mp4", + file.readBytes() + ) + } + } + + @UseExperimental(ExperimentalStdlibApi::class) + private suspend fun uploadToCuiCloud( + cuiCloudUrl: String, + cuiToken: String, + filePath: String, + content: ByteArray + ) { + println("filePath=$filePath") + println("content=${content.size / 1024 / 1024} MB") + + val response = withContext(Dispatchers.IO) { + Http.post(cuiCloudUrl) { + body = MultiPartFormDataContent( + formData { + append("base64", Base64.getEncoder().encodeToString(content)) + append("filePath", filePath) + append("large", "true") + append("key", cuiToken) + } + ) + } + } + println(response.status) + + val buffer = ByteArray(4096) + val resp = buildList { + while (true) { + val read = response.content.readAvailable(buffer, 0, buffer.size) + if (read == -1) { + break + } + addAll(buffer.toList().take(read)) + } + } + println(String(resp.toByteArray())) + + if (!response.status.isSuccess()) { + error("Cui cloud response: ${response.status}") + } + } +} + +inline fun buildList(builderAction: MutableList.() -> Unit): List { + return ArrayList().apply(builderAction) +} diff --git a/buildSrc/src/main/kotlin/upload/GitHub.kt b/buildSrc/src/main/kotlin/upload/GitHub.kt new file mode 100644 index 000000000..486247e33 --- /dev/null +++ b/buildSrc/src/main/kotlin/upload/GitHub.kt @@ -0,0 +1,178 @@ +@file:Suppress("EXPERIMENTAL_API_USAGE") + +package upload + +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO +import io.ktor.client.features.HttpTimeout +import io.ktor.client.request.put +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.gradle.api.Project +import org.gradle.kotlin.dsl.provideDelegate +import org.jsoup.Connection +import org.jsoup.Jsoup +import java.io.File +import java.util.* + +internal val Http = HttpClient(CIO) { + engine { + requestTimeout = 600_000 + } + install(HttpTimeout) { + socketTimeoutMillis = 600_000 + requestTimeoutMillis = 600_000 + connectTimeoutMillis = 600_000 + } +} + +object GitHub { + + private fun getGithubToken(project: Project): String { + kotlin.runCatching { + @Suppress("UNUSED_VARIABLE", "LocalVariableName") + val github_token: String by project + return github_token + } + + System.getProperty("github_token", null)?.let { + return it.trim() + } + + File(File(System.getProperty("user.dir")).parent, "/token.txt").let { local -> + if (local.exists()) { + return local.readText().trim() + } + } + + File(File(System.getProperty("user.dir")), "/token.txt").let { local -> + if (local.exists()) { + return local.readText().trim() + } + } + + error( + "Cannot find github token, " + + "please specify by creating a file token.txt in project dir, " + + "or by providing JVM parameter 'github_token'" + ) + } + + fun upload(file: File, url: String, project: Project) = runBlocking { + val token = getGithubToken(project) + println("token.length=${token.length}") + Http.put("$url?access_token=$token") { + val sha = getGithubSha("mirai-repo", "shadow/${project.name}/${file.name}", "master", project) + println("sha=$sha") + val content = String(Base64.getEncoder().encode(file.readBytes())) + body = """ + { + "message": "automatically upload on release", + "content": "$content" + ${if (sha == null) "" else """, "sha": "$sha" """} + } + """.trimIndent() + }.let { + println("Upload response: $it") + } + } + + + private suspend fun getGithubSha( + repo: String, + filePath: String, + branch: String, + project: Project + ): String? { + fun String.asJson(): JsonObject { + return JsonParser.parseString(this).asJsonObject + } + + /* + * 只能获取1M以内/branch为master的sha + * */ + class TargetTooLargeException() : Exception("Target TOO Large") + + suspend fun getShaSmart(repo: String, filePath: String, project: Project): String? { + return withContext(Dispatchers.IO) { + val response = Jsoup + .connect( + "https://api.github.com/repos/mamoe/$repo/contents/$filePath?access_token=" + getGithubToken( + project + ) + ) + .ignoreContentType(true) + .ignoreHttpErrors(true) + .method(Connection.Method.GET) + .execute() + if (response.statusCode() == 404) { + null + } else { + val p = response.body().asJson() + if (p.has("message") && p["message"].asString == "This API returns blobs up to 1 MB in size. The requested blob is too large to fetch via the API, but you can use the Git Data API to request blobs up to 100 MB in size.") { + throw TargetTooLargeException() + } + p.get("sha").asString + } + } + } + + suspend fun getShaStupid( + repo: String, + filePath: String, + branch: String, + project: Project + ): String? { + val resp = withContext(Dispatchers.IO) { + Jsoup + .connect( + "https://api.github.com/repos/mamoe/$repo/git/ref/heads/$branch?access_token=" + getGithubToken( + project + ) + ) + .ignoreContentType(true) + .ignoreHttpErrors(true) + .method(Connection.Method.GET) + .execute() + } + if (resp.statusCode() == 404) { + println("Branch Not Found") + return null + } + val info = resp.body().asJson().get("object").asJsonObject.get("url").asString + var parentNode = withContext(Dispatchers.IO) { + Jsoup.connect(info + "?access_token=" + getGithubToken(project)).ignoreContentType(true) + .method(Connection.Method.GET) + .execute().body().asJson().get("tree").asJsonObject.get("url").asString + } + filePath.split("/").forEach { subPath -> + withContext(Dispatchers.IO) { + Jsoup.connect(parentNode + "?access_token=" + getGithubToken(project)).ignoreContentType(true) + .method(Connection.Method.GET).execute().body().asJson().get("tree").asJsonArray + }.forEach list@{ + with(it.asJsonObject) { + if (this.get("path").asString == subPath) { + parentNode = this.get("url").asString + return@list + } + } + } + } + check(parentNode.contains("/blobs/")) + return parentNode.substringAfterLast("/") + } + + return if (branch == "master") { + try { + getShaSmart(repo, filePath, project) + } catch (e: TargetTooLargeException) { + getShaStupid(repo, filePath, branch, project) + } + } else { + getShaStupid(repo, filePath, branch, project) + } + } +} \ No newline at end of file diff --git a/mirai-console/src/main/java/net/mamoe/mirai/console/events/Events.java b/mirai-console/src/main/java/net/mamoe/mirai/console/events/Events.java index a49d3a328..2679f38ab 100644 --- a/mirai-console/src/main/java/net/mamoe/mirai/console/events/Events.java +++ b/mirai-console/src/main/java/net/mamoe/mirai/console/events/Events.java @@ -13,7 +13,6 @@ import kotlinx.coroutines.GlobalScope; import net.mamoe.mirai.event.Event; import net.mamoe.mirai.event.Listener; import net.mamoe.mirai.event.ListeningStatus; -import net.mamoe.mirai.event.internal.EventInternalJvmKt; import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; @@ -35,7 +34,7 @@ public final class Events { */ @NotNull public static Listener subscribe(@NotNull Class eventClass, @NotNull Function onEvent) { - return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent); + return EventsImplKt.subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent); } /** @@ -49,7 +48,7 @@ public final class Events { */ @NotNull public static Listener subscribeAlways(@NotNull Class eventClass, @NotNull Consumer onEvent) { - return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent); + return EventsImplKt.subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent); } diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/events/EventsImpl.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/events/EventsImpl.kt index 7d8b07733..eaf9e99d9 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/events/EventsImpl.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/events/EventsImpl.kt @@ -7,10 +7,26 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package net.mamoe.mirai.console.events; +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.runBlocking import net.mamoe.mirai.event.Event +import net.mamoe.mirai.event.Listener +import net.mamoe.mirai.event.ListeningStatus import net.mamoe.mirai.event.broadcast +import net.mamoe.mirai.event.internal._subscribeEventForJaptOnly +import java.util.function.Consumer +import java.util.function.Function internal fun broadcast(e: E): E = runBlocking { e.broadcast() } + +internal fun Class.subscribeEventForJaptOnly( + scope: CoroutineScope, + onEvent: Function +): Listener = _subscribeEventForJaptOnly(scope, onEvent) + +internal fun Class.subscribeEventForJaptOnly(scope: CoroutineScope, onEvent: Consumer): Listener = + _subscribeEventForJaptOnly(scope, onEvent) \ No newline at end of file From 0c905f8cd08af4f1746eb85cc4851f3228949954 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 2 Apr 2020 22:50:01 +0800 Subject: [PATCH 4/5] Fix file detecting --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4709862dc..afd4ab70a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -91,7 +91,7 @@ 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]|\.)*\.jar""")) } + .filter { it.name.matches(Regex("""${project.name}-([0-9]|\.)*-all\.jar""")) } .onEach { println("matched file: ${it.name}") } .associateBy { it.nameWithoutExtension.substringAfterLast('-') } .onEach { println("versions: $it") } @@ -100,4 +100,4 @@ fun Project.findLatestFile(): Map.Entry? { acc + 100.0.pow(2 - index).toInt() * (s.toIntOrNull() ?: 0) } } -} \ No newline at end of file +} From 5120e79fecb64e79bb888c5ec0ad08005bf0def8 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 2 Apr 2020 23:00:20 +0800 Subject: [PATCH 5/5] Fix naming issue --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index afd4ab70a..c952a7bd1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -93,7 +93,7 @@ fun Project.findLatestFile(): Map.Entry? { .onEach { println("all files=$it") } .filter { it.name.matches(Regex("""${project.name}-([0-9]|\.)*-all\.jar""")) } .onEach { println("matched file: ${it.name}") } - .associateBy { it.nameWithoutExtension.substringAfterLast('-') } + .associateBy { it.nameWithoutExtension.substringAfterLast('-').replace("-all", "") } .onEach { println("versions: $it") } .maxBy { it.key.split('.').foldRightIndexed(0) { index: Int, s: String, acc: Int ->