Skip to content

Commit bc4234b

Browse files
committed
Added support for Android (not KMP) projects KRPC-203
1 parent 070c8c3 commit bc4234b

File tree

14 files changed

+610
-259
lines changed

14 files changed

+610
-259
lines changed

gradle-plugin/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ tasks.withType<KotlinCompile>().configureEach {
3131
dependencies {
3232
compileOnly(libs.kotlin.gradle.plugin)
3333
compileOnly(libs.android.gradle.plugin)
34+
compileOnly(libs.android.gradle.plugin.api)
3435

3536
testImplementation(libs.kotlin.gradle.plugin)
3637
testImplementation(gradleTestKit())

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,13 @@ public open class RpcExtension @Inject internal constructor(objects: ObjectFacto
8383
internal val protocApplied = AtomicBoolean(false)
8484

8585
internal val protocInternal by lazy {
86-
if (protocApplied.get()) {
86+
if (protocApplied.compareAndSet(false, true)) {
87+
objects.newInstance<DefaultProtocExtension>().apply {
88+
callbacks.forEach { it.execute(this) }
89+
}
90+
} else {
8791
error("Illegal access to protoc extension during DefaultProtocExtension.init")
8892
}
89-
90-
protocApplied.set(true)
91-
objects.newInstance<DefaultProtocExtension>().apply {
92-
callbacks.forEach { it.execute(this) }
93-
}
9493
}
9594

9695
private val callbacks = mutableListOf<Action<ProtocExtension>>()

gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufExecTask.kt

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package kotlinx.rpc.buf.tasks
66

7+
import com.android.build.api.variant.Variant
78
import kotlinx.rpc.buf.BUF_EXECUTABLE_CONFIGURATION
89
import kotlinx.rpc.buf.BufExtension
910
import kotlinx.rpc.buf.execBuf
@@ -29,20 +30,31 @@ import kotlinx.rpc.buf.BufTasksExtension
2930
import org.gradle.api.logging.LogLevel
3031
import org.gradle.api.provider.SetProperty
3132
import org.gradle.api.tasks.Classpath
33+
import org.gradle.api.tasks.InputFiles
3234
import org.gradle.api.tasks.Internal
35+
import org.gradle.api.tasks.SkipWhenEmpty
3336
import javax.inject.Inject
3437

3538
/**
3639
* Abstract base class for `buf` tasks.
3740
*/
3841
public abstract class BufExecTask @Inject constructor(
3942
@Internal
40-
public val properties: Properties
43+
public val properties: Properties,
4144
) : DefaultTask() {
4245
init {
4346
group = PROTO_GROUP
4447
}
4548

49+
// unsued, but required for Gradle to properly recognise inputs
50+
@get:InputFiles
51+
@get:SkipWhenEmpty
52+
internal abstract val protoFiles: ListProperty<File>
53+
54+
// unsued, but required for Gradle to properly recognise inputs
55+
@get:InputFiles
56+
internal abstract val importProtoFiles: ListProperty<File>
57+
4658
// list of buf task dependencies of the same type
4759
@get:Internal
4860
internal abstract val bufTaskDependencies: SetProperty<String>
@@ -78,17 +90,33 @@ public abstract class BufExecTask @Inject constructor(
7890
isTest: Boolean,
7991
sourceSetName: String,
8092
/**
81-
* Name of the android flavor this task is associated with.
93+
* Name of the android flavors this task is associated with.
94+
*
95+
* @see [Variant.productFlavors]
8296
*/
83-
public val flavor: String,
97+
public val flavors: List<String>,
8498
/**
8599
* Name of the android build type this task is associated with.
100+
*
101+
* @see Variant.buildType
86102
*/
87-
public val buildType: String,
103+
public val buildType: String?,
88104
/**
89105
* Name of the android variant this task is associated with.
106+
*
107+
* @see Variant.name
90108
*/
91109
public val variant: String,
110+
111+
/**
112+
* Whether the task is for instrumentation tests.
113+
*/
114+
public val isAndroidTest: Boolean,
115+
116+
/**
117+
* Whether the task is for unit tests.
118+
*/
119+
public val isUnitTest: Boolean,
92120
) : Properties(isTest, sourceSetName)
93121

94122
/**
@@ -164,8 +192,8 @@ internal fun <T : BufExecTask> Project.registerBufExecTask(
164192
configuration: T.() -> Unit = {},
165193
): TaskProvider<T> = tasks.register(name, clazz, properties).apply {
166194
configure {
167-
val executableConfiguration = configurations.getByName(BUF_EXECUTABLE_CONFIGURATION)
168-
bufExecutable.set(executableConfiguration.singleFile)
195+
val executableConfiguration = configurations.named(BUF_EXECUTABLE_CONFIGURATION)
196+
bufExecutable.set(project.provider { executableConfiguration.get().singleFile })
169197
this.workingDir.set(workingDir)
170198

171199
val buf = provider { rpcExtension().protoc.get().buf }

gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,15 @@ import org.gradle.api.tasks.OutputDirectory
1616
import org.gradle.api.tasks.TaskProvider
1717
import java.io.File
1818
import kotlinx.rpc.buf.BufGenerateExtension
19+
import kotlinx.rpc.protoc.DefaultProtoSourceSet
20+
import kotlinx.rpc.protoc.bufExecProperties
21+
import org.gradle.api.file.SourceDirectorySet
22+
import org.gradle.api.provider.Provider
1923
import org.gradle.api.tasks.InputDirectory
2024
import org.gradle.api.tasks.InputFiles
25+
import org.gradle.api.tasks.OutputDirectories
26+
import org.gradle.api.tasks.SkipWhenEmpty
27+
import org.gradle.kotlin.dsl.listProperty
2128
import javax.inject.Inject
2229

2330
/**
@@ -26,16 +33,12 @@ import javax.inject.Inject
2633
* @see <a href="https://buf.build/docs/reference/cli/buf/generate/">buf generate</a>
2734
*/
2835
public abstract class BufGenerateTask @Inject internal constructor(properties: Properties) : BufExecTask(properties) {
29-
// unsued, but required for Gradle to properly recognise inputs
30-
@get:InputDirectory
31-
internal abstract val protoFilesDir: Property<File>
32-
33-
// unsued, but required for Gradle to properly recognise inputs
34-
@get:InputDirectory
35-
internal abstract val importFilesDir: Property<File>
36+
// used to properly calculate output directories
37+
@get:Input
38+
internal abstract val pluginNames: ListProperty<String>
3639

3740
/**
38-
* List of files used during `buf generate` command execution.
41+
* List of executable files used during `buf generate` command execution.
3942
*
4043
* @see [ProtocPlugin.Artifact.Local.executableFiles]
4144
*/
@@ -82,11 +85,22 @@ public abstract class BufGenerateTask @Inject internal constructor(properties: P
8285
public abstract val additionalArgs: ListProperty<String>
8386

8487
/**
85-
* The directory to output generated files.
88+
* The directory to output generated files to, used as a `buf generate --output` argument,
89+
* not the directory for sources. For that see [outputSourceDirectories].
8690
*/
8791
@get:OutputDirectory
8892
public abstract val outputDirectory: Property<File>
8993

94+
private val outputSourceDirectoriesInternal: ListProperty<File> = project.objects.listProperty()
95+
96+
/**
97+
* Generated source directories by plugin name.
98+
*
99+
* Can be used in [SourceDirectorySet.srcDirs].
100+
*/
101+
@get:OutputDirectories
102+
public val outputSourceDirectories: Provider<List<File>> = outputSourceDirectoriesInternal
103+
90104
init {
91105
command.set("generate")
92106

@@ -110,6 +124,11 @@ public abstract class BufGenerateTask @Inject internal constructor(properties: P
110124
}
111125

112126
this.args.set(args)
127+
128+
outputSourceDirectoriesInternal.set(pluginNames.map { plugins ->
129+
val out = outputDirectory.get()
130+
plugins.map { out.resolve(it) }
131+
})
113132
}
114133

115134
internal companion object {
@@ -118,20 +137,16 @@ public abstract class BufGenerateTask @Inject internal constructor(properties: P
118137
}
119138

120139
internal fun Project.registerBufGenerateTask(
121-
sourceSetName: String,
140+
protoSourceSet: DefaultProtoSourceSet,
122141
workingDir: File,
123142
outputDirectory: File,
124-
protoFilesDir: File,
125-
importFilesDir: File,
143+
includedPlugins: Provider<Set<ProtocPlugin>>,
126144
configure: BufGenerateTask.() -> Unit = {},
127145
): TaskProvider<BufGenerateTask> {
128-
val capitalName = sourceSetName.replaceFirstChar { it.uppercase() }
146+
val capitalName = protoSourceSet.name.replaceFirstChar { it.uppercase() }
129147
val bufGenerateTaskName = "${BufGenerateTask.NAME_PREFIX}$capitalName"
130148

131-
val properties = BufExecTask.Properties(
132-
isTest = sourceSetName.lowercase().endsWith("test"),
133-
sourceSetName = sourceSetName,
134-
)
149+
val properties = protoSourceSet.bufExecProperties()
135150

136151
return registerBufExecTask<BufGenerateTask>(bufGenerateTaskName, provider { workingDir }, properties) {
137152
group = PROTO_GROUP
@@ -145,8 +160,7 @@ internal fun Project.registerBufGenerateTask(
145160

146161
this.outputDirectory.set(outputDirectory)
147162

148-
this.protoFilesDir.set(protoFilesDir)
149-
this.importFilesDir.set(importFilesDir)
163+
this.pluginNames.set(includedPlugins.map { it.map { plugin -> plugin.name } })
150164

151165
configure()
152166
}

gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufTasks.kt

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,35 @@ public sealed interface BufTasks<BufTask : BufExecTask> : TaskCollection<BufTask
333333
// android
334334

335335
/**
336-
* Filters tasks by where [BufExecTask.AndroidProperties.flavor] matches the given flavor.
336+
* Android only.
337+
*
338+
* Filters tasks by where [BufExecTask.AndroidProperties.isUnitTest] is `true`.
339+
*
340+
* ```kotlin
341+
* rpc.protoc {
342+
* buf.tasks.all().unitTestTasks()
343+
* }
344+
* ```
345+
*/
346+
public fun unitTestTasks(): BufTasks<BufTask>
347+
348+
/**
349+
* Android only.
350+
*
351+
* Filters tasks by where [BufExecTask.AndroidProperties.isAndroidTest] is `true`.
352+
*
353+
* ```kotlin
354+
* rpc.protoc {
355+
* buf.tasks.all().androidTestTasks()
356+
* }
357+
* ```
358+
*/
359+
public fun androidTestTasks(): BufTasks<BufTask>
360+
361+
/**
362+
* Android only.
363+
*
364+
* Filters tasks by where [BufExecTask.AndroidProperties.flavors] matches the given flavor.
337365
*
338366
* Only returns Android tasks.
339367
*
@@ -346,6 +374,8 @@ public sealed interface BufTasks<BufTask : BufExecTask> : TaskCollection<BufTask
346374
public fun matchingFlavor(flavor: String): BufTasks<BufTask>
347375

348376
/**
377+
* Android only.
378+
*
349379
* Filters tasks by where [BufExecTask.AndroidProperties.buildType] matches the given buildType.
350380
*
351381
* Only returns Android tasks.
@@ -356,9 +386,11 @@ public sealed interface BufTasks<BufTask : BufExecTask> : TaskCollection<BufTask
356386
* }
357387
* ```
358388
*/
359-
public fun matchingBuildType(buildType: String): BufTasks<BufTask>
389+
public fun matchingBuildType(buildType: String?): BufTasks<BufTask>
360390

361391
/**
392+
* Android only.
393+
*
362394
* Filters tasks by where [BufExecTask.AndroidProperties.variant] matches the given variant.
363395
*
364396
* Only returns Android tasks.
@@ -532,21 +564,53 @@ internal open class BufTasksImpl<BufTask : BufExecTask> internal constructor(
532564
return BufTasksImpl(project, collection.matching { !it.properties.isTest }, kClass)
533565
}
534566

567+
override fun unitTestTasks(): BufTasks<BufTask> {
568+
return BufTasksImpl(
569+
project = project,
570+
collection = collection.matching {
571+
val properties = it.properties as? BufExecTask.AndroidProperties
572+
?: return@matching false
573+
574+
properties.isUnitTest
575+
},
576+
kClass = kClass,
577+
)
578+
}
579+
580+
override fun androidTestTasks(): BufTasks<BufTask> {
581+
return BufTasksImpl(
582+
project = project,
583+
collection = collection.matching {
584+
val properties = it.properties as? BufExecTask.AndroidProperties
585+
?: return@matching false
586+
587+
properties.isAndroidTest
588+
},
589+
kClass = kClass,
590+
)
591+
}
592+
535593
override fun matchingFlavor(flavor: String): BufTasks<BufTask> {
536594
return BufTasksImpl(
537595
project = project,
538596
collection = collection.matching {
539-
(it.properties as? BufExecTask.AndroidProperties)?.flavor == flavor
597+
val properties = it.properties as? BufExecTask.AndroidProperties
598+
?: return@matching false
599+
600+
properties.flavors.contains(flavor)
540601
},
541602
kClass = kClass,
542603
)
543604
}
544605

545-
override fun matchingBuildType(buildType: String): BufTasks<BufTask> {
606+
override fun matchingBuildType(buildType: String?): BufTasks<BufTask> {
546607
return BufTasksImpl(
547608
project = project,
548609
collection = collection.matching {
549-
(it.properties as? BufExecTask.AndroidProperties)?.buildType == buildType
610+
val properties = it.properties as? BufExecTask.AndroidProperties
611+
?: return@matching false
612+
613+
properties.buildType == buildType
550614
},
551615
kClass = kClass,
552616
)
@@ -556,7 +620,10 @@ internal open class BufTasksImpl<BufTask : BufExecTask> internal constructor(
556620
return BufTasksImpl(
557621
project = project,
558622
collection = collection.matching {
559-
(it.properties as? BufExecTask.AndroidProperties)?.variant == variant
623+
val properties = it.properties as? BufExecTask.AndroidProperties
624+
?: return@matching false
625+
626+
properties.variant == variant
560627
},
561628
kClass = kClass,
562629
)

0 commit comments

Comments
 (0)