Skip to content

Commit bb5a4d4

Browse files
authored
dataconnect: improve gradle plugin errors when the version of the cli is not found (#6333)
1 parent 834f27f commit bb5a4d4

File tree

6 files changed

+75
-132
lines changed

6 files changed

+75
-132
lines changed

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

+3-51
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,6 @@ abstract class DataConnectDslExtension @Inject constructor(objectFactory: Object
8989
var version: String?
9090
var file: File?
9191
var regularFile: RegularFile?
92-
var fileSizeInBytes: Long?
93-
var sha512DigestHex: String?
94-
var verificationEnabled: Boolean
9592
}
9693

9794
private class DataConnectExecutableBuilderImpl(initialValues: DataConnectExecutable?) :
@@ -121,29 +118,16 @@ abstract class DataConnectDslExtension @Inject constructor(objectFactory: Object
121118
_regularFile = value
122119
}
123120

124-
override var fileSizeInBytes: Long? = null
125-
override var sha512DigestHex: String? = null
126-
override var verificationEnabled: Boolean = true
127-
128121
fun updateFrom(info: DataConnectExecutable.File) {
129122
file = info.file
130-
updateFrom(info.verificationInfo)
131123
}
132124

133125
fun updateFrom(info: DataConnectExecutable.RegularFile) {
134126
regularFile = info.file
135-
updateFrom(info.verificationInfo)
136127
}
137128

138129
fun updateFrom(info: DataConnectExecutable.Version) {
139130
version = info.version
140-
updateFrom(info.verificationInfo)
141-
}
142-
143-
fun updateFrom(info: DataConnectExecutable.VerificationInfo?) {
144-
verificationEnabled = info !== null
145-
fileSizeInBytes = info?.fileSizeInBytes
146-
sha512DigestHex = info?.sha512DigestHex
147131
}
148132

149133
init {
@@ -159,9 +143,6 @@ abstract class DataConnectDslExtension @Inject constructor(objectFactory: Object
159143
val version = version
160144
val file = file
161145
val regularFile = regularFile
162-
val fileSizeInBytes = fileSizeInBytes
163-
val sha512DigestHex = sha512DigestHex
164-
val verificationEnabled = verificationEnabled
165146

166147
if (version === null && file === null && regularFile === null) {
167148
return null
@@ -195,41 +176,12 @@ abstract class DataConnectDslExtension @Inject constructor(objectFactory: Object
195176
)
196177
}
197178

198-
val verificationInfo: DataConnectExecutable.VerificationInfo? =
199-
if (!verificationEnabled) {
200-
null
201-
} else if (fileSizeInBytes === null && sha512DigestHex === null) {
202-
if (version !== null) {
203-
DataConnectExecutable.VerificationInfo.forVersion(version)
204-
} else {
205-
throw DataConnectGradleException(
206-
"8s9venv4ch",
207-
"Both 'fileSizeInBytes' and 'sha512DigestHex' were null" +
208-
" but _both_ must be set when verificationEnabled==true" +
209-
" and file!=null or regularFile!=null" +
210-
" (file=$file regularFile=$regularFile)"
211-
)
212-
}
213-
} else if (fileSizeInBytes === null || sha512DigestHex === null) {
214-
throw DataConnectGradleException(
215-
"gjzykv9pqq",
216-
"Both 'fileSizeInBytes' and 'sha512DigestHex' have to be set or both unset" +
217-
" when verificationEnabled==true, but one of them was set and the other was not" +
218-
" (fileSizeInBytes=$fileSizeInBytes, sha512DigestHex=$sha512DigestHex)"
219-
)
220-
} else {
221-
DataConnectExecutable.VerificationInfo(
222-
fileSizeInBytes = fileSizeInBytes,
223-
sha512DigestHex = sha512DigestHex,
224-
)
225-
}
226-
227179
return if (version !== null) {
228-
DataConnectExecutable.Version(version = version, verificationInfo = verificationInfo)
180+
DataConnectExecutable.Version(version = version)
229181
} else if (file !== null) {
230-
DataConnectExecutable.File(file = file, verificationInfo = verificationInfo)
182+
DataConnectExecutable.File(file = file)
231183
} else if (regularFile !== null) {
232-
DataConnectExecutable.RegularFile(file = regularFile, verificationInfo = verificationInfo)
184+
DataConnectExecutable.RegularFile(file = regularFile)
233185
} else {
234186
throw DataConnectGradleException(
235187
"yg49q5nzxt",

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

+6-44
Original file line numberDiff line numberDiff line change
@@ -16,65 +16,27 @@
1616
package com.google.firebase.dataconnect.gradle.plugin
1717

1818
import java.io.InputStream
19-
import java.io.Serializable
2019
import kotlinx.serialization.ExperimentalSerializationApi
2120
import kotlinx.serialization.json.Json
2221
import kotlinx.serialization.json.decodeFromStream
2322

24-
// The following command was used to generate the `serialVersionUID` constants for each class.
25-
// serialver -classpath \
26-
// plugin/build/classes/kotlin/main:$(find $HOME/.gradle/wrapper/dists -name
27-
// gradle-core-api-8.5.jar -printf '%p:') \
28-
// com.google.firebase.dataconnect.gradle.plugin.DataConnectExecutableInput\${VerificationInfo,File,RegularFile,Version}
29-
3023
sealed interface DataConnectExecutable {
3124

32-
data class VerificationInfo(val fileSizeInBytes: Long, val sha512DigestHex: String) :
33-
Serializable {
34-
35-
companion object {
36-
fun forVersion(version: String): VerificationInfo {
37-
val versions = VersionsJson.load().versions
38-
val versionInfo =
39-
versions[version]
40-
?: throw DataConnectGradleException(
41-
"3svd27ch8y",
42-
"File size and SHA512 digest is not known for version: $version"
43-
)
44-
return VerificationInfo(versionInfo.size, versionInfo.sha512DigestHex)
45-
}
46-
}
47-
}
25+
data class File(val file: java.io.File) : DataConnectExecutable
4826

49-
data class File(val file: java.io.File, val verificationInfo: VerificationInfo?) :
50-
DataConnectExecutable
27+
data class RegularFile(val file: org.gradle.api.file.RegularFile) : DataConnectExecutable
5128

52-
data class RegularFile(
53-
val file: org.gradle.api.file.RegularFile,
54-
val verificationInfo: VerificationInfo?
55-
) : DataConnectExecutable
56-
57-
data class Version(val version: String, val verificationInfo: VerificationInfo?) :
58-
DataConnectExecutable {
29+
data class Version(val version: String) : DataConnectExecutable {
5930
companion object {
60-
61-
private val defaultVersion: String
62-
get() = VersionsJson.load().default
63-
64-
fun forVersionWithDefaultVerificationInfo(version: String): Version {
65-
val verificationInfo = DataConnectExecutable.VerificationInfo.forVersion(version)
66-
return Version(version, verificationInfo)
67-
}
68-
69-
fun forDefaultVersionWithDefaultVerificationInfo(): Version =
70-
forVersionWithDefaultVerificationInfo(defaultVersion)
31+
val default: Version
32+
get() = Version(VersionsJson.load().default)
7133
}
7234
}
7335

7436
@OptIn(ExperimentalSerializationApi::class)
7537
object VersionsJson {
7638

77-
private const val RESOURCE_PATH =
39+
const val RESOURCE_PATH =
7840
"com/google/firebase/dataconnect/gradle/plugin/DataConnectExecutableVersions.json"
7941

8042
fun load(): Root = openFile().use { Json.decodeFromStream<Root>(it) }

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

+61-21
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package com.google.firebase.dataconnect.gradle.plugin
1717

18-
import com.google.firebase.dataconnect.gradle.plugin.DataConnectExecutable.VerificationInfo
1918
import java.io.File
2019
import java.net.HttpURLConnection
2120
import java.net.URL
@@ -24,6 +23,8 @@ import java.util.regex.Pattern
2423
import kotlin.time.Duration.Companion.seconds
2524
import kotlin.time.DurationUnit
2625
import kotlin.time.toDuration
26+
import kotlinx.serialization.encodeToString
27+
import kotlinx.serialization.json.Json
2728
import org.gradle.api.DefaultTask
2829
import org.gradle.api.file.DirectoryProperty
2930
import org.gradle.api.file.RegularFileProperty
@@ -41,8 +42,6 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
4142

4243
@get:Input @get:Optional abstract val version: Property<String>
4344

44-
@get:Input @get:Optional abstract val verificationInfo: Property<VerificationInfo>
45-
4645
@get:Internal abstract val buildDirectory: DirectoryProperty
4746

4847
@get:OutputFile abstract val outputFile: RegularFileProperty
@@ -51,13 +50,11 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
5150
fun run() {
5251
val inputFile: File? = inputFile.orNull?.asFile
5352
val version: String? = version.orNull
54-
val verificationInfo: VerificationInfo? = verificationInfo.orNull
5553
val buildDirectory: File = buildDirectory.get().asFile
5654
val outputFile: File = outputFile.get().asFile
5755

5856
logger.info("inputFile: {}", inputFile)
5957
logger.info("version: {}", version)
60-
logger.info("verificationInfo: {}", verificationInfo)
6158
logger.info("buildDirectory: {}", buildDirectory)
6259
logger.info("outputFile: {}", outputFile)
6360

@@ -75,37 +72,76 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
7572
runWithFile(inputFile = inputFile, outputFile = outputFile)
7673
} else if (version !== null) {
7774
runWithVersion(version = version, outputFile = outputFile)
75+
verifyOutputFile(outputFile, version)
7876
} else {
7977
throw DataConnectGradleException(
8078
"chc94cq7vx",
8179
"Neither 'inputFile' nor 'version' were specified," +
8280
" but exactly _one_ of them is required to be specified"
8381
)
8482
}
85-
86-
if (verificationInfo !== null) {
87-
verifyOutputFile(outputFile, verificationInfo)
88-
}
8983
}
9084

91-
private fun verifyOutputFile(outputFile: File, verificationInfo: VerificationInfo) {
85+
private fun verifyOutputFile(outputFile: File, version: String) {
9286
logger.info("Verifying file size and SHA512 digest of file: {}", outputFile)
9387
val fileInfo = FileInfo.forFile(outputFile)
94-
if (fileInfo.sizeInBytes != verificationInfo.fileSizeInBytes) {
95-
throw DataConnectGradleException(
96-
"zjdpbsjv42",
97-
"File $outputFile has an unexpected size (in bytes): actual=" +
88+
89+
val verificationInfoJsonString =
90+
jsonPrettyPrint.encodeToString(
91+
DataConnectExecutable.VersionsJson.VerificationInfo(
92+
size = fileInfo.sizeInBytes,
93+
sha512DigestHex = fileInfo.sha512DigestHex,
94+
)
95+
)
96+
97+
val verificationInfoByVersion = DataConnectExecutable.VersionsJson.load().versions
98+
val verificationInfo = verificationInfoByVersion[version]
99+
if (verificationInfo === null) {
100+
val message =
101+
"verification information for ${outputFile.absolutePath}" +
102+
" (version $version) is not known; known versions are: " +
103+
verificationInfoByVersion.keys.sorted().joinToString(", ")
104+
logger.error("ERROR: $message")
105+
logger.error(
106+
"To update ${DataConnectExecutable.VersionsJson.RESOURCE_PATH} with" +
107+
" information about this version, add this JSON blob: $verificationInfoJsonString"
108+
)
109+
throw DataConnectGradleException("ym8assbfgw", message)
110+
}
111+
112+
val verificationErrors = mutableListOf<String>()
113+
if (fileInfo.sizeInBytes != verificationInfo.size) {
114+
logger.error(
115+
"ERROR: File ${outputFile.absolutePath} has an unexpected size (in bytes): actual is " +
98116
fileInfo.sizeInBytes.toStringWithThousandsSeparator() +
99-
" expected=" +
100-
verificationInfo.fileSizeInBytes.toStringWithThousandsSeparator()
117+
" but expected " +
118+
verificationInfo.size.toStringWithThousandsSeparator()
101119
)
102-
} else if (fileInfo.sha512DigestHex != verificationInfo.sha512DigestHex) {
103-
throw DataConnectGradleException(
104-
"3yyma4dqga",
105-
"File $outputFile has an unexpected SHA512 digest:" +
106-
" actual=${fileInfo.sha512DigestHex} expected=${verificationInfo.sha512DigestHex}"
120+
verificationErrors.add("file size mismatch")
121+
}
122+
if (fileInfo.sha512DigestHex != verificationInfo.sha512DigestHex) {
123+
logger.error(
124+
"ERROR: File ${outputFile.absolutePath} has an unexpected SHA512 digest:" +
125+
" actual is ${fileInfo.sha512DigestHex}" +
126+
" but expected ${verificationInfo.sha512DigestHex}"
107127
)
128+
verificationErrors.add("SHA512 digest mismatch")
129+
}
130+
131+
if (verificationErrors.isEmpty()) {
132+
logger.info("Verifying file size and SHA512 digest succeeded")
133+
return
108134
}
135+
136+
logger.error(
137+
"To update ${DataConnectExecutable.VersionsJson.RESOURCE_PATH} with" +
138+
" information about this version, add this JSON blob: $verificationInfoJsonString"
139+
)
140+
141+
throw DataConnectGradleException(
142+
"x9dfwhjr9c",
143+
"Verification of ${outputFile.absolutePath} failed: ${verificationErrors.joinToString(", ")}"
144+
)
109145
}
110146

111147
data class FileInfo(val sizeInBytes: Long, val sha512DigestHex: String) {
@@ -199,4 +235,8 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
199235
}
200236
}
201237
}
238+
239+
private companion object {
240+
val jsonPrettyPrint = Json { prettyPrint = true }
241+
}
202242
}

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

-11
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,6 @@ abstract class DataConnectGradlePlugin : Plugin<Project> {
110110
}
111111
)
112112
)
113-
verificationInfo.set(
114-
dataConnectExecutable.map(
115-
TransformerInterop {
116-
when (it) {
117-
is DataConnectExecutable.File -> it.verificationInfo
118-
is DataConnectExecutable.RegularFile -> it.verificationInfo
119-
is DataConnectExecutable.Version -> it.verificationInfo
120-
}
121-
}
122-
)
123-
)
124113
outputFile.set(
125114
dataConnectExecutable.map {
126115
when (it) {

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ class DataConnectLocalSettings(project: Project) {
2929
) { settingName, settingValue, project ->
3030
if (settingName == KEY_DATA_CONNECT_EXECUTABLE_FILE) {
3131
val regularFile = project.layout.projectDirectory.file(settingValue)
32-
DataConnectExecutable.RegularFile(regularFile, verificationInfo = null)
32+
DataConnectExecutable.RegularFile(regularFile)
3333
} else if (settingName == KEY_DATA_CONNECT_EXECUTABLE_VERSION) {
34-
DataConnectExecutable.Version.forVersionWithDefaultVerificationInfo(settingValue)
34+
DataConnectExecutable.Version(settingValue)
3535
} else {
3636
throw IllegalStateException(
3737
"fileValue==null && versionValue==null (error code rbhmsd524t)"

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ class DataConnectProviders(
3535
val fileValueFromGradleProperty: Provider<DataConnectExecutable> =
3636
project.providers.gradleProperty(fileGradlePropertyName).map {
3737
val regularFile = project.layout.projectDirectory.file(it)
38-
DataConnectExecutable.RegularFile(regularFile, verificationInfo = null)
38+
DataConnectExecutable.RegularFile(regularFile)
3939
}
4040
val versionValueFromGradleProperty: Provider<DataConnectExecutable> =
4141
project.providers.gradleProperty(versionGradlePropertyName).map {
42-
DataConnectExecutable.Version.forVersionWithDefaultVerificationInfo(it)
42+
DataConnectExecutable.Version(it)
4343
}
4444
val valueFromVariant: Provider<DataConnectExecutable> = variantExtension.dataConnectExecutable
4545
val valueFromProject: Provider<DataConnectExecutable> =
@@ -50,7 +50,7 @@ class DataConnectProviders(
5050
.orElse(versionValueFromGradleProperty)
5151
.orElse(valueFromVariant)
5252
.orElse(valueFromProject)
53-
.orElse(DataConnectExecutable.Version.forDefaultVersionWithDefaultVerificationInfo())
53+
.orElse(DataConnectExecutable.Version.default)
5454
}
5555

5656
val postgresConnectionUrl: Provider<String> = run {

0 commit comments

Comments
 (0)