Skip to content

Commit 6bee142

Browse files
authored
dataconnect: add ktfmt support to gradle plugin (#6439)
1 parent 9754546 commit 6bee142

File tree

7 files changed

+165
-2
lines changed

7 files changed

+165
-2
lines changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ abstract class DataConnectDslExtension @Inject constructor(objectFactory: Object
6363
@Suppress("unused")
6464
fun emulator(block: DataConnectEmulatorDslExtension.() -> Unit): Unit = block(emulator)
6565

66+
/**
67+
* Values to use when running ktfmt to format the code generated by the Data Connect toolkit,
68+
* which override the values from those defined in the outer scope.
69+
*/
70+
val ktfmt: DataConnectKtfmtDslExtension =
71+
objectFactory.newInstance<DataConnectKtfmtDslExtension>()
72+
73+
/**
74+
* Configure values to use when running ktfmt to format the code generated by the Data Connect
75+
* toolkit, which override the values from those defined in the outer scope.
76+
*/
77+
@Suppress("unused") fun ktfmt(block: DataConnectKtfmtDslExtension.() -> Unit): Unit = block(ktfmt)
78+
6679
/**
6780
* Values to use when performing code generation, which override the values from those defined in
6881
* the outer scope.
@@ -85,6 +98,14 @@ abstract class DataConnectDslExtension @Inject constructor(objectFactory: Object
8598
abstract var schemaExtensionsOutputEnabled: Boolean?
8699
}
87100

101+
/**
102+
* Values to use when running ktfmt to format the code generated by the Data Connect toolkit,
103+
* which override the values from those defined in the outer scope.
104+
*/
105+
abstract class DataConnectKtfmtDslExtension {
106+
abstract var jarFile: File?
107+
}
108+
88109
interface DataConnectExecutableBuilder {
89110
var version: String?
90111
var file: File?

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

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package com.google.firebase.dataconnect.gradle.plugin
1717

1818
import java.io.File
1919
import org.gradle.api.DefaultTask
20+
import org.gradle.api.Task
2021
import org.gradle.api.file.DirectoryProperty
2122
import org.gradle.api.file.RegularFileProperty
2223
import org.gradle.api.provider.Property
@@ -40,19 +41,23 @@ abstract class DataConnectGenerateCodeTask : DefaultTask() {
4041

4142
@get:OutputDirectory abstract val outputDirectory: DirectoryProperty
4243

44+
@get:Optional @get:InputFile abstract val ktfmtJarFile: RegularFileProperty
45+
4346
@TaskAction
4447
fun run() {
4548
val dataConnectExecutable: File = dataConnectExecutable.get().asFile
4649
val configDirectory: File? = configDirectory.orNull?.asFile
4750
val connectors: Collection<String> = connectors.get().distinct().sorted()
4851
val buildDirectory: File = buildDirectory.get().asFile
4952
val outputDirectory: File = outputDirectory.get().asFile
53+
val ktfmtJarFile: File? = ktfmtJarFile.orNull?.asFile
5054

5155
logger.info("dataConnectExecutable={}", dataConnectExecutable.absolutePath)
5256
logger.info("configDirectory={}", configDirectory?.absolutePath)
5357
logger.info("connectors={}", connectors.joinToString(", "))
5458
logger.info("buildDirectory={}", buildDirectory.absolutePath)
5559
logger.info("outputDirectory={}", outputDirectory.absolutePath)
60+
logger.info("ktfmtJarFile={}", ktfmtJarFile?.absolutePath)
5661

5762
if (outputDirectory.exists()) {
5863
logger.info("Deleting directory: $outputDirectory")
@@ -71,9 +76,50 @@ abstract class DataConnectGenerateCodeTask : DefaultTask() {
7176
) {
7277
this.connectors = connectors
7378
this.outputDirectory = outputDirectory
74-
this.logFile = File(buildDirectory, "log.txt")
79+
this.logFile = File(buildDirectory, "codegen.log.txt")
80+
}
81+
82+
if (ktfmtJarFile !== null) {
83+
logger.info("Running ktfmt on generated code")
84+
runKtfmt(
85+
ktfmtJarFile = ktfmtJarFile,
86+
directory = outputDirectory,
87+
logFile = File(buildDirectory, "ktfmt.log.txt")
88+
)
7589
}
7690

7791
logger.info("Completed successfully")
7892
}
7993
}
94+
95+
private fun Task.runKtfmt(
96+
ktfmtJarFile: File,
97+
directory: File,
98+
logFile: File,
99+
) {
100+
project.mkdir(logFile.parentFile)
101+
val logFileStream = logFile.outputStream()
102+
103+
try {
104+
project.javaexec { execSpec ->
105+
execSpec.run {
106+
classpath(ktfmtJarFile)
107+
mainClass.set("com.facebook.ktfmt.cli.Main")
108+
args("--google-style")
109+
args(directory.absolutePath)
110+
isIgnoreExitValue = false
111+
standardOutput = logFileStream
112+
errorOutput = logFileStream
113+
}
114+
}
115+
} catch (e: Exception) {
116+
logFileStream.close()
117+
logFile.forEachLine { logger.error(it.trimEnd()) }
118+
throw e
119+
} finally {
120+
logFileStream.close()
121+
if (logger.isInfoEnabled) {
122+
logFile.forEachLine { logger.error(it.trimEnd()) }
123+
}
124+
}
125+
}

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
@@ -185,6 +185,7 @@ abstract class DataConnectGradlePlugin : Plugin<Project> {
185185
}
186186
connectors.set(dataConnectProviders.connectors)
187187
buildDirectory.set(baseBuildDirectory.map { it.dir("generateCode") })
188+
ktfmtJarFile.set(dataConnectProviders.ktfmtJarFile)
188189
}
189190

190191
variant.sources.java!!.addGeneratedSourceDirectory(

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package com.google.firebase.dataconnect.gradle.plugin
1717

1818
import java.util.Properties
1919
import org.gradle.api.Project
20+
import org.gradle.api.file.RegularFile
2021
import org.gradle.api.provider.Provider
2122

2223
class DataConnectLocalSettings(project: Project) {
@@ -68,12 +69,18 @@ class DataConnectLocalSettings(project: Project) {
6869
}
6970
}
7071

72+
val ktfmtJarFile: Provider<RegularFile> =
73+
project.providerForDataConnectLocalSetting(KEY_KTFMT_JAR_FILE) { settingValue, project ->
74+
project.layout.projectDirectory.file(settingValue)
75+
}
76+
7177
companion object {
7278
const val FILE_NAME = "dataconnect.local.properties"
7379
const val KEY_DATA_CONNECT_EXECUTABLE_FILE = "dataConnectExecutable.file"
7480
const val KEY_DATA_CONNECT_EXECUTABLE_VERSION = "dataConnectExecutable.version"
7581
const val KEY_POSTGRES_CONNECTION_URL = "emulator.postgresConnectionUrl"
7682
const val KEY_SCHEMA_EXTENSIONS_OUTPUT_ENABLED = "emulator.schemaExtensionsOutputEnabled"
83+
const val KEY_KTFMT_JAR_FILE = "ktfmt.jar.file"
7784

7885
fun Project.providerForDataConnectLocalSetting(settingName: String): Provider<String> =
7986
providerForDataConnectLocalSetting(settingName) { value, _ -> value }

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package com.google.firebase.dataconnect.gradle.plugin
1717

1818
import org.gradle.api.Project
1919
import org.gradle.api.file.Directory
20+
import org.gradle.api.file.RegularFile
2021
import org.gradle.api.provider.Provider
2122

2223
class DataConnectProviders(
@@ -120,6 +121,24 @@ class DataConnectProviders(
120121
.orElse(valueFromProject)
121122
}
122123

124+
val ktfmtJarFile: Provider<RegularFile> = run {
125+
val gradlePropertyName = "ktfmt.jar.file"
126+
val valueFromLocalSettings: Provider<RegularFile> = localSettings.ktfmtJarFile
127+
val valueFromGradleProperty: Provider<RegularFile> =
128+
project.providers.gradleProperty(gradlePropertyName).flatMap {
129+
project.layout.file(project.provider { project.file(it) })
130+
}
131+
val valueFromVariant: Provider<RegularFile> =
132+
project.layout.file(variantExtension.ktfmt.jarFile)
133+
val valueFromProject: Provider<RegularFile> =
134+
project.layout.file(project.provider { projectExtension.ktfmt.jarFile })
135+
136+
valueFromLocalSettings
137+
.orElse(valueFromGradleProperty)
138+
.orElse(valueFromVariant)
139+
.orElse(valueFromProject)
140+
}
141+
123142
val customConfigDir: Provider<Directory> = run {
124143
val valueFromVariant: Provider<Directory> = project.layout.dir(variantExtension.configDir)
125144
val valueFromProject: Provider<Directory> =

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ import com.android.build.api.variant.VariantExtension
2222
import com.android.build.api.variant.VariantExtensionConfig
2323
import com.google.firebase.dataconnect.gradle.plugin.DataConnectDslExtension.DataConnectCodegenDslExtension
2424
import com.google.firebase.dataconnect.gradle.plugin.DataConnectDslExtension.DataConnectEmulatorDslExtension
25+
import com.google.firebase.dataconnect.gradle.plugin.DataConnectDslExtension.DataConnectKtfmtDslExtension
2526
import java.io.File
2627
import javax.inject.Inject
2728
import org.gradle.api.model.ObjectFactory
2829
import org.gradle.api.provider.Property
29-
import org.gradle.kotlin.dsl.*
30+
import org.gradle.kotlin.dsl.newInstance
3031

3132
/**
3233
* This is the extension type for extending [com.android.build.api.variant.Variant].
@@ -104,6 +105,14 @@ abstract class DataConnectVariantDslExtension(
104105
productFlavorExtensions.map { it.emulator },
105106
)
106107

108+
/** @see DataConnectDslExtension.ktfmt */
109+
val ktfmt: DataConnectKtfmtVariantDslExtension =
110+
objectFactory.newInstance(
111+
variant,
112+
buildTypeExtension.ktfmt,
113+
productFlavorExtensions.map { it.ktfmt },
114+
)
115+
107116
/** Values to use when performing code generation. */
108117
abstract class DataConnectCodegenVariantDslExtension
109118
@Inject
@@ -158,6 +167,27 @@ abstract class DataConnectVariantDslExtension(
158167
}
159168
}
160169

170+
/** Values to use formatting code with ktfmt. */
171+
abstract class DataConnectKtfmtVariantDslExtension
172+
@Inject
173+
constructor(
174+
variant: Variant,
175+
buildTypeExtension: DataConnectKtfmtDslExtension,
176+
productFlavorExtensions: List<DataConnectKtfmtDslExtension>,
177+
) {
178+
/** @see DataConnectKtfmtDslExtension.jarFile */
179+
abstract val jarFile: Property<File>
180+
init {
181+
jarFile.setFrom(
182+
variant,
183+
buildTypeExtension,
184+
productFlavorExtensions,
185+
"jarFile",
186+
DataConnectKtfmtDslExtension::jarFile
187+
)
188+
}
189+
}
190+
161191
private companion object {
162192

163193
fun <PropertyType : Any, ExtensionType : Any> Property<PropertyType>.setFrom(
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/bash
2+
3+
# Copyright 2024 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
set -euo pipefail
18+
19+
if [[ $# -gt 0 ]] ; then
20+
echo "ERROR: no command-line arguments are supported, but got $*" >&2
21+
exit 2
22+
fi
23+
24+
readonly PROJECT_ROOT_DIR="$(dirname "$0")/../.."
25+
26+
readonly TARGETS=(
27+
":firebase-dataconnect:connectors:generateDebugDataConnectSources"
28+
)
29+
30+
readonly args=(
31+
"${PROJECT_ROOT_DIR}/gradlew"
32+
"-p"
33+
"${PROJECT_ROOT_DIR}"
34+
"--configure-on-demand"
35+
"${TARGETS[@]}"
36+
)
37+
38+
echo "${args[*]}"
39+
exec "${args[@]}"

0 commit comments

Comments
 (0)