Skip to content

Commit 84701d0

Browse files
committed
Simplified grpc gradle config (#281)
* Simplified grpc gradle config * Enabled explicit API for the Gradle Plugin
1 parent 2ccfdec commit 84701d0

File tree

9 files changed

+314
-35
lines changed

9 files changed

+314
-35
lines changed

gradle-plugin/build.gradle.kts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ tasks.withType<KotlinCompile>().configureEach {
3131
}
3232

3333
dependencies {
34+
implementation(libs.protobuf.gradle.plugin)
3435
compileOnly(libs.kotlin.gradle.plugin)
3536
}
3637

@@ -57,7 +58,10 @@ gradlePlugin {
5758
}
5859

5960
abstract class GeneratePluginVersionTask @Inject constructor(
60-
@get:Input val pluginVersion: String,
61+
@get:Input val libraryVersion: String,
62+
@get:Input val protobufVersion: String,
63+
@get:Input val grpcVersion: String,
64+
@get:Input val grpcKotlinVersion: String,
6165
@get:OutputDirectory val sourcesDir: File
6266
) : DefaultTask() {
6367
@TaskAction
@@ -68,7 +72,14 @@ abstract class GeneratePluginVersionTask @Inject constructor(
6872
"""
6973
package kotlinx.rpc
7074
71-
public const val PLUGIN_VERSION: String = "$pluginVersion"
75+
public const val LIBRARY_VERSION: String = "$libraryVersion"
76+
77+
@Deprecated("Use kotlinx.rpc.LIBRARY_VERSION instead", ReplaceWith("kotlinx.rpc.LIBRARY_VERSION"))
78+
public const val PLUGIN_VERSION: String = LIBRARY_VERSION
79+
80+
public const val PROTOBUF_VERSION: String = "$protobufVersion"
81+
public const val GRPC_VERSION: String = "$grpcVersion"
82+
public const val GRPC_KOTLIN_VERSION: String = "$grpcKotlinVersion"
7283
7384
""".trimIndent()
7485
)
@@ -77,8 +88,14 @@ abstract class GeneratePluginVersionTask @Inject constructor(
7788

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

80-
val generatePluginVersionTask =
81-
tasks.register<GeneratePluginVersionTask>("generatePluginVersion", version.toString(), sourcesDir)
91+
val generatePluginVersionTask = tasks.register<GeneratePluginVersionTask>(
92+
"generatePluginVersion",
93+
version.toString(),
94+
libs.versions.protobuf.asProvider().get().toString(),
95+
libs.versions.grpc.asProvider().get().toString(),
96+
libs.versions.grpc.kotlin.get().toString(),
97+
sourcesDir,
98+
)
8299

83100
kotlin {
84101
sourceSets {

gradle-plugin/src/main/kotlin/kotlinx/rpc/Extensions.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77
package kotlinx.rpc
88

99
import org.gradle.api.Action
10+
import org.gradle.api.Project
1011
import org.gradle.api.model.ObjectFactory
1112
import org.gradle.api.provider.Property
13+
import org.gradle.kotlin.dsl.findByType
1214
import org.gradle.api.provider.Provider
1315
import org.gradle.kotlin.dsl.newInstance
1416
import org.gradle.kotlin.dsl.property
1517
import javax.inject.Inject
1618

19+
public fun Project.rpcExtension(): RpcExtension = extensions.findByType<RpcExtension>() ?: RpcExtension(objects)
20+
1721
public open class RpcExtension @Inject constructor(objects: ObjectFactory) {
1822
/**
1923
* Controls `@Rpc` [annotation type-safety](https://github.com/Kotlin/kotlinx-rpc/pull/240) compile-time checkers.
@@ -37,6 +41,18 @@ public open class RpcExtension @Inject constructor(objects: ObjectFactory) {
3741
public fun strict(configure: Action<RpcStrictModeExtension>) {
3842
configure.execute(strict)
3943
}
44+
45+
/**
46+
* Grpc settings.
47+
*/
48+
public val grpc: GrpcExtension = objects.newInstance<GrpcExtension>()
49+
50+
/**
51+
* Grpc settings.
52+
*/
53+
public fun grpc(configure: Action<GrpcExtension>) {
54+
configure.execute(grpc)
55+
}
4056
}
4157

4258
public open class RpcStrictModeExtension @Inject constructor(objects: ObjectFactory) {
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.rpc
6+
7+
import com.google.protobuf.gradle.ExecutableLocator
8+
import com.google.protobuf.gradle.GenerateProtoTask
9+
import com.google.protobuf.gradle.ProtobufExtension
10+
import org.gradle.api.Action
11+
import org.gradle.api.GradleException
12+
import org.gradle.api.Project
13+
import org.gradle.api.model.ObjectFactory
14+
import org.gradle.api.provider.Property
15+
import org.gradle.api.specs.Spec
16+
import org.gradle.api.tasks.TaskCollection
17+
import org.gradle.kotlin.dsl.findByType
18+
import org.gradle.kotlin.dsl.property
19+
import org.gradle.kotlin.dsl.the
20+
import javax.inject.Inject
21+
22+
public open class GrpcExtension @Inject constructor(objects: ObjectFactory, private val project: Project) {
23+
/**
24+
* Determines whether the gRPC support is enabled in the project.
25+
*
26+
* Allows for additional configuration checks.
27+
*/
28+
public val enabled: Property<Boolean> = objects.property<Boolean>().convention(false)
29+
30+
/**
31+
* Access for [GrpcPlugin] for [LOCATOR_NAME] name.
32+
*/
33+
public fun plugin(action: Action<GrpcPlugin>) {
34+
pluginAccess(action, LOCATOR_NAME)
35+
}
36+
37+
/**
38+
* Access for [GrpcPlugin] for [GRPC_JAVA_LOCATOR_NAME] name.
39+
*/
40+
public fun grpcJavaPlugin(action: Action<GrpcPlugin>) {
41+
pluginAccess(action, GRPC_JAVA_LOCATOR_NAME)
42+
}
43+
44+
/**
45+
* Access for [GrpcPlugin] for [GRPC_KOTLIN_LOCATOR_NAME] name.
46+
*/
47+
public fun grpcKotlinPlugin(action: Action<GrpcPlugin>) {
48+
pluginAccess(action, GRPC_KOTLIN_LOCATOR_NAME)
49+
}
50+
51+
/**
52+
* Shortcut for
53+
*
54+
* ```kotlin
55+
* protobuf {
56+
* generateProtoTasks.all().all { ... }
57+
* }
58+
* ```
59+
*/
60+
public fun tasks(taskAction: Action<GenerateProtoTask>) {
61+
project.the<ProtobufExtension>().generateProtoTasks.all().all(taskAction)
62+
}
63+
64+
/**
65+
* Shortcut for
66+
*
67+
* ```kotlin
68+
* protobuf {
69+
* generateProtoTasks.all().matching { ... }
70+
* }
71+
* ```
72+
*/
73+
public fun tasksMatching(spec: Spec<in GenerateProtoTask>): TaskCollection<GenerateProtoTask> {
74+
return project.the<ProtobufExtension>().generateProtoTasks.all().matching(spec)
75+
}
76+
77+
private fun pluginAccess(action: Action<GrpcPlugin>, locatorName: String) {
78+
val extension = project.the<ProtobufExtension>()
79+
val plugin = object : GrpcPlugin {
80+
override fun options(options: Action<GenerateProtoTask.PluginOptions>) {
81+
extension.generateProtoTasks.all().all {
82+
options.execute(plugins.maybeCreate(locatorName))
83+
}
84+
}
85+
86+
override fun locator(locatorAction: Action<ExecutableLocator>) {
87+
extension.plugins {
88+
locatorAction.execute(maybeCreate(locatorName))
89+
}
90+
}
91+
}
92+
93+
action.execute(plugin)
94+
}
95+
96+
public companion object {
97+
/**
98+
* [com.google.protobuf.gradle.ExecutableLocator]'s name for the `kotlinx-rpc` plugin
99+
*
100+
* ```kotlin
101+
* protobuf {
102+
* plugins {
103+
* named(LOCATOR_NAME)
104+
* }
105+
* }
106+
* ```
107+
*
108+
* Same name is used for [GenerateProtoTask] plugin in `generateProtoTasks.plugins`
109+
*/
110+
public const val LOCATOR_NAME: String = "kotlinx-rpc"
111+
112+
/**
113+
* [com.google.protobuf.gradle.ExecutableLocator]'s name for the `grpc-java` plugin
114+
*
115+
* ```kotlin
116+
* protobuf {
117+
* plugins {
118+
* named(GRPC_JAVA_LOCATOR_NAME)
119+
* }
120+
* }
121+
* ```
122+
*
123+
* Same name is used for [GenerateProtoTask] plugin in `generateProtoTasks.plugins`
124+
*/
125+
public const val GRPC_JAVA_LOCATOR_NAME: String = "grpc"
126+
127+
/**
128+
* [com.google.protobuf.gradle.ExecutableLocator]'s name for the `grpc-kotlin` plugin
129+
*
130+
* ```kotlin
131+
* protobuf {
132+
* plugins {
133+
* named(GRPC_KOTLIN_LOCATOR_NAME)
134+
* }
135+
* }
136+
* ```
137+
*
138+
* Same name is used for [GenerateProtoTask] plugin in `generateProtoTasks.plugins`
139+
*/
140+
public const val GRPC_KOTLIN_LOCATOR_NAME: String = "grpckt"
141+
}
142+
}
143+
144+
/**
145+
* Access to a specific protobuf plugin.
146+
*/
147+
public interface GrpcPlugin {
148+
/**
149+
* Access for [GenerateProtoTask.PluginOptions]
150+
*
151+
* ```kotlin
152+
* rpc {
153+
* grpc {
154+
* plugin {
155+
* options {
156+
* option("option=value")
157+
* }
158+
* }
159+
* }
160+
* }
161+
* ```
162+
*/
163+
public fun options(optionsAction: Action<GenerateProtoTask.PluginOptions>)
164+
165+
/**
166+
* Access for [ExecutableLocator]
167+
*
168+
* ```kotlin
169+
* rpc {
170+
* grpc {
171+
* plugin {
172+
* locator {
173+
* path = "$buildDirPath/libs/protobuf-plugin-$version-all.jar"
174+
* }
175+
* }
176+
* }
177+
* }
178+
* ```
179+
*/
180+
public fun locator(locatorAction: Action<ExecutableLocator>)
181+
}
182+
183+
internal fun Project.configureGrpc() {
184+
val grpc = rpcExtension().grpc
185+
var wasApplied = false
186+
187+
pluginManager.withPlugin("com.google.protobuf") {
188+
if (wasApplied) {
189+
return@withPlugin
190+
}
191+
192+
wasApplied = true
193+
194+
val protobuf = extensions.findByType<ProtobufExtension>()
195+
?: run {
196+
logger.error("Protobuf plugin (com.google.protobuf) was not applied. Please report of this issue.")
197+
return@withPlugin
198+
}
199+
200+
protobuf.configureProtobuf(project = project)
201+
}
202+
203+
afterEvaluate {
204+
if (grpc.enabled.get() && !wasApplied) {
205+
throw GradleException(
206+
"""
207+
gRPC Support is enabled, but 'com.google.protobuf' was not be applied during project evaluation.
208+
The 'com.google.protobuf' plugin must be applied to the project first.
209+
""".trimIndent()
210+
)
211+
}
212+
}
213+
}
214+
215+
private fun ProtobufExtension.configureProtobuf(project: Project) {
216+
val buildDirPath: String = project.layout.buildDirectory.get().asFile.absolutePath
217+
218+
protoc {
219+
artifact = "com.google.protobuf:protoc:$PROTOBUF_VERSION"
220+
}
221+
222+
plugins {
223+
val existed = findByName(GrpcExtension.LOCATOR_NAME) != null
224+
maybeCreate(GrpcExtension.LOCATOR_NAME).apply {
225+
if (!existed) {
226+
artifact = "org.jetbrains.kotlinx:kotlinx-rpc-protobuf-plugin:$LIBRARY_VERSION:all@jar"
227+
}
228+
}
229+
230+
val grpcJavaPluginExisted = findByName(GrpcExtension.GRPC_JAVA_LOCATOR_NAME) != null
231+
maybeCreate(GrpcExtension.GRPC_JAVA_LOCATOR_NAME).apply {
232+
if (!grpcJavaPluginExisted) {
233+
artifact = "io.grpc:protoc-gen-grpc-java:$GRPC_VERSION"
234+
}
235+
}
236+
237+
val grpcKotlinPluginExisted = findByName(GrpcExtension.GRPC_KOTLIN_LOCATOR_NAME) != null
238+
maybeCreate(GrpcExtension.GRPC_KOTLIN_LOCATOR_NAME).apply {
239+
if (!grpcKotlinPluginExisted) {
240+
artifact = "io.grpc:protoc-gen-grpc-kotlin:$GRPC_KOTLIN_VERSION:jdk8@jar"
241+
}
242+
}
243+
}
244+
245+
generateProtoTasks {
246+
all().all {
247+
plugins {
248+
val existed = findByName(GrpcExtension.LOCATOR_NAME) != null
249+
maybeCreate(GrpcExtension.LOCATOR_NAME).apply {
250+
if (!existed) {
251+
option("debugOutput=$buildDirPath/protobuf-plugin.log")
252+
option("messageMode=interface")
253+
}
254+
}
255+
256+
maybeCreate(GrpcExtension.GRPC_JAVA_LOCATOR_NAME)
257+
258+
maybeCreate(GrpcExtension.GRPC_KOTLIN_LOCATOR_NAME)
259+
}
260+
}
261+
}
262+
}

gradle-plugin/src/main/kotlin/kotlinx/rpc/KotlinCompilerPluginBuilder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.rpc

gradle-plugin/src/main/kotlin/kotlinx/rpc/RpcDangerousApi.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.rpc

gradle-plugin/src/main/kotlin/kotlinx/rpc/RpcGradlePlugin.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.rpc
@@ -14,6 +14,8 @@ public class RpcGradlePlugin : Plugin<Project> {
1414
target.extensions.create<RpcExtension>("rpc")
1515

1616
applyCompilerPlugin(target)
17+
18+
target.configureGrpc()
1719
}
1820

1921
private fun applyCompilerPlugin(target: Project) {

gradle-plugin/src/main/kotlin/kotlinx/rpc/RpcPluginConst.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

55
package kotlinx.rpc

0 commit comments

Comments
 (0)