Pretty buildscript

This commit is contained in:
Him188 2020-10-03 13:35:05 +08:00
parent a9d4d14576
commit 80722aaea7
10 changed files with 316 additions and 786 deletions

View File

@ -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<DokkaTask>()) {
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<DokkaTask>().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<String, File> {
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<KotlinJvmOptions>
}
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<KotlinProjectExtension>()?.sourceSets
val Project.kotlinTargets
get() =
extensions.findByName("kotlin").safeAs<KotlinSingleTargetExtension>()?.target?.let { listOf(it) }
?: extensions.findByName("kotlin").safeAs<KotlinMultiplatformExtension>()?.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 }

View File

@ -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,

View File

@ -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

View File

@ -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<HttpResponse>(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<Byte> {
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 <R> retryCatching(n: Int, onFailure: () -> Unit = {}, block: () -> R): Result<R> {
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 <E> buildList(builderAction: MutableList<E>.() -> Unit): List<E> {
return ArrayList<E>().apply(builderAction)
}

View File

@ -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<String>("$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)
}
}
}

View File

@ -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")
}

View File

@ -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")
configurePublishing("mirai-core-all")

View File

@ -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<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.androidMain: NamedDomainObjectProvider<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>
get() = named<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>("androidMain")
val NamedDomainObjectContainer<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.androidTest: NamedDomainObjectProvider<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>
get() = named<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>("androidTest")
val NamedDomainObjectContainer<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.jvmMain: NamedDomainObjectProvider<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>
get() = named<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>("jvmMain")
val NamedDomainObjectContainer<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.jvmTest: NamedDomainObjectProvider<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>
get() = named<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>("jvmTest")
fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.implementation1(dependencyNotation: String) =
implementation(dependencyNotation) {
exclude("org.jetbrains.kotlin", "kotlin-stdlib")

View File

@ -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

View File

@ -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<KotlinSourceSet>.androidMain: NamedDomainObjectProvider<KotlinSourceSet>
get() = named<KotlinSourceSet>("androidMain")
val NamedDomainObjectContainer<KotlinSourceSet>.androidTest: NamedDomainObjectProvider<KotlinSourceSet>
get() = named<KotlinSourceSet>("androidTest")
val NamedDomainObjectContainer<KotlinSourceSet>.jvmMain: NamedDomainObjectProvider<KotlinSourceSet>
get() = named<KotlinSourceSet>("jvmMain")
val NamedDomainObjectContainer<KotlinSourceSet>.jvmTest: NamedDomainObjectProvider<KotlinSourceSet>
get() = named<KotlinSourceSet>("jvmTest")
fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.implementation1(dependencyNotation: String) =
implementation(dependencyNotation) {
exclude("org.jetbrains.kotlin", "kotlin-stdlib")