From 80722aaea73d072a6c749a0fd1c1b3bbbb8232e0 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Sat, 3 Oct 2020 13:35:05 +0800
Subject: [PATCH] Pretty buildscript

---
 build.gradle.kts                              | 429 ++++++++----------
 buildSrc/src/main/kotlin/PublishingHelpers.kt |   4 +-
 buildSrc/src/main/kotlin/Versions.kt          |  83 ++--
 buildSrc/src/main/kotlin/upload/CuiCloud.kt   | 175 -------
 buildSrc/src/main/kotlin/upload/GitHub.kt     | 211 ---------
 java-test/build.gradle.kts                    |  22 -
 mirai-core-all/build.gradle.kts               |  33 +-
 mirai-core-api/build.gradle.kts               |  89 ++--
 .../src/commonMain/kotlin/BotFactory.kt       |   1 +
 mirai-core/build.gradle.kts                   |  55 ++-
 10 files changed, 316 insertions(+), 786 deletions(-)
 delete mode 100644 buildSrc/src/main/kotlin/upload/CuiCloud.kt
 delete mode 100644 buildSrc/src/main/kotlin/upload/GitHub.kt
 delete mode 100644 java-test/build.gradle.kts

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