diff --git a/build.gradle.kts b/build.gradle.kts index 87422303c..042bf4cf0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,33 +2,35 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.jetbrains.dokka.gradle.DokkaTask -import java.time.Duration -import kotlin.math.pow +import org.jetbrains.kotlin.gradle.dsl.* +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.utils.addToStdlib.safeAs buildscript { repositories { mavenLocal() // maven(url = "https://mirrors.huaweicloud.com/repository/maven") - maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") - maven(url = "https://kotlin.bintray.com/kotlinx") + mavenCentral() jcenter() google() - mavenCentral() + maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") + maven(url = "https://kotlin.bintray.com/kotlinx") } dependencies { - classpath("com.android.tools.build:gradle:${Versions.Android.androidGradlePlugin}") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.compiler}") - classpath("org.jetbrains.kotlin:kotlin-serialization:${Versions.Kotlin.compiler}") - classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${Versions.Kotlin.atomicFU}") - classpath("org.jetbrains.kotlinx:binary-compatibility-validator:${Versions.Kotlin.binaryValidator}") + classpath("com.android.tools.build:gradle:${Versions.androidGradlePlugin}") + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${Versions.atomicFU}") + classpath("org.jetbrains.kotlinx:binary-compatibility-validator:${Versions.binaryValidator}") } } plugins { - id("org.jetbrains.dokka") version Versions.Kotlin.dokka apply false + kotlin("jvm") version Versions.kotlinCompiler + kotlin("plugin.serialization") version Versions.kotlinCompiler + id("org.jetbrains.dokka") version Versions.dokka apply false id("net.mamoe.kotlin-jvm-blocking-bridge") version Versions.blockingBridge apply false - id("com.jfrog.bintray") version Versions.Publishing.bintray + id("com.jfrog.bintray") version Versions.bintray } // https://github.com/kotlin/binary-compatibility-validator @@ -57,7 +59,7 @@ runCatching { allprojects { group = "net.mamoe" - version = Versions.Mirai.version + version = Versions.project repositories { mavenLocal() @@ -68,225 +70,143 @@ allprojects { google() mavenCentral() } -} - -subprojects { - if (this@subprojects.name == "java-test") { - return@subprojects - } afterEvaluate { - if (name == "mirai-core-all") { - return@afterEvaluate + configureJvmTarget() + configureMppShadow() + configureEncoding() + configureKotlinTestSettings() + configureKotlinCompilerSettings() + configureKotlinExperimentalUsages() + + if (isKotlinJvmProject) { + configureFlattenSourceSets() } - apply(plugin = "com.github.johnrengelman.shadow") - val kotlin = - runCatching { - (this as ExtensionAware).extensions.getByName("kotlin") as? org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension - }.getOrNull() ?: return@afterEvaluate + configureDokka() + } +} - val shadowJvmJar by tasks.creating(ShadowJar::class) sd@{ - - group = "mirai" - archiveClassifier.set("-all") - - val compilations = - kotlin.targets.filter { it.platformType == org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm } - .map { it.compilations["main"] } - - compilations.forEach { - dependsOn(it.compileKotlinTask) - from(it.output) +fun Project.configureDokka() { + apply(plugin = "org.jetbrains.dokka") + tasks { + val dokka by getting(DokkaTask::class) { + outputFormat = "html" + outputDirectory = "$buildDir/dokka" + } + val dokkaMarkdown by creating(DokkaTask::class) { + outputFormat = "markdown" + outputDirectory = "$buildDir/dokka-markdown" + } + val dokkaGfm by creating(DokkaTask::class) { + outputFormat = "gfm" + outputDirectory = "$buildDir/dokka-gfm" + } + } + for (task in tasks.filterIsInstance()) { + task.configuration { + perPackageOption { + prefix = "net.mamoe.mirai" + skipDeprecated = true } - - println(project.configurations.joinToString()) - - from(project.configurations.getByName("jvmRuntimeClasspath")) - - this.exclude { file -> - file.name.endsWith(".sf", ignoreCase = true) + for (suppressedPackage in arrayOf( + "net.mamoe.mirai.internal", + "net.mamoe.mirai.event.internal", + "net.mamoe.mirai.utils.internal", + "net.mamoe.mirai.internal" + )) { + perPackageOption { + prefix = suppressedPackage + suppress = true + } } + } + } +} - this.manifest { - this.attributes( - "Manifest-Version" to 1, - "Implementation-Vendor" to "Mamoe Technologies", - "Implementation-Title" to this@afterEvaluate.name.toString(), - "Implementation-Version" to this@afterEvaluate.version.toString() - ) - } +@Suppress("NOTHING_TO_INLINE") // or error +fun Project.configureJvmTarget() { + tasks.withType(KotlinJvmCompile::class.java) { + kotlinOptions.jvmTarget = "11" + } + + extensions.findByType(JavaPluginExtension::class.java)?.run { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } +} + +fun Project.configureMppShadow() { + val kotlin = + runCatching { + (this as ExtensionAware).extensions.getByName("kotlin") as? KotlinMultiplatformExtension + }.getOrNull() ?: return + + val shadowJvmJar by tasks.creating(ShadowJar::class) sd@{ + group = "mirai" + archiveClassifier.set("-all") + + val compilations = + kotlin.targets.filter { it.platformType == KotlinPlatformType.jvm } + .map { it.compilations["main"] } + + compilations.forEach { + dependsOn(it.compileKotlinTask) + from(it.output) + } + + println(project.configurations.joinToString()) + + from(project.configurations.getByName("jvmRuntimeClasspath")) + + this.exclude { file -> + file.name.endsWith(".sf", ignoreCase = true) } /* - val shadowJarMd5 = tasks.register("shadowJarMd5") { - dependsOn("shadowJvmJar") - - val outFiles = shadowJvmJar.outputs.files.associateWith { file -> - File(file.parentFile, file.name.removeSuffix(".jar").removeSuffix("-all") + "-all.jar.md5") - } - - outFiles.forEach { (_, output) -> - outputs.files(output) - } - - doLast { - for ((origin, output) in outFiles) { - output - .also { it.createNewFile() } - .writeText(origin.inputStream().md5().toUHexString("").trim(Char::isWhitespace)) - } - } - - tasks.getByName("publish").dependsOn(this) - tasks.getByName("bintrayUpload").dependsOn(this) - }.get() - */ - - val githubUpload by tasks.creating { - group = "mirai" - dependsOn(shadowJvmJar) - - doFirst { - timeout.set(Duration.ofHours(3)) - findLatestFile().let { (_, file) -> - val filename = file.name - println("Uploading file $filename") - runCatching { - upload.GitHub.upload( - file, - project, - "mirai-repo", - "shadow/${project.name}/$filename" - ) - }.exceptionOrNull()?.let { - System.err.println("GitHub Upload failed") - it.printStackTrace() // force show stacktrace - throw it - } - runCatching { - upload.GitHub.upload( - file.inputStream().use { upload.GitHub.run { it.md5().hex().toByteArray(Charsets.UTF_8) } }, - project, - "mirai-repo", - "shadow/${project.name}/$filename.md5" - ) - }.exceptionOrNull()?.let { - System.err.println("GitHub Upload failed") - it.printStackTrace() // force show stacktrace - throw it - } - } - } - } - - apply(plugin = "org.jetbrains.dokka") - this.tasks { - val dokka by getting(DokkaTask::class) { - outputFormat = "html" - outputDirectory = "$buildDir/dokka" - } - val dokkaMarkdown by creating(DokkaTask::class) { - outputFormat = "markdown" - outputDirectory = "$buildDir/dokka-markdown" - } - val dokkaGfm by creating(DokkaTask::class) { - outputFormat = "gfm" - outputDirectory = "$buildDir/dokka-gfm" - } - } - - val dokkaGitHubUpload by tasks.creating { - group = "mirai" - - val dokkaTaskName = "dokka" - - dependsOn(tasks.getByName(dokkaTaskName)) - doFirst { - val baseDir = file("./build/$dokkaTaskName/${project.name}") - - timeout.set(Duration.ofHours(6)) - file("build/$dokkaTaskName/").walk() - .filter { it.isFile } - .map { old -> - if (old.name == "index.md") File(old.parentFile, "README.md").also { new -> old.renameTo(new) } - else old - } - // optimize md - .forEach { file -> - if (file.endsWith(".md")) { - file.writeText( - file.readText().replace("index.md", "README.md", ignoreCase = true) - .replace(Regex("""```\n([\s\S]*?)```""")) { - "\n" + """ - ```kotlin - $it - ``` - """.trimIndent() - }) - } /* else if (file.name == "README.md") { - file.writeText(file.readText().replace(Regex("""(\n\n\|\s)""")) { - "\n\n" + """" - ||| - |:----------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| - | - """.trimIndent() - }) - }*/ - val filename = file.toRelativeString(baseDir) - println("Uploading file $filename") - runCatching { - upload.GitHub.upload( - file, - project, - "mirai-doc", - "${project.name}/${project.version}/$filename" - ) - }.exceptionOrNull()?.let { - System.err.println("GitHub Upload failed") - it.printStackTrace() // force show stacktrace - throw it - } - } - } - } + this.manifest { + this.attributes( + "Manifest-Version" to 1, + "Implementation-Vendor" to "Mamoe Technologies", + "Implementation-Title" to this.name.toString(), + "Implementation-Version" to this.version.toString() + ) + }*/ } +} - afterEvaluate { - tasks.filterIsInstance().forEach { task -> - with(task) { - configuration { - perPackageOption { - prefix = "net.mamoe.mirai" - skipDeprecated = true +fun Project.configureEncoding() { + tasks.withType(JavaCompile::class.java) { + options.encoding = "UTF8" + } +} + +fun Project.configureKotlinTestSettings() { + tasks.withType(Test::class) { + useJUnitPlatform() + } + when { + isKotlinJvmProject -> { + dependencies { + testImplementation(kotlin("test-junit5")) + + testApi("org.junit.jupiter:junit-jupiter-api:5.2.0") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.2.0") + } + } + isKotlinMpp -> { + kotlinSourceSets?.forEach { sourceSet -> + if (sourceSet.name == "common") { + sourceSet.dependencies { + implementation(kotlin("test")) + implementation(kotlin("test-annotations-common")) } - perPackageOption { - prefix = "net.mamoe.mirai.internal" - suppress = true - } - perPackageOption { - prefix = "net.mamoe.mirai.event.internal" - suppress = true - } - perPackageOption { - prefix = "net.mamoe.mirai.utils.internal" - suppress = true - } - perPackageOption { - prefix = "net.mamoe.mirai.internal.utils" - suppress = true - } - perPackageOption { - prefix = "net.mamoe.mirai.internal.contact" - suppress = true - } - perPackageOption { - prefix = "net.mamoe.mirai.internal.message" - suppress = true - } - perPackageOption { - prefix = "net.mamoe.mirai.internal.network" - suppress = true + } else { + sourceSet.dependencies { + implementation(kotlin("test-junit5")) + + implementation("org.junit.jupiter:junit-jupiter-api:5.2.0") + implementation("org.junit.jupiter:junit-jupiter-engine:5.2.0") } } } @@ -294,21 +214,60 @@ subprojects { } } - -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") +fun Project.configureKotlinCompilerSettings() { + val kotlinCompilations = kotlinCompilations ?: return + for (kotlinCompilation in kotlinCompilations) with(kotlinCompilation) { + if (isKotlinJvmProject) { + @Suppress("UNCHECKED_CAST") + this as KotlinCompilation + } + kotlinOptions.freeCompilerArgs += "-Xjvm-default=all" + } } + +val experimentalAnnotations = arrayOf( + "kotlin.RequiresOptIn", + "kotlin.contracts.ExperimentalContracts", + "kotlin.experimental.ExperimentalTypeInference", + "net.mamoe.mirai.utils.MiraiInternalAPI", + "net.mamoe.mirai.utils.MiraiExperimentalAPI", + "net.mamoe.mirai.LowLevelAPI" +) + +fun Project.configureKotlinExperimentalUsages() { + val sourceSets = kotlinSourceSets ?: return + + for (target in sourceSets) { + experimentalAnnotations.forEach { a -> + target.languageSettings.useExperimentalAnnotation(a) + target.languageSettings.progressiveMode = true + target.languageSettings.enableLanguageFeature("InlineClasses") + } + } +} + +fun Project.configureFlattenSourceSets() { + sourceSets { + findByName("main")?.apply { + resources.setSrcDirs(listOf(projectDir.resolve("resources"))) + java.setSrcDirs(listOf(projectDir.resolve("src"))) + } + findByName("test")?.apply { + resources.setSrcDirs(listOf(projectDir.resolve("resources"))) + java.setSrcDirs(listOf(projectDir.resolve("test"))) + } + } +} + +val Project.kotlinSourceSets get() = extensions.findByName("kotlin").safeAs()?.sourceSets + +val Project.kotlinTargets + get() = + extensions.findByName("kotlin").safeAs()?.target?.let { listOf(it) } + ?: extensions.findByName("kotlin").safeAs()?.targets + +val Project.isKotlinJvmProject: Boolean get() = extensions.findByName("kotlin") is KotlinJvmProjectExtension +val Project.isKotlinMpp: Boolean get() = extensions.findByName("kotlin") is KotlinMultiplatformExtension + +val Project.kotlinCompilations + get() = kotlinTargets?.flatMap { it.compilations } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/PublishingHelpers.kt b/buildSrc/src/main/kotlin/PublishingHelpers.kt index ed44db5c8..515327531 100644 --- a/buildSrc/src/main/kotlin/PublishingHelpers.kt +++ b/buildSrc/src/main/kotlin/PublishingHelpers.kt @@ -1,7 +1,6 @@ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "NOTHING_TO_INLINE", "RemoveRedundantBackticks") import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.publish.maven.MavenPublication @@ -9,7 +8,6 @@ import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.bundling.Jar import org.gradle.kotlin.dsl.* import upload.Bintray -import java.io.File import java.util.* import kotlin.reflect.KProperty @@ -54,7 +52,7 @@ internal fun org.gradle.api.Project.`publishing`(configure: org.gradle.api.publi (this as org.gradle.api.plugins.ExtensionAware).extensions.configure("publishing", configure) -inline fun Project.setupPublishing( +inline fun Project.configurePublishing( artifactId: String, bintrayRepo: String = "mirai", bintrayPkgName: String = artifactId, diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index c847df1d7..911c2ce0d 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,49 +1,64 @@ +@file:Suppress("ObjectPropertyName", "ObjectPropertyName", "unused") /* - * Copyright 2019-2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ +* Copyright 2019-2020 Mamoe Technologies and contributors. +* +* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. +* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link. +* +* https://github.com/mamoe/mirai/blob/master/LICENSE +*/ object Versions { - object Mirai { - const val version = "2.0-M1" - } + const val project = "2.0-M1" - object Kotlin { - const val compiler = "1.4.10" - const val stdlib = "1.4.10" - const val coroutines = "1.3.9" - const val atomicFU = "0.14.4" - const val serialization = "1.0.0-RC" - const val ktor = "1.4.0" - const val binaryValidator = "0.2.3" + const val kotlinCompiler = "1.4.10" + const val kotlinStdlib = "1.4.10" + const val coroutines = "1.3.9" + const val atomicFU = "0.14.4" + const val serialization = "1.0.0-RC" + const val ktor = "1.4.1" - const val io = "0.1.16" - const val coroutinesIo = "0.1.16" - const val dokka = "0.10.1" - } + const val binaryValidator = "0.2.3" - val blockingBridge = "1.1.0" + const val io = "0.1.16" + const val coroutinesIo = "0.1.16" + const val dokka = "0.10.1" - object Android { - const val androidGradlePlugin = "3.5.3" - } + const val blockingBridge = "1.1.0" - object Publishing { - const val bintray = "1.8.5" - } + const val androidGradlePlugin = "3.5.3" - object Logging { - const val slf4j = "1.7.30" - const val log4j = "2.13.3" - } + const val bintray = "1.8.5" + + const val slf4j = "1.7.30" + const val log4j = "2.13.3" } @Suppress("unused") fun kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version" @Suppress("unused") -fun ktor(id: String, version: String = Versions.Kotlin.ktor) = "io.ktor:ktor-$id:$version" +fun ktor(id: String, version: String = Versions.ktor) = "io.ktor:ktor-$id:$version" + + +val `kotlinx-coroutines-core` = kotlinx("coroutines-core", Versions.coroutines) +val `kotlinx-serialization-core` = kotlinx("serialization-core", Versions.serialization) +val `kotlinx-serialization-json` = kotlinx("serialization-json", Versions.serialization) +val `kotlinx-serialization-protobuf` = kotlinx("serialization-protobuf", Versions.serialization) +const val `kotlinx-atomicfu` = "org.jetbrains.kotlinx:atomicfu:${Versions.atomicFU}" +val `kotlinx-io` = kotlinx("io", Versions.io) +val `kotlinx-io-jvm` = kotlinx("io-jvm", Versions.io) +val `kotlinx-coroutines-io` = kotlinx("coroutines-io", Versions.coroutinesIo) +val `kotlinx-coroutines-io-jvm` = kotlinx("coroutines-io-jvm", Versions.coroutinesIo) + +val `ktor-serialization` = ktor("serialization", Versions.ktor) + +val `ktor-client-core` = ktor("client-core", Versions.ktor) +val `ktor-client-cio` = ktor("client-cio", Versions.ktor) +val `ktor-client-android` = ktor("client-android", Versions.ktor) +val `ktor-network` = ktor("network", Versions.ktor) +val `ktor-client-okhttp` = ktor("client-okhttp", Versions.ktor) +val `ktor-client-serialization-jvm` = ktor("client-serialization-jvm", Versions.ktor) + +const val slf4j = "org.slf4j:slf4j-api:" + Versions.slf4j +const val `log4j-api` = "org.apache.logging.log4j:log4j-api:" + Versions.log4j \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/upload/CuiCloud.kt b/buildSrc/src/main/kotlin/upload/CuiCloud.kt deleted file mode 100644 index 8b46101e7..000000000 --- a/buildSrc/src/main/kotlin/upload/CuiCloud.kt +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2019-2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - -package upload - -import io.ktor.client.request.* -import io.ktor.client.request.forms.* -import io.ktor.client.statement.* -import io.ktor.http.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -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.* -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@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) - - - val bytes = file.readBytes() - - runBlocking { - var first = true - retryCatching(1000) { - if (!first) { - println() - println() - println("Upload failed. Waiting 15s") - delay(15_000) - } - first = false - uploadToCuiCloud( - cuiCloudUrl, - key, - "/mirai/${project.name}/${file.nameWithoutExtension}.mp4", - bytes - ) - }.getOrThrow() - } - } - - @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}") - } - } -} - - -@OptIn(ExperimentalContracts::class) -@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE") -@kotlin.internal.InlineOnly -internal inline fun retryCatching(n: Int, onFailure: () -> Unit = {}, block: () -> R): Result { - contract { - callsInPlace(block, InvocationKind.AT_LEAST_ONCE) - } - require(n >= 0) { "param n for retryCatching must not be negative" } - var exception: Throwable? = null - repeat(n) { - try { - return Result.success(block()) - } catch (e: Throwable) { - try { - exception?.addSuppressed(e) - } catch (e: Throwable) { - } - exception = e - onFailure() - } - } - return Result.failure(exception!!) -} - -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 deleted file mode 100644 index ace819be9..000000000 --- a/buildSrc/src/main/kotlin/upload/GitHub.kt +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2019-2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - -@file:Suppress("EXPERIMENTAL_API_USAGE") - -package upload - -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import io.ktor.client.* -import io.ktor.client.engine.cio.* -import io.ktor.client.features.* -import io.ktor.client.request.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -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 ByteArray.hex(): String = buildString(size * 2) { - this@hex.forEach { byte -> - val uint = Integer.toHexString(byte.toInt() and 0xFF) - if (uint.length == 1) append('0') - append(uint) - } - } - - fun upload(file: File, project: Project, repo: String, targetFilePath: String) = upload( - file.readBytes(), project, repo, targetFilePath - ) - - fun upload(source: ByteArray, project: Project, repo: String, targetFilePath: String) = runBlocking { - val token = getGithubToken(project) - println("token.length=${token.length}") - val url = "https://api.github.com/repos/project-mirai/$repo/contents/$targetFilePath" - retryCatching(100, onFailure = { delay(30_000) }) { // 403 forbidden? - Http.put("$url?access_token=$token") { - val sha = retryCatching(3, onFailure = { delay(30_000) }) { - getGithubSha( - repo, - targetFilePath, - "master", - project - ) - }.getOrNull() - println("sha=$sha") - val content = String(Base64.getEncoder().encode(source)) - body = """ - { - "message": "Automatically upload on release ${project.name}:${project.version}", - "content": "$content" - ${if (sha == null) "" else """, "sha": "$sha" """} - } - """.trimIndent() - }.let { - println("Upload response: $it") - } - delay(1000) - }.getOrThrow() - } - - - 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/project-mirai/$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/project-mirai/$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/java-test/build.gradle.kts b/java-test/build.gradle.kts deleted file mode 100644 index 3cb966ef9..000000000 --- a/java-test/build.gradle.kts +++ /dev/null @@ -1,22 +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 - */ - - -plugins { - java -} - - -dependencies { - - implementation(project(":mirai-core")) - - implementation(project(":mirai-serialization")) - - testImplementation(group = "junit", name = "junit", version = "4.12") -} diff --git a/mirai-core-all/build.gradle.kts b/mirai-core-all/build.gradle.kts index d396a559c..51c5e2bab 100644 --- a/mirai-core-all/build.gradle.kts +++ b/mirai-core-all/build.gradle.kts @@ -9,7 +9,7 @@ plugins { id("net.mamoe.kotlin-jvm-blocking-bridge") } -version = Versions.Mirai.version +version = Versions.project description = "Mirai core shadowed" java { @@ -22,34 +22,7 @@ tasks.withType(JavaCompile::class.java) { } kotlin { - explicitApiWarning() - - sourceSets.all { - target.compilations.all { - kotlinOptions { - jvmTarget = "1.8" - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" - //useIR = true - } - } - languageSettings.apply { - enableLanguageFeature("InlineClasses") - progressiveMode = true - - useExperimentalAnnotation("kotlin.Experimental") - useExperimentalAnnotation("kotlin.RequiresOptIn") - - useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI") - useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiExperimentalAPI") - useExperimentalAnnotation("net.mamoe.mirai.console.ConsoleFrontEndImplementation") - useExperimentalAnnotation("net.mamoe.mirai.console.util.ConsoleExperimentalApi") - useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") - useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference") - useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") - useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi") - useExperimentalAnnotation("net.mamoe.mirai.console.util.ConsoleInternalApi") - } - } + explicitApi() } dependencies { @@ -57,4 +30,4 @@ dependencies { api(project(":mirai-core-api")) } -setupPublishing("mirai-core-all") \ No newline at end of file +configurePublishing("mirai-core-all") \ No newline at end of file diff --git a/mirai-core-api/build.gradle.kts b/mirai-core-api/build.gradle.kts index a27495b7a..3eaf02f2b 100644 --- a/mirai-core-api/build.gradle.kts +++ b/mirai-core-api/build.gradle.kts @@ -38,70 +38,38 @@ kotlin { } jvm { - // withJava() // https://youtrack.jetbrains.com/issue/KT-39991 + withJava() } - sourceSets.apply { - all { - languageSettings.enableLanguageFeature("InlineClasses") - languageSettings.useExperimentalAnnotation("kotlin.Experimental") - languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI") - languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiExperimentalAPI") - languageSettings.useExperimentalAnnotation("net.mamoe.mirai.LowLevelAPI") - languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") - languageSettings.useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference") - languageSettings.useExperimentalAnnotation("kotlin.time.ExperimentalTime") - languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") - languageSettings.useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi") - languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.UnstableExternalImage") - - languageSettings.progressiveMode = true - } - + sourceSets { val commonMain by getting { dependencies { api(kotlin("serialization")) api(kotlin("reflect")) - api1(kotlinx("serialization-core", Versions.Kotlin.serialization)) - implementation1(kotlinx("serialization-protobuf", Versions.Kotlin.serialization)) - api1(kotlinx("io", Versions.Kotlin.io)) - api1(kotlinx("coroutines-io", Versions.Kotlin.coroutinesIo)) - api(kotlinx("coroutines-core", Versions.Kotlin.coroutines)) + api1(`kotlinx-serialization-core`) + implementation1(`kotlinx-serialization-protobuf`) + api1(`kotlinx-io`) + api1(`kotlinx-coroutines-io`) + api(`kotlinx-coroutines-core`) - implementation1("org.jetbrains.kotlinx:atomicfu:${Versions.Kotlin.atomicFU}") + implementation1(`kotlinx-atomicfu`) - api1(ktor("client-cio")) - api1(ktor("client-core")) - api1(ktor("network")) - } - } - - commonTest { - dependencies { - implementation(kotlin("test-annotations-common")) - implementation(kotlin("test-common")) + api1(`ktor-client-cio`) + api1(`ktor-client-core`) + api1(`ktor-network`) } } if (isAndroidSDKAvailable) { - val androidMain by getting { + androidMain { dependencies { api(kotlin("reflect")) - api1(kotlinx("io-jvm", Versions.Kotlin.io)) - api1(kotlinx("coroutines-io-jvm", Versions.Kotlin.coroutinesIo)) + api1(`kotlinx-io-jvm`) + api1(`kotlinx-coroutines-io-jvm`) - api1(ktor("client-android", Versions.Kotlin.ktor)) - } - } - - val androidTest by getting { - dependencies { - implementation(kotlin("test")) - implementation(kotlin("test-junit")) - implementation(kotlin("test-annotations-common")) - implementation(kotlin("test-common")) + api1(`ktor-client-android`) } } } @@ -109,20 +77,17 @@ kotlin { val jvmMain by getting { dependencies { api(kotlin("reflect")) - compileOnly("org.apache.logging.log4j:log4j-api:" + Versions.Logging.log4j) - compileOnly("org.slf4j:slf4j-api:" + Versions.Logging.slf4j) + compileOnly(`log4j-api`) + compileOnly(slf4j) - api1(ktor("client-core-jvm", Versions.Kotlin.ktor)) - api1(kotlinx("io-jvm", Versions.Kotlin.io)) - api1(kotlinx("coroutines-io-jvm", Versions.Kotlin.coroutinesIo)) + api1(`kotlinx-io-jvm`) + api1(`kotlinx-coroutines-io-jvm`) } } val jvmTest by getting { dependencies { - implementation(kotlin("test")) - implementation(kotlin("test-junit")) - implementation("org.pcap4j:pcap4j-distribution:1.8.2") + api("org.pcap4j:pcap4j-distribution:1.8.2") runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE } @@ -130,6 +95,20 @@ kotlin { } } +val NamedDomainObjectContainer.androidMain: NamedDomainObjectProvider + get() = named("androidMain") + +val NamedDomainObjectContainer.androidTest: NamedDomainObjectProvider + get() = named("androidTest") + + +val NamedDomainObjectContainer.jvmMain: NamedDomainObjectProvider + get() = named("jvmMain") + +val NamedDomainObjectContainer.jvmTest: NamedDomainObjectProvider + get() = named("jvmTest") + + fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.implementation1(dependencyNotation: String) = implementation(dependencyNotation) { exclude("org.jetbrains.kotlin", "kotlin-stdlib") diff --git a/mirai-core-api/src/commonMain/kotlin/BotFactory.kt b/mirai-core-api/src/commonMain/kotlin/BotFactory.kt index 0dcfe01dc..bd4dde5e8 100644 --- a/mirai-core-api/src/commonMain/kotlin/BotFactory.kt +++ b/mirai-core-api/src/commonMain/kotlin/BotFactory.kt @@ -6,6 +6,7 @@ * * https://github.com/mamoe/mirai/blob/master/LICENSE */ + @file:Suppress("FunctionName", "INAPPLICABLE_JVM_NAME", "DEPRECATION_ERROR", "DeprecatedCallableAddReplaceWith") package net.mamoe.mirai diff --git a/mirai-core/build.gradle.kts b/mirai-core/build.gradle.kts index 342b7b2ce..54738eb40 100644 --- a/mirai-core/build.gradle.kts +++ b/mirai-core/build.gradle.kts @@ -1,5 +1,7 @@ @file:Suppress("UNUSED_VARIABLE") +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet + plugins { kotlin("multiplatform") id("kotlinx-atomicfu") @@ -60,60 +62,71 @@ kotlin { } } - val commonMain by getting { + commonMain { dependencies { - api1(kotlinx("serialization-core", Versions.Kotlin.serialization)) - api(kotlinx("coroutines-core", Versions.Kotlin.coroutines)) - implementation1(kotlinx("serialization-protobuf", Versions.Kotlin.serialization)) - api1("org.jetbrains.kotlinx:atomicfu:${Versions.Kotlin.atomicFU}") - api1(kotlinx("io", Versions.Kotlin.io)) - implementation1(kotlinx("coroutines-io", Versions.Kotlin.coroutinesIo)) + api1(`kotlinx-serialization-core`) + implementation1(`kotlinx-serialization-protobuf`) + + api1(`kotlinx-atomicfu`) + api1(`kotlinx-coroutines-core`) + + api1(`kotlinx-io`) + implementation1(`kotlinx-coroutines-io`) } } - val commonTest by getting { + commonTest { dependencies { - implementation(kotlin("test-annotations-common")) - implementation(kotlin("test-common")) implementation(kotlin("script-runtime")) } } if (isAndroidSDKAvailable) { - val androidMain by getting { + androidMain { dependencies { } } - val androidTest by getting { + androidTest { dependencies { - implementation(kotlin("test", Versions.Kotlin.compiler)) - implementation(kotlin("test-junit", Versions.Kotlin.compiler)) + implementation(kotlin("test", Versions.kotlinCompiler)) + implementation(kotlin("test-junit", Versions.kotlinCompiler)) implementation(kotlin("test-annotations-common")) implementation(kotlin("test-common")) } } } - val jvmMain by getting { + jvmMain { dependencies { implementation("org.bouncycastle:bcprov-jdk15on:1.64") - api1(kotlinx("io-jvm", Versions.Kotlin.io)) - // api(kotlinx("coroutines-debug", Versions.Kotlin.coroutines)) + api1(`kotlinx-io-jvm`) + // api(kotlinx("coroutines-debug", Versions.coroutines)) } } - val jvmTest by getting { + jvmTest { dependencies { - dependsOn(commonTest) - implementation(kotlin("test", Versions.Kotlin.compiler)) - implementation(kotlin("test-junit", Versions.Kotlin.compiler)) implementation("org.pcap4j:pcap4j-distribution:1.8.2") } } } } +val NamedDomainObjectContainer.androidMain: NamedDomainObjectProvider + get() = named("androidMain") + +val NamedDomainObjectContainer.androidTest: NamedDomainObjectProvider + get() = named("androidTest") + + +val NamedDomainObjectContainer.jvmMain: NamedDomainObjectProvider + get() = named("jvmMain") + +val NamedDomainObjectContainer.jvmTest: NamedDomainObjectProvider + get() = named("jvmTest") + + fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.implementation1(dependencyNotation: String) = implementation(dependencyNotation) { exclude("org.jetbrains.kotlin", "kotlin-stdlib")