idea: Correctly sort versions, fix compatibility issues with some intellij versions.

This commit is contained in:
Him188 2022-02-07 16:18:25 +00:00
parent e856a017a1
commit 1d97a20b78
8 changed files with 205 additions and 80 deletions

View File

@ -19,6 +19,7 @@ object Versions {
val core = project
val console = project
val consoleIntellij = "$project-160-213-1" // mirai-kotlin-idea-patch
val consoleTerminal = project
const val kotlinCompiler = "1.6.0"
@ -59,7 +60,7 @@ object Versions {
const val intellijGradlePlugin = "1.3.0"
// const val kotlinIntellijPlugin = "211-1.5.20-release-284-IJ7442.40" // keep to newest as kotlinCompiler
const val intellij = "2021.3" // don't update easily unless you want your disk space -= 500MB
const val intellij = "2021.3.2" // don't update easily unless you want your disk space -= 500MB
}

View File

@ -1,10 +1,10 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* Copyright 2019-2022 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.
* 此源代码的使用受 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
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress("UnusedImport")
@ -18,7 +18,8 @@ plugins {
}
repositories {
maven("https://maven.aliyun.com/repository/public")
maven("https://maven.aliyun.com/repository/public") // IntelliJ dependencies are very large (>500MB)
mavenCentral()
}
version = Versions.console
@ -42,12 +43,11 @@ intellij {
)
}
afterEvaluate {
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.getByName("publishPlugin", org.jetbrains.intellij.tasks.PublishPluginTask::class) {
val pluginKey = project.findProperty("jetbrains.hub.key")?.toString()
if (pluginKey != null) {
@ -65,12 +65,14 @@ fun File.resolveMkdir(relative: String): File {
kotlin.target.compilations.all {
kotlinOptions {
jvmTarget = "11"
apiVersion = "1.5" // bundled Kotlin is 1.5.10
}
}
// https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library
tasks.withType<org.jetbrains.intellij.tasks.PatchPluginXmlTask> {
sinceBuild.set("201.*")
untilBuild.set("215.*")
sinceBuild.set("212.*")
untilBuild.set("225.*")
pluginDescription.set(
"""
Plugin development support for <a href='https://github.com/mamoe/mirai'>Mirai Console</a>
@ -91,12 +93,12 @@ tasks.withType<org.jetbrains.intellij.tasks.PatchPluginXmlTask> {
}
dependencies {
api(`jetbrains-annotations`)
api(`kotlinx-coroutines-jdk8`)
api(`kotlinx-coroutines-swing`)
api(project(":mirai-console-compiler-common"))
implementation(`kotlin-stdlib-jdk8`)
implementation(`kotlin-reflect`)
implementation(project(":mirai-console-compiler-common")) {
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
exclude("org.jetbrains.kotlin", "kotlin-stdlib-jdk7")
exclude("org.jetbrains.kotlin", "kotlin-stdlib-jdk8")
}
// implementation(project(":mirai-console-compiler-common")) {
// isTransitive = false
// }
}

View File

@ -0,0 +1,9 @@
#
# Copyright 2019-2022 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/dev/LICENSE
#
kotlin.stdlib.default.dependency=false

View File

@ -1,10 +1,10 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* Copyright 2019-2022 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.
* 此源代码的使用受 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
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@ -26,9 +26,6 @@ import com.intellij.openapi.startup.StartupManager
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import net.mamoe.mirai.console.intellij.assets.Icons
import net.mamoe.mirai.console.intellij.creator.steps.BuildSystemStep
import net.mamoe.mirai.console.intellij.creator.steps.OptionsStep
@ -37,6 +34,7 @@ import net.mamoe.mirai.console.intellij.creator.tasks.CreateProjectTask
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.Executors
class MiraiModuleBuilder : JavaModuleBuilder() {
override fun getPresentableName() = MiraiModuleType.NAME
@ -90,15 +88,18 @@ class MiraiModuleBuilder : JavaModuleBuilder() {
val vFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(pathName)
?: throw IllegalStateException("Failed to refresh and file file: $path")
return path to vFile
}
private val scope = CoroutineScope(SupervisorJob())
// private val scope = CoroutineScope(SupervisorJob())
private val scope = Executors.newFixedThreadPool(2)
private val model = MiraiProjectModel.create(scope)
override fun cleanup() {
super.cleanup()
scope.cancel()
scope.shutdownNow()
}
override fun createWizardSteps(
@ -107,7 +108,7 @@ class MiraiModuleBuilder : JavaModuleBuilder() {
): Array<ModuleWizardStep> {
return arrayOf(
BuildSystemStep(model),
PluginCoordinatesStep(model),
PluginCoordinatesStep(model, scope),
)
}

View File

@ -1,22 +1,21 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* Copyright 2019-2022 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.
* 此源代码的使用受 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
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.console.intellij.creator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import net.mamoe.mirai.console.intellij.creator.MiraiVersionKind.Companion.getMiraiVersionListAsync
import net.mamoe.mirai.console.intellij.creator.steps.BuildSystemType
import net.mamoe.mirai.console.intellij.creator.steps.LanguageType
import net.mamoe.mirai.console.intellij.creator.tasks.adjustToClassName
import net.mamoe.mirai.console.intellij.creator.tasks.lateinitReadWriteProperty
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutorService
import kotlin.contracts.contract
data class ProjectCoordinates(
@ -54,7 +53,7 @@ class MiraiProjectModel private constructor() {
var packageName: String by lateinitReadWriteProperty { projectCoordinates.checkNotNull("projectCoordinates").groupId }
var availableMiraiVersions: Deferred<Set<MiraiVersion>>? = null
var availableMiraiVersions: CompletableFuture<Set<MiraiVersion>>? = null
val availableMiraiVersionsOrFail get() = availableMiraiVersions.checkNotNull("availableMiraiVersions")
fun checkValuesNotNull() {
@ -64,11 +63,23 @@ class MiraiProjectModel private constructor() {
}
companion object {
fun create(scope: CoroutineScope): MiraiProjectModel {
fun create(scope: ExecutorService): MiraiProjectModel {
return MiraiProjectModel().apply {
availableMiraiVersions = scope.getMiraiVersionListAsync()
availableMiraiVersions = scope.async { MiraiVersionKind.getMiraiVersionList() }
}
}
fun <T> ExecutorService.async(block: () -> T): CompletableFuture<T> {
val future = CompletableFuture<T>()
submit {
try {
future.complete(block())
} catch (e: Throwable) {
future.completeExceptionally(e)
}
}
return future
}
}
}

View File

@ -1,18 +1,20 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* Copyright 2019-2022 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.
* 此源代码的使用受 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
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.console.intellij.creator
import kotlinx.coroutines.*
import com.intellij.openapi.diagnostic.Logger
import com.intellij.util.text.SemVer
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import java.io.IOException
typealias MiraiVersion = String
@ -22,7 +24,7 @@ enum class MiraiVersionKind {
},
Prerelease {
override fun isThatKind(version: String): Boolean =
!version.contains("-dev") // && (version.contains("-M") || version.contains("-RC"))
version.contains("-M") || version.contains("-RC")
},
Nightly {
override fun isThatKind(version: String): Boolean = true // version.contains("-dev")
@ -34,8 +36,10 @@ enum class MiraiVersionKind {
val DEFAULT = Stable
private val REGEX_STABLE = Regex("""^\d+\.\d+(?:\.\d+)?$""")
private val LOG = Logger.getInstance(MiraiVersionKind::class.java)
private suspend fun getMiraiVersionList(): Set<MiraiVersion> {
@Throws(IOException::class)
fun getMiraiVersionList(): Set<MiraiVersion> {
fun download(url: String): Document {
return Jsoup.connect(url)
.followRedirects(true)
@ -44,29 +48,87 @@ enum class MiraiVersionKind {
.get()
}
val document = runInterruptible {
// https://maven.aliyun.com/repository/central/net/mamoe/mirai-core/maven-metadata.xml
// https://repo.maven.apache.org/maven2/net/mamoe/mirai-core/maven-metadata.xml
kotlin.runCatching {
download("https://maven.aliyun.com/repository/central/net/mamoe/mirai-core/maven-metadata.xml")
}.recoverCatching {
download("https://repo.maven.apache.org/maven2/net/mamoe/mirai-core/maven-metadata.xml")
}.getOrThrow()
}
return kotlin.runCatching {
download("https://maven.aliyun.com/repository/central/net/mamoe/mirai-core/maven-metadata.xml")
}.recoverCatching {
download("https://repo.maven.apache.org/maven2/net/mamoe/mirai-core/maven-metadata.xml")
}.map { document ->
val xml = document.toString()
val xml = document.toString()
return Regex("""<version>\s*(.*?)\s*</version>""").findAll(xml).mapNotNull { it.groupValues[1] }.toSet()
Regex("""<version>\s*(.*?)\s*</version>""")
.findAll(xml)
.mapNotNull { it.groupValues.getOrNull(1) }
.sortVersionsDescending()
.toSet()
}.getOrThrow()
}
fun CoroutineScope.getMiraiVersionListAsync(): Deferred<Set<MiraiVersion>> {
return async(CoroutineName("getMiraiVersionListAsync")) {
getMiraiVersionList()
}
}
// Kotlin version: not working because
// Caused by: java.util.ServiceConfigurationError: kotlinx.coroutines.CoroutineExceptionHandler: com.intellij.openapi.application.impl.CoroutineExceptionHandlerImpl not a subtype
//
// private suspend fun getMiraiVersionList(): Set<MiraiVersion> {
// suspend fun download(url: String): Document {
// return Jsoup.connect(url)
// .followRedirects(true)
// .ignoreContentType(true)
// .ignoreHttpErrors(true)
// .run { runInterruptible(Dispatchers.IO) { get() } }
// }
//
// val document = supervisorScope {
// val jobs = mutableListOf<Deferred<Document>>()
// jobs += async {
// download("https://maven.aliyun.com/repository/central/net/mamoe/mirai-core/maven-metadata.xml")
// }
// jobs += async {
// download("https://repo.maven.apache.org/maven2/net/mamoe/mirai-core/maven-metadata.xml")
// }
// val timeout = launch {
// delay(10_000)
// }
// // select the faster one
// select<Document> {
// jobs.forEach { job -> job.onAwait { it } }
// timeout.onJoin {
// throw IllegalStateException("Timeout getMiraiVersionList").apply {
// jobs.forEach {
// if (it.isCompleted) {
// try {
// it.await()
// } catch (e: Throwable) {
// addSuppressed(e)
// }
// }
// }
// }
// }
// }
// jobs.forEach { it.cancel() }
// timeout.cancel()
// }
//
// val xml = document.toString()
//
// return Regex("""<version>\s*(.*?)\s*</version>""").findAll(xml).mapNotNull { it.groupValues.getOrNull(1) }.toSet()
// }
// fun CoroutineScope.getMiraiVersionListAsync(): Deferred<Set<MiraiVersion>> {
// return async(CoroutineName("getMiraiVersionListAsync")) {
// getMiraiVersionList()
// }
// }
}
}
internal fun Sequence<String>.sortVersionsDescending(): Sequence<String> {
return this
.mapNotNull { SemVer.parseFromText(it) }
.sortedWith { o1, o2 ->
o2.compareTo(o1)
}
.map { it.toString() }
}
/*

View File

@ -1,17 +1,18 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* Copyright 2019-2022 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.
* 此源代码的使用受 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
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.console.intellij.creator.steps
import com.intellij.ide.util.projectWizard.ModuleWizardStep
import kotlinx.coroutines.*
import com.intellij.openapi.diagnostic.Logger
import com.intellij.vcs.log.submitSafe
import net.mamoe.mirai.console.compiler.common.CheckerConstants.PLUGIN_ID_PATTERN
import net.mamoe.mirai.console.intellij.creator.MiraiProjectModel
import net.mamoe.mirai.console.intellij.creator.MiraiVersionKind
@ -24,10 +25,12 @@ import net.mamoe.mirai.console.intellij.creator.tasks.adjustToClassName
import net.mamoe.mirai.console.intellij.diagnostics.ContextualParametersChecker
import java.awt.event.ItemEvent
import java.awt.event.ItemListener
import java.util.concurrent.ExecutorService
import javax.swing.*
class PluginCoordinatesStep(
private val model: MiraiProjectModel
private val model: MiraiProjectModel,
private val scope: ExecutorService,
) : ModuleWizardStep() {
private lateinit var panel: JPanel
@ -54,7 +57,7 @@ class PluginCoordinatesStep(
private val versionKindChangeListener: ItemListener = ItemListener { event ->
if (event.stateChange != ItemEvent.SELECTED) return@ItemListener
updateVersionItems()
updateVersionItemsAsync()
}
override fun getPreferredFocusedComponent(): JComponent = idField
@ -70,8 +73,8 @@ class PluginCoordinatesStep(
miraiVersionBox.addItem(VERSION_LOADING_PLACEHOLDER)
miraiVersionBox.selectedItem = VERSION_LOADING_PLACEHOLDER
model.availableMiraiVersionsOrFail.invokeOnCompletion {
updateVersionItems()
model.availableMiraiVersionsOrFail.whenComplete { _, _ ->
updateVersionItemsAsync()
}
if (idField.text.isNullOrEmpty()) {
@ -87,16 +90,15 @@ class PluginCoordinatesStep(
}
}
@OptIn(DelicateCoroutinesApi::class)
private fun updateVersionItems() {
GlobalScope.launch(Dispatchers.Main + CoroutineName("updateVersionItems")) {
if (!model.availableMiraiVersionsOrFail.isCompleted) return@launch
private fun updateVersionItemsAsync() {
scope.submitSafe(LOG) {
if (!model.availableMiraiVersionsOrFail.isDone) return@submitSafe
miraiVersionBox.removeAllItems()
val expectingKind = miraiVersionKindBox.selectedItem as? MiraiVersionKind ?: MiraiVersionKind.DEFAULT
kotlin.runCatching { model.availableMiraiVersionsOrFail.await() }
kotlin.runCatching { model.availableMiraiVersionsOrFail.join() }
.fold(
onSuccess = { versions ->
versions.sortedDescending()
versions
.filter { v -> expectingKind.isThatKind(v) }
.forEach { v -> miraiVersionBox.addItem(v) }
},
@ -141,5 +143,6 @@ class PluginCoordinatesStep(
companion object {
const val VERSION_LOADING_PLACEHOLDER = "Loading..."
private val LOG = Logger.getInstance(PluginCoordinatesStep::class.java)
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2019-2022 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/dev/LICENSE
*/
package creator
import net.mamoe.mirai.console.intellij.creator.sortVersionsDescending
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class MiraiVersionKindTest {
@Test
fun sortVersions() {
assertEquals(
"2.10.0, 2.10.0-RC, 2.10.0-M1, 2.9.0, 2.9.0-RC, 2.9.0-M2, 2.9.0-M1, 2.7.0, 2.7.0-RC"
.split(",")
.map { it.trim() },
sequenceOf(
"2.9.0",
"2.9.0-M1",
"2.9.0-M2",
"2.9.0-RC",
"2.7.0",
"2.7.0-RC",
"2.10.0",
"2.10.0-RC",
"2.10.0-M1"
).sortVersionsDescending().toList()
)
}
}