Skip to content

Commit e296249

Browse files
authored
dataconnect: gradle plugin support for 'sdk generate' added (#7266)
1 parent 11f1259 commit e296249

File tree

3 files changed

+126
-4
lines changed

3 files changed

+126
-4
lines changed

firebase-dataconnect/gradleplugin/plugin/src/main/kotlin/com/google/firebase/dataconnect/gradle/plugin/DataConnectExecutableLauncher.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ import org.gradle.api.Task
2121
interface DataConnectExecutableConfig {
2222
var outputDirectory: File?
2323
var connectors: Collection<String>
24+
var connectorId: Collection<String>
2425
var listen: String?
2526
var localConnectionString: String?
2627
var logFile: File?
2728
var schemaExtensionsOutputEnabled: Boolean?
29+
var platform: String?
2830
}
2931

3032
fun Task.runDataConnectExecutable(
@@ -37,10 +39,12 @@ fun Task.runDataConnectExecutable(
3739
object : DataConnectExecutableConfig {
3840
override var outputDirectory: File? = null
3941
override var connectors: Collection<String> = emptyList()
42+
override var connectorId: Collection<String> = emptyList()
4043
override var listen: String? = null
4144
override var localConnectionString: String? = null
4245
override var logFile: File? = null
4346
override var schemaExtensionsOutputEnabled: Boolean? = null
47+
override var platform: String? = null
4448
}
4549
.apply(configure)
4650

@@ -76,7 +80,13 @@ fun Task.runDataConnectExecutable(
7680
args("-connectors=${it.joinToString(",")}")
7781
}
7882
}
83+
config.connectorId.let {
84+
if (it.isNotEmpty()) {
85+
args("-connector_id=${it.joinToString(",")}")
86+
}
87+
}
7988
config.listen?.let { args("-listen=${it}") }
89+
config.platform?.let { args("-platform=${it}") }
8090
config.localConnectionString?.let { args("-local_connection_string=${it}") }
8191
config.schemaExtensionsOutputEnabled?.let { args("-enable_output_schema_extensions=${it}") }
8292
}

firebase-dataconnect/gradleplugin/plugin/src/main/kotlin/com/google/firebase/dataconnect/gradle/plugin/DataConnectGenerateCodeTask.kt

Lines changed: 115 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,30 @@
1515
*/
1616
package com.google.firebase.dataconnect.gradle.plugin
1717

18+
import com.google.firebase.dataconnect.gradle.plugin.DataConnectGenerateCodeTask.CallingConvention
1819
import java.io.File
20+
import javax.inject.Inject
1921
import org.gradle.api.DefaultTask
20-
import org.gradle.api.Task
2122
import org.gradle.api.file.DirectoryProperty
2223
import org.gradle.api.file.RegularFileProperty
2324
import org.gradle.api.provider.Property
25+
import org.gradle.api.provider.Provider
2426
import org.gradle.api.tasks.Input
2527
import org.gradle.api.tasks.InputFile
2628
import org.gradle.api.tasks.InputFiles
2729
import org.gradle.api.tasks.Internal
2830
import org.gradle.api.tasks.Optional
2931
import org.gradle.api.tasks.OutputDirectory
3032
import org.gradle.api.tasks.TaskAction
33+
import org.gradle.process.ExecOperations
34+
import org.slf4j.Logger
3135

3236
abstract class DataConnectGenerateCodeTask : DefaultTask() {
3337

3438
@get:InputFile abstract val dataConnectExecutable: RegularFileProperty
3539

40+
@get:Input abstract val dataConnectExecutableCallingConvention: Property<CallingConvention>
41+
3642
@get:Optional @get:InputFiles abstract val configDirectory: DirectoryProperty
3743

3844
@get:Input abstract val connectors: Property<Collection<String>>
@@ -43,16 +49,32 @@ abstract class DataConnectGenerateCodeTask : DefaultTask() {
4349

4450
@get:Optional @get:InputFile abstract val ktfmtJarFile: RegularFileProperty
4551

52+
@get:Inject abstract val execOperations: ExecOperations
53+
54+
/**
55+
* The subcommand of the Data Connect executable to use to perform code generation.
56+
*
57+
* In August 2025 the subcommand was changed by cl/795582011 from "gradle generate" to "sdk
58+
* generate -platform=kotlin". The "gradle generate" command was last supported in version 2.11.0
59+
* of the Data Connect executable.
60+
*/
61+
enum class CallingConvention {
62+
GRADLE,
63+
SDK_GENERATE,
64+
}
65+
4666
@TaskAction
4767
fun run() {
4868
val dataConnectExecutable: File = dataConnectExecutable.get().asFile
69+
val dataConnectExecutableCallingConvention = dataConnectExecutableCallingConvention.get()
4970
val configDirectory: File? = configDirectory.orNull?.asFile
5071
val connectors: Collection<String> = connectors.get().distinct().sorted()
5172
val buildDirectory: File = buildDirectory.get().asFile
5273
val outputDirectory: File = outputDirectory.get().asFile
5374
val ktfmtJarFile: File? = ktfmtJarFile.orNull?.asFile
5475

5576
logger.info("dataConnectExecutable={}", dataConnectExecutable.absolutePath)
77+
logger.info("dataConnectExecutableCallingConvention={}", dataConnectExecutableCallingConvention)
5678
logger.info("configDirectory={}", configDirectory?.absolutePath)
5779
logger.info("connectors={}", connectors.joinToString(", "))
5880
logger.info("buildDirectory={}", buildDirectory.absolutePath)
@@ -69,14 +91,26 @@ abstract class DataConnectGenerateCodeTask : DefaultTask() {
6991
return
7092
}
7193

94+
val subCommand =
95+
when (dataConnectExecutableCallingConvention) {
96+
CallingConvention.GRADLE -> listOf("gradle", "generate")
97+
CallingConvention.SDK_GENERATE -> listOf("sdk", "generate")
98+
}
99+
72100
runDataConnectExecutable(
73101
dataConnectExecutable = dataConnectExecutable,
74-
subCommand = listOf("gradle", "generate"),
102+
subCommand = subCommand,
75103
configDirectory = configDirectory,
76104
) {
77-
this.connectors = connectors
105+
when (dataConnectExecutableCallingConvention) {
106+
CallingConvention.GRADLE -> this.connectors = connectors
107+
CallingConvention.SDK_GENERATE -> this.connectorId = connectors
108+
}
78109
this.outputDirectory = outputDirectory
79110
this.logFile = File(buildDirectory, "codegen.log.txt")
111+
if (dataConnectExecutableCallingConvention == CallingConvention.SDK_GENERATE) {
112+
this.platform = "kotlin"
113+
}
80114
}
81115

82116
if (ktfmtJarFile !== null) {
@@ -92,7 +126,7 @@ abstract class DataConnectGenerateCodeTask : DefaultTask() {
92126
}
93127
}
94128

95-
private fun Task.runKtfmt(
129+
private fun DataConnectGenerateCodeTask.runKtfmt(
96130
ktfmtJarFile: File,
97131
directory: File,
98132
logFile: File,
@@ -123,3 +157,80 @@ private fun Task.runKtfmt(
123157
}
124158
}
125159
}
160+
161+
fun DataConnectGenerateCodeTask.detectedCallingConvention(
162+
dataConnectExecutable: RegularFileProperty = this.dataConnectExecutable,
163+
buildDirectory: DirectoryProperty = this.buildDirectory,
164+
execOperations: ExecOperations = this.execOperations,
165+
logger: Logger = this.logger
166+
): Provider<CallingConvention> =
167+
dataConnectExecutable.map {
168+
determineCallingConvention(
169+
dataConnectExecutable = it.asFile,
170+
workDirectory = File(buildDirectory.get().asFile, "determineCallingConvention"),
171+
execOperations = execOperations,
172+
logger = logger,
173+
)
174+
}
175+
176+
private fun determineCallingConvention(
177+
dataConnectExecutable: File,
178+
workDirectory: File,
179+
execOperations: ExecOperations,
180+
logger: Logger,
181+
): CallingConvention {
182+
logger.info(
183+
"Determining calling convention of Data Connect executable: {}",
184+
dataConnectExecutable.absolutePath
185+
)
186+
187+
val callingConventionResults =
188+
CallingConvention.entries.map { callingConvention ->
189+
val logFile =
190+
File(workDirectory, "$callingConvention.log.txt").also { it.parentFile.mkdirs() }
191+
logger.info(
192+
"Testing {} for support of calling convention {} (log file: {})",
193+
dataConnectExecutable.absolutePath,
194+
callingConvention,
195+
logFile.absolutePath
196+
)
197+
198+
val exitCode: Int =
199+
logFile.outputStream().use { logFileStream ->
200+
execOperations
201+
.exec { execSpec ->
202+
execSpec.run {
203+
executable(dataConnectExecutable)
204+
isIgnoreExitValue = true
205+
standardOutput = logFileStream
206+
errorOutput = logFileStream
207+
when (callingConvention) {
208+
CallingConvention.GRADLE -> args("gradle", "help", "generate")
209+
CallingConvention.SDK_GENERATE -> args("sdk", "help", "generate")
210+
}
211+
}
212+
}
213+
.exitValue
214+
}
215+
216+
val callingConventionSupported = exitCode == 0
217+
logger.info(
218+
"Testing {} for support of calling convention {} completed: {} (exitCode={})",
219+
dataConnectExecutable.absolutePath,
220+
callingConvention,
221+
callingConventionSupported,
222+
exitCode
223+
)
224+
Pair(callingConvention, callingConventionSupported)
225+
}
226+
227+
val supportedCallingConventions: List<CallingConvention> =
228+
callingConventionResults.filter { it.second }.map { it.first }
229+
return supportedCallingConventions.singleOrNull()
230+
?: throw DataConnectGradleException(
231+
"d24j9dm3r6",
232+
"could not detect calling convention of Data Connect executable ${dataConnectExecutable.absolutePath}: " +
233+
"found ${supportedCallingConventions.size} supported calling conventions, but expected exactly 1: " +
234+
supportedCallingConventions.joinToString(", ")
235+
)
236+
}

firebase-dataconnect/gradleplugin/plugin/src/main/kotlin/com/google/firebase/dataconnect/gradle/plugin/DataConnectGradlePlugin.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ abstract class DataConnectGradlePlugin : Plugin<Project> {
186186
connectors.set(dataConnectProviders.connectors)
187187
buildDirectory.set(baseBuildDirectory.map { it.dir("generateCode") })
188188
ktfmtJarFile.set(dataConnectProviders.ktfmtJarFile)
189+
dataConnectExecutableCallingConvention.set(detectedCallingConvention())
189190
}
190191

191192
variant.sources.java!!.addGeneratedSourceDirectory(

0 commit comments

Comments
 (0)