Skip to content

Commit

Permalink
Merge branch '3.1.0-eap' into marychatte/KTOR-7435-Add-serialization-…
Browse files Browse the repository at this point in the history
…for-SSE
  • Loading branch information
marychatte authored Nov 14, 2024
2 parents b89036b + ccb920f commit 0502a51
Show file tree
Hide file tree
Showing 13 changed files with 164 additions and 67 deletions.
9 changes: 6 additions & 3 deletions buildSrc/src/main/kotlin/CI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,19 @@ fun Project.configureTestTasksOnCi() {
*/
private fun KotlinJvmTest.applyTestRetryCompatibilityWorkaround() {
if (targetName == null) return
val originalTargetName = targetName

val executeTestsActionIndex = taskActions.indexOfLast { it.displayName == "Execute executeTests" }
check(executeTestsActionIndex != -1) { "Action executeTests not found" }

// Add the workaround action and then move it to the correct position right before tests execution.
doFirst("workaround for compatibility with testRetry") {
targetName = null
}
doFirst("workaround for compatibility with testRetry") { targetName = null }
val injectedAction = taskActions.removeFirst()
taskActions.add(executeTestsActionIndex, injectedAction)

// Restore targetName value as other plugins might rely on it.
// For example, kover uses it to find test tasks by target name
doLast("restore targetName") { targetName = originalTargetName }
}

// Docs: https://docs.gradle.com/develocity/gradle-plugin/current/#test_retry
Expand Down
3 changes: 1 addition & 2 deletions buildSrc/src/main/kotlin/JsConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ internal fun Project.configureJsTestTasks(target: String) {
val shouldRunJsBrowserTest = !hasProperty("teamcity") || hasProperty("enable-js-tests")
if (shouldRunJsBrowserTest) return

val capitalizedTarget = target.replaceFirstChar { it.titlecase() }
tasks.maybeNamed("clean${capitalizedTarget}BrowserTest") { onlyIf { false } }
tasks.maybeNamed("clean${target.capitalized()}BrowserTest") { onlyIf { false } }
tasks.maybeNamed("${target}BrowserTest") { onlyIf { false } }
}
138 changes: 85 additions & 53 deletions buildSrc/src/main/kotlin/Publication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,73 @@
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

import internal.*
import org.gradle.api.*
import org.gradle.api.publish.*
import org.gradle.api.publish.maven.*
import org.gradle.api.publish.maven.tasks.*
import org.gradle.api.publish.plugins.*
import org.gradle.jvm.tasks.*
import org.gradle.kotlin.dsl.*
import org.gradle.plugins.signing.*
import java.util.concurrent.locks.*

fun isAvailableForPublication(publication: Publication): Boolean {
val name = publication.name
if (name == "maven") return true

var result = false
val jvmAndCommon = setOf(
"jvm",
"androidRelease",
"androidDebug",
"js",
"wasmJs",
"metadata",
"kotlinMultiplatform"
)
result = result || name in jvmAndCommon
result = result || (HOST_NAME == "linux" && (name == "linuxX64" || name == "linuxArm64"))
result = result || (HOST_NAME == "windows" && name == "mingwX64")
val macPublications = setOf(
"iosX64",
"iosArm64",
"iosSimulatorArm64",

"watchosX64",
"watchosArm32",
"watchosArm64",
"watchosSimulatorArm64",
"watchosDeviceArm64",

"tvosX64",
"tvosArm64",
"tvosSimulatorArm64",

"macosX64",
"macosArm64"
)

result = result || (HOST_NAME == "macos" && name in macPublications)

// can be published from any host
val androidNativePublication = setOf(
"androidNativeArm32",
"androidNativeArm64",
"androidNativeX64",
"androidNativeX86"
)

result = result || name in androidNativePublication

return result
}
private val jvmAndCommonTargets = setOf(
"jvm",
"androidRelease",
"androidDebug",
"metadata",
"kotlinMultiplatform",
"maven",
)

private val jsTargets = setOf(
"js",
"wasmJs",
)

private val linuxTargets = setOf(
"linuxX64",
"linuxArm64",
)

private val windowsTargets = setOf(
"mingwX64",
)

private val darwinTargets = setOf(
"iosX64",
"iosArm64",
"iosSimulatorArm64",

"watchosX64",
"watchosArm32",
"watchosArm64",
"watchosSimulatorArm64",
"watchosDeviceArm64",

"tvosX64",
"tvosArm64",
"tvosSimulatorArm64",

"macosX64",
"macosArm64",
)

private val androidNativeTargets = setOf(
"androidNativeArm32",
"androidNativeArm64",
"androidNativeX64",
"androidNativeX86",
)

fun Project.configurePublication() {
apply(plugin = "maven-publish")

tasks.withType<AbstractPublishToMaven>().configureEach {
onlyIf { isAvailableForPublication(publication) }
onlyIf { publication.isAvailableForPublication() }
}
configureAggregatingTasks()

val publishingUser: String? = System.getenv("PUBLISHING_USER")
val publishingPassword: String? = System.getenv("PUBLISHING_PASSWORD")
Expand Down Expand Up @@ -99,7 +100,7 @@ fun Project.configurePublication() {
}
maven {
name = "testLocal"
setUrl("${rootProject.layout.buildDirectory.get().asFile}/m2")
setUrl(rootProject.layout.buildDirectory.dir("m2"))
}
}

Expand All @@ -108,7 +109,8 @@ fun Project.configurePublication() {

pom {
name = project.name
description = project.description?.takeIf { it.isNotEmpty() } ?: "Ktor is a framework for quickly creating web applications in Kotlin with minimal effort."
description = project.description.orEmpty()
.ifEmpty { "Ktor is a framework for quickly creating web applications in Kotlin with minimal effort." }
url = "https://github.com/ktorio/ktor"
licenses {
license {
Expand Down Expand Up @@ -147,6 +149,36 @@ fun Project.configurePublication() {
configureJavadocArtifact()
}

private fun Publication.isAvailableForPublication(): Boolean {
val name = name

var result = name in jvmAndCommonTargets || name in jsTargets || name in androidNativeTargets
result = result || (HOST_NAME == "linux" && name in linuxTargets)
result = result || (HOST_NAME == "windows" && name in windowsTargets)
result = result || (HOST_NAME == "macos" && name in darwinTargets)

return result
}

private fun Project.configureAggregatingTasks() {
registerAggregatingTask("JvmAndCommon", jvmAndCommonTargets)
if (hasJs || hasWasmJs) registerAggregatingTask("Js", jsTargets)
if (hasLinux) registerAggregatingTask("Linux", linuxTargets)
if (hasWindows) registerAggregatingTask("Windows", windowsTargets)
if (hasDarwin) registerAggregatingTask("Darwin", darwinTargets)
if (hasAndroidNative) registerAggregatingTask("AndroidNative", androidNativeTargets)
}

private fun Project.registerAggregatingTask(name: String, targets: Set<String>) {
tasks.register("publish${name}Publications") {
group = PublishingPlugin.PUBLISH_TASK_GROUP
val targetsTasks = targets.mapNotNull { target ->
tasks.maybeNamed("publish${target.capitalized()}PublicationToMavenRepository")
}
dependsOn(targetsTasks)
}
}

private fun Project.configureSigning() {
extra["signing.gnupg.keyName"] = (System.getenv("SIGN_KEY_ID") ?: return)
extra["signing.gnupg.passphrase"] = (System.getenv("SIGN_KEY_PASSPHRASE") ?: return)
Expand Down
6 changes: 2 additions & 4 deletions buildSrc/src/main/kotlin/TargetsConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
@file:OptIn(ExperimentalKotlinGradlePluginApi::class)

import org.gradle.api.*
import org.gradle.api.tasks.testing.*
import org.gradle.kotlin.dsl.*
import org.jetbrains.kotlin.gradle.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.gradle.tasks.*
import java.io.*

private val Project.files: Array<File> get() = project.projectDir.listFiles() ?: emptyArray()
Expand All @@ -27,7 +25,7 @@ val Project.hasAndroidNative: Boolean get() = hasPosix || files.any { it.name ==
val Project.hasWindows: Boolean get() = hasPosix || files.any { it.name == "windows" }
val Project.hasJsAndWasmShared: Boolean get() = files.any { it.name == "jsAndWasmShared" }
val Project.hasJs: Boolean get() = hasCommon || files.any { it.name == "js" } || hasJsAndWasmShared
val Project.hasWasm: Boolean get() = hasCommon || files.any { it.name == "wasmJs" } || hasJsAndWasmShared
val Project.hasWasmJs: Boolean get() = hasCommon || files.any { it.name == "wasmJs" } || hasJsAndWasmShared
val Project.hasJvm: Boolean get() = hasCommon || hasJvmAndNix || hasJvmAndPosix || files.any { it.name == "jvm" }

val Project.hasExplicitNative: Boolean
Expand All @@ -42,7 +40,7 @@ fun Project.configureTargets() {
if (hasJvm) configureJvm()

if (hasJs) configureJs()
if (hasWasm) configureWasm()
if (hasWasmJs) configureWasm()

if (hasPosix) posixTargets()
if (hasNix) nixTargets()
Expand Down
7 changes: 7 additions & 0 deletions buildSrc/src/main/kotlin/internal/String.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package internal

internal fun String.capitalized() = replaceFirstChar { it.uppercase() }
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ serialization = "1.7.3"
ktlint = "3.15.0"
kotlinx-browser = "0.2"

netty = "4.1.114.Final"
netty = "4.1.115.Final"
netty-tcnative = "2.0.69.Final"

jetty = "9.4.56.v20240826"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlin.coroutines.*
import kotlin.test.*
import kotlin.test.assertFailsWith
import kotlin.time.Duration.Companion.minutes

class ServerSentEventsTest : ClientLoader(2.minutes) {
Expand Down
3 changes: 2 additions & 1 deletion ktor-io/api/ktor-io.api
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ public abstract interface class io/ktor/utils/io/ChannelJob {
}

public final class io/ktor/utils/io/ConcurrentIOException : java/lang/IllegalStateException {
public fun <init> (Ljava/lang/String;)V
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class io/ktor/utils/io/CountedByteReadChannel : io/ktor/utils/io/ByteReadChannel {
Expand Down
2 changes: 1 addition & 1 deletion ktor-io/api/ktor-io.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ final class io.ktor.utils.io/ByteChannel : io.ktor.utils.io/BufferedByteWriteCha
}

final class io.ktor.utils.io/ConcurrentIOException : kotlin/IllegalStateException { // io.ktor.utils.io/ConcurrentIOException|null[0]
constructor <init>(kotlin/String) // io.ktor.utils.io/ConcurrentIOException.<init>|<init>(kotlin.String){}[0]
constructor <init>(kotlin/String, kotlin/Throwable? = ...) // io.ktor.utils.io/ConcurrentIOException.<init>|<init>(kotlin.String;kotlin.Throwable?){}[0]
}

final class io.ktor.utils.io/CountedByteReadChannel : io.ktor.utils.io/ByteReadChannel { // io.ktor.utils.io/CountedByteReadChannel|null[0]
Expand Down
34 changes: 32 additions & 2 deletions ktor-io/common/src/io/ktor/utils/io/ByteChannel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import kotlin.concurrent.Volatile
import kotlin.coroutines.*
import kotlin.jvm.*

internal expect val DEVELOPMENT_MODE: Boolean
internal const val CHANNEL_MAX_SIZE: Int = 1024 * 1024

/**
Expand Down Expand Up @@ -189,13 +190,16 @@ public class ByteChannel(public val autoFlush: Boolean = false) : ByteReadChanne
// Resume the previous task
when (previous) {
is TaskType ->
previous.resume(ConcurrentIOException(slot.taskName()))
previous.resume(ConcurrentIOException(slot.taskName(), previous.created))

is Slot.Task ->
previous.resume()

is Slot.Closed -> {
slot.resume(previous.cause)
return
}

Slot.Empty -> {}
}

Expand All @@ -219,6 +223,8 @@ public class ByteChannel(public val autoFlush: Boolean = false) : ByteReadChanne
data class Closed(val cause: Throwable?) : Slot

sealed interface Task : Slot {
val created: Throwable?

val continuation: Continuation<Unit>

fun taskName(): String
Expand All @@ -231,10 +237,30 @@ public class ByteChannel(public val autoFlush: Boolean = false) : ByteReadChanne
}

class Read(override val continuation: Continuation<Unit>) : Task {
override var created: Throwable? = null

init {
if (DEVELOPMENT_MODE) {
created = Throwable("ReadTask 0x${continuation.hashCode().toString(16)}").also {
it.stackTraceToString()
}
}
}

override fun taskName(): String = "read"
}

class Write(override val continuation: Continuation<Unit>) : Task {
override var created: Throwable? = null

init {
if (DEVELOPMENT_MODE) {
created = Throwable("WriteTask 0x${continuation.hashCode().toString(16)}").also {
it.stackTraceToString()
}
}
}

override fun taskName(): String = "write"
}
}
Expand All @@ -243,4 +269,8 @@ public class ByteChannel(public val autoFlush: Boolean = false) : ByteReadChanne
/**
* Thrown when a coroutine awaiting I/O is replaced by another.
*/
public class ConcurrentIOException(taskName: String) : IllegalStateException("Concurrent $taskName attempts")
public class ConcurrentIOException(
taskName: String,
cause: Throwable? = null
) : IllegalStateException("Concurrent $taskName attempts", cause) {
}
10 changes: 10 additions & 0 deletions ktor-io/jvm/src/io/ktor/utils/io/ByteChannel.jvm.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.utils.io

private const val DEVELOPMENT_MODE_KEY: String = "io.ktor.development"

internal actual val DEVELOPMENT_MODE: Boolean
get() = System.getProperty(DEVELOPMENT_MODE_KEY)?.toBoolean() == true
8 changes: 8 additions & 0 deletions ktor-io/posix/src/io/ktor/utils/io/ByteChannel.posix.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.utils.io

internal actual val DEVELOPMENT_MODE: Boolean
get() = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright 2014-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package io.ktor.utils.io

internal actual val DEVELOPMENT_MODE: Boolean
get() = false

0 comments on commit 0502a51

Please sign in to comment.