Skip to content

Commit f3d3439

Browse files
committed
UpdateDataConnectExecutableVersionsTask.kt: refactor for improved readability
1 parent 3a35cca commit f3d3439

File tree

1 file changed

+137
-120
lines changed

1 file changed

+137
-120
lines changed

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

Lines changed: 137 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
package com.google.firebase.dataconnect.gradle.plugin
1818

1919
import com.google.cloud.storage.Blob
20+
import com.google.cloud.storage.Bucket
21+
import com.google.cloud.storage.Storage
2022
import com.google.cloud.storage.Storage.BlobListOption
2123
import com.google.cloud.storage.StorageException
2224
import com.google.cloud.storage.StorageOptions
25+
import com.google.firebase.dataconnect.gradle.plugin.DataConnectExecutableVersionsRegistry.VersionInfo
2326
import com.google.firebase.dataconnect.gradle.plugin.DataConnectExecutableVersionsRegistry.serializedValue
2427
import io.github.z4kn4fein.semver.Version
2528
import io.github.z4kn4fein.semver.toVersion
@@ -67,21 +70,21 @@ abstract class UpdateDataConnectExecutableVersionsTask : DefaultTask() {
6770
registry.versions.size,
6871
jsonFile.absolutePath,
6972
registry.defaultVersion,
70-
registry.versions.sortedWith(versionInfoComparator).joinToString {
71-
"${it.version}-${it.os.serializedValue}"
72-
}
73+
registry.versions.sortedWith(versionInfoComparator).toLogString()
7374
)
7475

75-
val cloudStorageVersions = downloadVersionInfoFromCloudStorage()
76+
val cloudStorageVersions: Set<CloudStorageVersionInfo> =
77+
StorageOptions.getDefaultInstance()
78+
.service
79+
.getDataConnectExecutablesBucket()
80+
.list(BlobListOption.prefix("emulator/"))
81+
.iterateAll()
82+
.mapNotNull { it.toCloudStorageVersionInfoOrNull() }
83+
.toSet()
7684

77-
val unknownVersions =
78-
cloudStorageVersions
79-
.filterNotIn(registry)
80-
.sortedWith(
81-
compareBy<CloudStorageVersionInfo> { it.version }
82-
.thenByDescending { it.operatingSystem.serializedValue }
83-
)
84-
if (unknownVersions.isEmpty()) {
85+
val cloudStorageVersionsMissingFromRegistry: List<CloudStorageVersionInfo> =
86+
cloudStorageVersions.filterNotIn(registry).sortedWith(cloudStorageVersionInfoComparator)
87+
if (cloudStorageVersionsMissingFromRegistry.isEmpty()) {
8588
logger.lifecycle(
8689
"Not updating {} since it already contains all versions.",
8790
jsonFile.absolutePath
@@ -91,17 +94,20 @@ abstract class UpdateDataConnectExecutableVersionsTask : DefaultTask() {
9194

9295
logger.lifecycle(
9396
"Downloading details for {} versions missing from registry file: {}",
94-
unknownVersions.size,
95-
unknownVersions.joinToString { "${it.version}-${it.operatingSystem.serializedValue}" }
97+
cloudStorageVersionsMissingFromRegistry.size,
98+
cloudStorageVersionsMissingFromRegistry.toLogString()
9699
)
97-
val unknownVersionInfos = unknownVersions.map { it.toRegistryVersionInfo(workDirectory) }
98-
val updatedRegistry = registry.updatedWith(unknownVersionInfos)
100+
101+
val updatedRegistry =
102+
registry.updatedWith(
103+
cloudStorageVersionsMissingFromRegistry.map { it.toRegistryVersionInfo(workDirectory) }
104+
)
99105

100106
logger.lifecycle(
101107
"Updating {} with {} versions: {}",
102108
jsonFile.absolutePath,
103-
unknownVersions.size,
104-
unknownVersions.joinToString { "${it.version}-${it.operatingSystem.serializedValue}" }
109+
cloudStorageVersionsMissingFromRegistry.size,
110+
cloudStorageVersionsMissingFromRegistry.toLogString()
105111
)
106112

107113
if (updatedRegistry.defaultVersion == registry.defaultVersion) {
@@ -122,103 +128,104 @@ abstract class UpdateDataConnectExecutableVersionsTask : DefaultTask() {
122128
DataConnectExecutableVersionsRegistry.save(updatedRegistry, jsonFile)
123129
}
124130

125-
private fun downloadVersionInfoFromCloudStorage(): Set<CloudStorageVersionInfo> {
126-
val storage = StorageOptions.getDefaultInstance().service
131+
private data class CloudStorageVersionInfo(
132+
val version: Version,
133+
val operatingSystem: OperatingSystem,
134+
val blob: Blob,
135+
)
136+
137+
private fun Storage.getDataConnectExecutablesBucket(): Bucket {
127138
val bucketName = "firemat-preview-drop"
128139
logger.lifecycle("Finding all Data Connect executable versions in GCS bucket: {}", bucketName)
129-
val bucket =
130-
storage
131-
.runCatching { get(bucketName) }
132-
.onFailure { e ->
133-
if (
134-
e is StorageException &&
135-
e.cause.let {
136-
it is com.google.api.client.http.HttpResponseException &&
137-
(it.statusCode == 401 || it.statusCode == 403)
138-
}
139-
) {
140-
logger.error(
141-
"ERROR: 401/403 error returned from Google Cloud Storage; " +
142-
"try running \"gcloud auth application-default login\" and/or unsetting the " +
143-
"GOOGLE_APPLICATION_CREDENTIALS environment variable to fix"
144-
)
145-
}
140+
141+
return runCatching { get(bucketName) }
142+
.onFailure { e ->
143+
if (
144+
e is StorageException &&
145+
e.cause.let {
146+
it is com.google.api.client.http.HttpResponseException &&
147+
(it.statusCode == 401 || it.statusCode == 403)
148+
}
149+
) {
150+
logger.error(
151+
"ERROR: 401/403 error returned from Google Cloud Storage; " +
152+
"try running \"gcloud auth application-default login\" and/or unsetting the " +
153+
"GOOGLE_APPLICATION_CREDENTIALS environment variable to fix"
154+
)
146155
}
147-
.getOrThrow()
148-
?: throw DataConnectGradleException("bvkxzp2esg", "GCS bucket not found: $bucketName")
156+
}
157+
.getOrThrow()
158+
?: throw DataConnectGradleException("bvkxzp2esg", "GCS bucket not found: $bucketName")
159+
}
149160

150-
val invalidVersions = setOf("1.15.0".toVersion())
151-
val minVersion = "1.3.4".toVersion()
161+
private fun Blob.toCloudStorageVersionInfoOrNull(): CloudStorageVersionInfo? {
162+
logger.debug("[av7zhespw2] Found Data Connect executable file: {}", name)
163+
val match =
164+
fileNameRegex.matchEntire(name)
165+
?: run {
166+
logger.debug(
167+
"[p4vjjcp2kq] Ignoring Data Connect executable file: {} " +
168+
"(does not match regex: {})",
169+
name,
170+
fileNameRegex
171+
)
172+
return null
173+
}
152174

153-
val blobs = bucket.list(BlobListOption.prefix("emulator/"))
154-
val regex = ".*dataconnect-emulator-([^-]+)-v(.*)".toRegex()
155-
val dataConnectExecutableBinaries =
156-
blobs
157-
.iterateAll()
158-
.mapNotNull {
159-
logger.debug("[av7zhespw2] Found Data Connect executable file: {}", it.name)
160-
val match =
161-
regex.matchEntire(it.name)
162-
?: run {
163-
logger.debug(
164-
"[p4vjjcp2kq] Ignoring Data Connect executable file: {} " +
165-
"(does not match regex: {})",
166-
it.name,
167-
regex
168-
)
169-
return@mapNotNull null
170-
}
171-
CloudStorageVersionInfo(
172-
version =
173-
run {
174-
val versionString = match.groups[2]?.value
175-
versionString?.toVersionOrNull(strict = false)
176-
?: run {
177-
logger.info(
178-
"WARNING: Ignoring Data Connect executable file: {} " +
179-
"(invalid version: {} (in match for regex {}))",
180-
it.name,
181-
versionString,
182-
regex
183-
)
184-
return@mapNotNull null
185-
}
186-
},
187-
operatingSystem =
188-
when (val operatingSystemString = match.groups[1]?.value) {
189-
"linux" -> OperatingSystem.Linux
190-
"macos" -> OperatingSystem.MacOS
191-
"windows" -> OperatingSystem.Windows
192-
else -> {
193-
logger.info(
194-
"WARNING: Ignoring Data Connect executable file: {} " +
195-
"(unknown operating system name: {} (in match for regex {}))",
196-
it.name,
197-
operatingSystemString,
198-
regex
199-
)
200-
return@mapNotNull null
201-
}
202-
},
203-
blob = it,
175+
val versionString = match.groups[2]?.value
176+
val version = versionString?.toVersionOrNull(strict = false)
177+
if (version === null) {
178+
logger.info(
179+
"Ignoring Data Connect executable file: {} " +
180+
"(invalid version: {} (in match for regex {}))",
181+
name,
182+
versionString,
183+
fileNameRegex
184+
)
185+
return null
186+
}
187+
188+
if (version < minVersion) {
189+
logger.info(
190+
"Ignoring Data Connect executable file: {} " +
191+
"(version {} is less than the minimum version: {})",
192+
name,
193+
versionString,
194+
minVersion
195+
)
196+
return null
197+
}
198+
199+
if (version in invalidVersions) {
200+
logger.info(
201+
"Ignoring Data Connect executable file: {} " + "(version {} is a known invalid version)",
202+
name,
203+
versionString
204+
)
205+
return null
206+
}
207+
208+
val operatingSystem =
209+
when (val operatingSystemString = match.groups[1]?.value) {
210+
"linux" -> OperatingSystem.Linux
211+
"macos" -> OperatingSystem.MacOS
212+
"windows" -> OperatingSystem.Windows
213+
else -> {
214+
logger.info(
215+
"WARNING: Ignoring Data Connect executable file: {} " +
216+
"(unknown operating system name: {} (in match for regex {}))",
217+
name,
218+
operatingSystemString,
219+
fileNameRegex
204220
)
221+
return null
205222
}
206-
.filter { it.version >= minVersion }
207-
.filterNot { invalidVersions.contains(it.version) }
208-
.toSet()
223+
}
209224

210-
return dataConnectExecutableBinaries
225+
return CloudStorageVersionInfo(version, operatingSystem, blob = this)
211226
}
212227

213-
private data class CloudStorageVersionInfo(
214-
val version: Version,
215-
val operatingSystem: OperatingSystem,
216-
val blob: Blob,
217-
)
218-
219-
private fun CloudStorageVersionInfo.toRegistryVersionInfo(
220-
workDirectory: File
221-
): DataConnectExecutableVersionsRegistry.VersionInfo {
228+
private fun CloudStorageVersionInfo.toRegistryVersionInfo(workDirectory: File): VersionInfo {
222229
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
223230

224231
logger.lifecycle(
@@ -238,19 +245,31 @@ abstract class UpdateDataConnectExecutableVersionsTask : DefaultTask() {
238245
"never happen; if it _does_ happen it _could_ indicate a compromised " +
239246
"downloaded binary [y5967yd2cf]"
240247
}
241-
return DataConnectExecutableVersionsRegistry.VersionInfo(
242-
version,
243-
operatingSystem,
244-
fileInfo.sizeInBytes,
245-
fileInfo.sha512DigestHex
246-
)
248+
return VersionInfo(version, operatingSystem, fileInfo.sizeInBytes, fileInfo.sha512DigestHex)
247249
}
248250

249251
private companion object {
250252

251253
val versionInfoComparator =
252-
compareBy<DataConnectExecutableVersionsRegistry.VersionInfo> { it.version }
253-
.thenByDescending { it.os.serializedValue }
254+
compareBy<VersionInfo> { it.version }.thenByDescending { it.os.serializedValue }
255+
256+
val cloudStorageVersionInfoComparator =
257+
compareBy<CloudStorageVersionInfo> { it.version }
258+
.thenByDescending { it.operatingSystem.serializedValue }
259+
260+
@JvmName("toLogStringCloudStorageVersionInfo")
261+
fun Iterable<CloudStorageVersionInfo>.toLogString(): String = joinToString {
262+
"${it.version}-${it.operatingSystem.serializedValue}"
263+
}
264+
265+
@JvmName("toLogStringVersionInfo")
266+
fun Iterable<VersionInfo>.toLogString(): String = joinToString {
267+
"${it.version}-${it.os.serializedValue}"
268+
}
269+
270+
val invalidVersions = setOf("1.15.0".toVersion())
271+
val minVersion = "1.3.4".toVersion()
272+
val fileNameRegex = ".*dataconnect-emulator-([^-]+)-v(.*)".toRegex()
254273

255274
/**
256275
* Creates a returns a new list that contains all elements of the receiving [Iterable] that are
@@ -265,16 +284,14 @@ abstract class UpdateDataConnectExecutableVersionsTask : DefaultTask() {
265284
}
266285

267286
private fun DataConnectExecutableVersionsRegistry.Root.updatedWith(
268-
updatedVersions: Iterable<DataConnectExecutableVersionsRegistry.VersionInfo>
287+
updatedVersions: Iterable<VersionInfo>
269288
): DataConnectExecutableVersionsRegistry.Root {
270-
val mergedVersions = buildList {
289+
val allVersions = buildList {
271290
addAll(versions)
272-
for (version in updatedVersions) {
273-
val index = indexOfLast { versionInfoComparator.compare(it, version) < 0 }
274-
add(index + 1, version)
275-
}
291+
addAll(updatedVersions)
292+
sortWith(versionInfoComparator)
276293
}
277-
return copy(defaultVersion = mergedVersions.maxOf { it.version }, versions = mergedVersions)
294+
return copy(defaultVersion = allVersions.maxOf { it.version }, versions = allVersions)
278295
}
279296
}
280297
}

0 commit comments

Comments
 (0)