Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@ detekt/reports/**
local.properties
scan-journal.log

# krpc compat tests
tests/krpc-protocol-compatibility-tests/v*
gradle-conventions/src/main/kotlin/util/krpc_compat/versions.kt
1 change: 1 addition & 0 deletions gradle-conventions-settings/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ rootProject.name = "gradle-conventions-settings"
// Code below is a hack because a chicken-egg problem, I can't use myself as a settings-plugin
apply(from = "src/main/kotlin/conventions-repositories.settings.gradle.kts")
apply(from = "src/main/kotlin/conventions-version-resolution.settings.gradle.kts")
apply(from = "src/main/kotlin/krpc-compat-tests.settings.gradle.kts")

include(":develocity")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ fun VersionCatalogBuilder.resolveKotlinVersion(versionCatalog: Map<String, Strin

// Resolves a core kotlinx.rpc version (without a Kotlin version prefix) from the Version Catalog.
// Uses LIBRARY_VERSION_ENV_VAR_NAME instead if present
fun VersionCatalogBuilder.resolveLibraryVersion(versionCatalog: Map<String, String>) {
fun resolveLibraryVersion(versionCatalog: Map<String, String>): String {
val libraryCoreVersion: String = System.getenv(SettingsConventions.LIBRARY_VERSION_ENV_VAR_NAME)
?.takeIf { it.isNotBlank() }
?: versionCatalog[SettingsConventions.LIBRARY_CORE_VERSION_ALIAS]
Expand All @@ -158,27 +158,31 @@ fun VersionCatalogBuilder.resolveLibraryVersion(versionCatalog: Map<String, Stri
else -> libraryCoreVersion.substringBefore('-') + eapVersion
}

version(SettingsConventions.LIBRARY_CORE_VERSION_ALIAS, resultingVersion)
return resultingVersion
}

fun String.kotlinVersionParsed(): KotlinVersion {
val (major, minor, patch) = substringBefore('-').split(".").map { it.toInt() }
return KotlinVersion(major, minor, patch)
}

val currentPath: Path = file(".").toPath().toAbsolutePath()
val rootDir = findGlobalRootDirPath(currentPath)
val versionCatalog = resolveVersionCatalog(rootDir)
val libVersion = resolveLibraryVersion(versionCatalog)

extra["libVersion"] = libVersion

dependencyResolutionManagement {
versionCatalogs {
create("libs") {
val currentPath = file(".").toPath().toAbsolutePath()
val rootDir = findGlobalRootDirPath(currentPath)

from(files("$rootDir/${SettingsConventions.LIBS_VERSION_CATALOG_PATH}"))

val versionCatalog = resolveVersionCatalog(rootDir)

val (kotlinVersion, compilerVersion) = resolveKotlinVersion(versionCatalog)

resolveLibraryVersion(versionCatalog)
version(SettingsConventions.LIBRARY_CORE_VERSION_ALIAS, libVersion)

val kotlinVersionParsed = kotlinVersion.kotlinVersionParsed()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

import kotlin.io.path.createDirectories
import kotlin.io.path.writeText

// ADD NEW VERSIONS HERE
val versionDirs = mapOf(
"v0_8" to CompatVersion("0.8.1", "2.2.0"),
"v0_9" to CompatVersion("0.9.1", "2.2.0"),
"v0_10" to CompatVersion("0.10.0", "2.2.20"),
)

// DON'T MODIFY BELOW THIS LINE

val globalRootDirValue: String = extra["globalRootDir"] as? String
?: error("globalRootDir property is not set")

val globalRootDir: java.nio.file.Path = java.nio.file.Path.of(globalRootDirValue)

val compatDir: java.nio.file.Path = globalRootDir
.resolve("tests")
.resolve("krpc-protocol-compatibility-tests")

val libVersion = settings.extra["libVersion"] as? String
?: error("libVersion property is not set")

class CompatVersion(
val rpc: String,
val kotlin: String,
)

versionDirs.forEach { (dir, version) ->
val moduleDir = compatDir.resolve(dir)
moduleDir.createDirectories()
val buildFile = moduleDir.resolve("build.gradle.kts")
buildFile.writeText(
"""
/* THIS FILE IS AUTO-GENERATED, DO NOT EDIT! */

import util.krpc_compat.setupCompat

setupCompat("${version.rpc}", "${version.kotlin}")

""".trimIndent()
)
val propertiesFile = moduleDir.resolve("gradle.properties")
propertiesFile.writeText(
"""
/* THIS FILE IS AUTO-GENERATED, DO NOT EDIT! */

kotlin.compiler.runViaBuildToolsApi=true

""".trimIndent()
)

logger.lifecycle("Generating :tests:krpc-protocol-compatibility-tests:$dir")
include(":tests:krpc-protocol-compatibility-tests:$dir")
}

val versionsConventionsFile: java.nio.file.Path = globalRootDir
.resolve("gradle-conventions")
.resolve("src")
.resolve("main")
.resolve("kotlin")
.resolve("util")
.resolve("krpc_compat")
.resolve("versions.kt")

logger.lifecycle("Generating krpc_compat/versions.kt")
versionsConventionsFile.writeText(
"""
|/* THIS FILE IS AUTO-GENERATED, DO NOT EDIT! */
|
|package util.krpc_compat
|
|val krpcCompatVersions = mapOf(
| ${versionDirs.entries.joinToString("\n| ") { "\"${it.key}\" to \"${it.value.rpc}\"," }}
|
| "Latest" to "$libVersion", // current version
|)
|
""".trimMargin()
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ val processCsmTemplates =
tasks.register<ProcessCsmTemplate>(
"processCsmTemplates",
libs.versions.kotlin.compiler.get(),
emptyMap<String, String>(),
templatesDir,
sourcesDir,
)
Expand Down
2 changes: 2 additions & 0 deletions gradle-conventions/src/main/kotlin/util/csm/task.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import kotlin.io.path.writeLines

abstract class ProcessCsmTemplate @Inject constructor(
@get:Input val kotlinComplierVersion: String,
@get:Input val replacementMap: Map<String, String>,
@get:InputDirectory val templatesDir: Provider<Path>,
@get:OutputDirectory val sourcesDir: Provider<Path>,
) : DefaultTask() {
Expand All @@ -43,6 +44,7 @@ abstract class ProcessCsmTemplate @Inject constructor(
val lines = CsmTemplateProcessor.process(
lines = file.readLines(Charsets.UTF_8),
kotlinCompilerVersion = kotlinComplierVersion,
replacementMap = replacementMap,
logger = logger,
)
out.parent.toFile().mkdirs()
Expand Down
12 changes: 10 additions & 2 deletions gradle-conventions/src/main/kotlin/util/csm/template.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.gradle.api.GradleException
import org.slf4j.Logger

object CsmTemplateProcessor {
fun process(lines: List<String>, kotlinCompilerVersion: String, logger: Logger): List<String> {
fun process(lines: List<String>, kotlinCompilerVersion: String, logger: Logger, replacementMap: Map<String, String>): List<String> {
val result = mutableListOf<String>()

val tags: ArrayDeque<String> = ArrayDeque()
Expand All @@ -21,7 +21,7 @@ object CsmTemplateProcessor {
val defaultBuffer = mutableListOf<String>()
val specificBuffer = mutableListOf<String>()

lines.forEachIndexed { i, line ->
lines.map { it.applyReplacements(replacementMap) }.forEachIndexed { i, line ->
val trimmed = line.trim()
when {
trimmed.startsWith("//##csm") -> {
Expand Down Expand Up @@ -179,3 +179,11 @@ object CsmTemplateProcessor {
Skip, Apply;
}
}

private fun String.applyReplacements(replacementMap: Map<String, String>): String {
var result = this
replacementMap.forEach { (from, to) ->
result = result.replace(from, to)
}
return result
}
52 changes: 52 additions & 0 deletions gradle-conventions/src/main/kotlin/util/krpc_compat/setup.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package util.krpc_compat

import org.gradle.api.Project
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.named
import org.jetbrains.kotlin.buildtools.api.ExperimentalBuildToolsApi
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME
import util.withKotlinJvmExtension

private fun kcp(suffix: String, version: String): String {
return "org.jetbrains.kotlinx:kotlinx-rpc-compiler-plugin-$suffix:$version"
}

fun Project.setupCompat(rpcVersion: String, kotlinVersion: String) {
plugins.apply("org.jetbrains.kotlin.jvm")

dependencies.apply {
add("compileOnly", project(":tests:krpc-protocol-compatibility-tests:test-api"))

add("implementation", "org.jetbrains.kotlinx:kotlinx-rpc-krpc-client:$rpcVersion")
add("implementation", "org.jetbrains.kotlinx:kotlinx-rpc-krpc-server:$rpcVersion")
add("implementation", "org.jetbrains.kotlinx:kotlinx-rpc-krpc-serialization-json:$rpcVersion")

val kcpVersion = "$kotlinVersion-$rpcVersion"
add(PLUGIN_CLASSPATH_CONFIGURATION_NAME, kcp("common", kcpVersion))
add(PLUGIN_CLASSPATH_CONFIGURATION_NAME, kcp("cli", kcpVersion))
add(PLUGIN_CLASSPATH_CONFIGURATION_NAME, kcp("backend", kcpVersion))
add(PLUGIN_CLASSPATH_CONFIGURATION_NAME, kcp("k2", kcpVersion))
}

withKotlinJvmExtension {
@OptIn(ExperimentalBuildToolsApi::class, ExperimentalKotlinGradlePluginApi::class)
compilerVersion.set(kotlinVersion)

sourceSets.named("main") {
kotlin.srcDirs(layout.buildDirectory.dir("generated-sources").map { it.asFile.resolve("csm") })
}
}

tasks.named<Jar>("jar") {
archiveVersion.set(rpcVersion)
}

tasks.named("compileKotlin").configure {
dependsOn(":tests:krpc-protocol-compatibility-tests:process_template_${project.name}")
}
}
54 changes: 54 additions & 0 deletions gradle-conventions/src/main/kotlin/util/other/generateSource.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package util.other

import org.gradle.api.DefaultTask
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.register
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import util.withKotlinJvmExtension
import util.withKotlinKmpExtension
import java.io.File
import javax.inject.Inject

abstract class GenerateSourceTask @Inject constructor(
@get:Input val filename: String,
@get:Input val text: String,
@get:OutputDirectory val sourcesDir: File,
) : DefaultTask() {
@TaskAction
fun generate() {
val sourceFile = File(sourcesDir, "${filename}.kt")
sourceFile.writeText(text)
}
}

fun Project.generateSource(
name: String,
text: String,
chooseSourceSet: NamedDomainObjectContainer<KotlinSourceSet>.() -> NamedDomainObjectProvider<KotlinSourceSet>,
) {
val sourcesDir = File(project.layout.buildDirectory.asFile.get(), "generated-sources/kotlin")

val generatePluginVersionTask =
tasks.register<GenerateSourceTask>("generateSources_$name", name, text, sourcesDir)

withKotlinJvmExtension {
chooseSourceSet(sourceSets).configure {
kotlin.srcDir(generatePluginVersionTask.map { it.sourcesDir })
}
}

withKotlinKmpExtension {
chooseSourceSet(sourceSets).configure {
kotlin.srcDir(generatePluginVersionTask.map { it.sourcesDir })
}
}
}
42 changes: 11 additions & 31 deletions gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import util.other.generateSource

/*
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
Expand Down Expand Up @@ -55,36 +56,15 @@ gradlePlugin {
}
}

abstract class GeneratePluginVersionTask @Inject constructor(
@get:Input val pluginVersion: String,
@get:OutputDirectory val sourcesDir: File
) : DefaultTask() {
@TaskAction
fun generate() {
val sourceFile = File(sourcesDir, "Versions.kt")

sourceFile.writeText(
"""
package kotlinx.rpc

public const val PLUGIN_VERSION: String = "$pluginVersion"

""".trimIndent()
)
}
}

val sourcesDir = File(project.layout.buildDirectory.asFile.get(), "generated-sources/pluginVersion")

val generatePluginVersionTask =
tasks.register<GeneratePluginVersionTask>("generatePluginVersion", version.toString(), sourcesDir)

kotlin {
sourceSets {
main {
kotlin.srcDir(generatePluginVersionTask.map { it.sourcesDir })
}
}
}
generateSource(
name = "Versions",
text = """
package kotlinx.rpc

public const val PLUGIN_VERSION: String = "$version"

""".trimIndent(),
chooseSourceSet = { main }
)

logger.lifecycle("[Gradle Plugin] kotlinx.rpc project version: $version")
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ include(":tests")
include(":tests:test-utils")
include(":tests:krpc-compatibility-tests")
include(":tests:krpc-protocol-compatibility-tests")
include(":tests:krpc-protocol-compatibility-tests:test-api")

val kotlinMasterBuild = providers.gradleProperty("kotlinx.rpc.kotlinMasterBuild").orNull == "true"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ public void testMultiModule() {
runTest("src/testData/box/multiModule.kt");
}

@Test
@TestMetadata("serviceDescriptor.kt")
public void testServiceDescriptor() {
runTest("src/testData/box/serviceDescriptor.kt");
}
@Test
@TestMetadata("serviceDescriptor.kt")
public void testServiceDescriptor() {
runTest("src/testData/box/serviceDescriptor.kt");
}

@Test
@TestMetadata("simple.kt")
Expand Down
Loading