@@ -23,9 +23,8 @@ import java.util.regex.Pattern
2323import kotlin.time.Duration.Companion.seconds
2424import kotlin.time.DurationUnit
2525import kotlin.time.toDuration
26- import kotlinx.serialization.encodeToString
27- import kotlinx.serialization.json.Json
2826import org.gradle.api.DefaultTask
27+ import org.gradle.api.Task
2928import org.gradle.api.file.DirectoryProperty
3029import org.gradle.api.file.RegularFileProperty
3130import org.gradle.api.provider.Property
@@ -42,6 +41,8 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
4241
4342 @get:Input @get:Optional abstract val version: Property <String >
4443
44+ @get:Input @get:Optional abstract val operatingSystem: Property <OperatingSystem >
45+
4546 @get:Internal abstract val buildDirectory: DirectoryProperty
4647
4748 @get:OutputFile abstract val outputFile: RegularFileProperty
@@ -50,11 +51,13 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
5051 fun run () {
5152 val inputFile: File ? = inputFile.orNull?.asFile
5253 val version: String? = version.orNull
54+ val operatingSystem: OperatingSystem = operatingSystem.get()
5355 val buildDirectory: File = buildDirectory.get().asFile
5456 val outputFile: File = outputFile.get().asFile
5557
5658 logger.info(" inputFile: {}" , inputFile)
5759 logger.info(" version: {}" , version)
60+ logger.info(" operatingSystem: {}" , operatingSystem)
5861 logger.info(" buildDirectory: {}" , buildDirectory)
5962 logger.info(" outputFile: {}" , outputFile)
6063
@@ -71,8 +74,8 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
7174 } else if (inputFile != = null ) {
7275 runWithFile(inputFile = inputFile, outputFile = outputFile)
7376 } else if (version != = null ) {
74- runWithVersion (version = version, outputFile = outputFile)
75- verifyOutputFile(outputFile, version)
77+ downloadDataConnectExecutable (version, operatingSystem, outputFile)
78+ verifyOutputFile(outputFile, operatingSystem, version)
7679 } else {
7780 throw DataConnectGradleException (
7881 " chc94cq7vx" ,
@@ -82,66 +85,73 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
8285 }
8386 }
8487
85- private fun verifyOutputFile (outputFile : File , version : String ) {
88+ private fun verifyOutputFile (
89+ outputFile : File ,
90+ operatingSystem : OperatingSystem ,
91+ version : String
92+ ) {
8693 logger.info(" Verifying file size and SHA512 digest of file: {}" , outputFile)
8794 val fileInfo = FileInfo .forFile(outputFile)
8895
89- val verificationInfoJsonString =
90- jsonPrettyPrint.encodeToString(
91- DataConnectExecutable .VersionsJson .VerificationInfo (
92- size = fileInfo.sizeInBytes,
93- sha512DigestHex = fileInfo.sha512DigestHex,
94- )
95- )
96+ val allVersions = DataConnectExecutableVersionsRegistry .load().versions
97+ val allVersionNames =
98+ allVersions
99+ .asSequence()
100+ .filter { it.os == operatingSystem }
101+ .map { it.version }
102+ .distinct()
103+ .sorted()
104+ .joinToString(" , " )
105+ val applicableVersions =
106+ allVersions.filter { it.version == version && it.os == operatingSystem }
96107
97- val verificationInfoByVersion = DataConnectExecutable .VersionsJson .load().versions
98- val verificationInfo = verificationInfoByVersion[version]
99- if (verificationInfo == = null ) {
108+ if (applicableVersions.isEmpty()) {
100109 val message =
101- " verification information for ${outputFile.absolutePath} " +
102- " (version $version ) is not known; known versions are: " +
103- verificationInfoByVersion.keys.sorted().joinToString(" , " )
110+ " verification information for Data Connect toolkit executable" +
111+ " version $version for $operatingSystem is not known;" +
112+ " known versions for $operatingSystem are: $allVersionNames " +
113+ " (loaded from ${DataConnectExecutableVersionsRegistry .PATH } )"
104114 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- )
109115 throw DataConnectGradleException (" ym8assbfgw" , message)
116+ } else if (applicableVersions.size > 1 ) {
117+ val message =
118+ " INTERNAL ERROR: ${applicableVersions.size} verification information records for" +
119+ " Data Connect toolkit executable version $version for $operatingSystem were found in" +
120+ " ${DataConnectExecutableVersionsRegistry .PATH } , but expected exactly 1"
121+ logger.error(" ERROR: $message " )
122+ throw DataConnectGradleException (" zyw5xrky6e" , message)
110123 }
111124
125+ val versionInfo = applicableVersions.single()
112126 val verificationErrors = mutableListOf<String >()
113- if (fileInfo.sizeInBytes != verificationInfo .size) {
127+ if (fileInfo.sizeInBytes != versionInfo .size) {
114128 logger.error(
115129 " ERROR: File ${outputFile.absolutePath} has an unexpected size (in bytes): actual is " +
116130 fileInfo.sizeInBytes.toStringWithThousandsSeparator() +
117131 " but expected " +
118- verificationInfo .size.toStringWithThousandsSeparator()
132+ versionInfo .size.toStringWithThousandsSeparator()
119133 )
120134 verificationErrors.add(" file size mismatch" )
121135 }
122- if (fileInfo.sha512DigestHex != verificationInfo .sha512DigestHex) {
136+ if (fileInfo.sha512DigestHex != versionInfo .sha512DigestHex) {
123137 logger.error(
124138 " ERROR: File ${outputFile.absolutePath} has an unexpected SHA512 digest:" +
125139 " actual is ${fileInfo.sha512DigestHex} " +
126- " but expected ${verificationInfo .sha512DigestHex} "
140+ " but expected ${versionInfo .sha512DigestHex} "
127141 )
128142 verificationErrors.add(" SHA512 digest mismatch" )
129143 }
130144
131- if (verificationErrors.isEmpty()) {
132- logger.info(" Verifying file size and SHA512 digest succeeded" )
133- return
145+ if (verificationErrors.isNotEmpty()) {
146+ val errorMessage =
147+ " Verification of ${outputFile.absolutePath} " +
148+ " (version=${versionInfo.version} os=${versionInfo.os} ) failed:" +
149+ " ${verificationErrors.joinToString(" , " )} "
150+ logger.error(errorMessage)
151+ throw DataConnectGradleException (" x9dfwhjr9c" , errorMessage)
134152 }
135153
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- )
154+ logger.info(" Verifying file size and SHA512 digest succeeded" )
145155 }
146156
147157 data class FileInfo (val sizeInBytes : Long , val sha512DigestHex : String ) {
@@ -181,62 +191,73 @@ abstract class DataConnectExecutableDownloadTask : DefaultTask() {
181191 }
182192 }
183193
184- private fun runWithVersion (version : String , outputFile : File ) {
185- val fileName = " dataconnect-emulator-linux-v$version "
186- val url = URL (" https://storage.googleapis.com/firemat-preview-drop/emulator/$fileName " )
194+ companion object {
195+ fun Task.downloadDataConnectExecutable (
196+ version : String ,
197+ operatingSystem : OperatingSystem ,
198+ outputFile : File
199+ ) {
200+ val osName =
201+ when (operatingSystem) {
202+ OperatingSystem .Windows -> " windows"
203+ OperatingSystem .MacOS -> " macos"
204+ OperatingSystem .Linux -> " linux"
205+ }
206+ val downloadFileName = " dataconnect-emulator-$osName -v$version "
207+ val url =
208+ URL (" https://storage.googleapis.com/firemat-preview-drop/emulator/$downloadFileName " )
187209
188- logger.info(" Downloading {} to {}" , url, outputFile)
189- project.mkdir(outputFile.parentFile)
210+ logger.info(" Downloading {} to {}" , url, outputFile)
211+ project.mkdir(outputFile.parentFile)
190212
191- val connection = url.openConnection() as HttpURLConnection
192- connection.requestMethod = " GET"
213+ val connection = url.openConnection() as HttpURLConnection
214+ connection.requestMethod = " GET"
193215
194- val responseCode = connection.responseCode
195- if (responseCode != HttpURLConnection .HTTP_OK ) {
196- throw DataConnectGradleException (
197- " n3mj6ahxwt" ,
198- " Downloading Data Connect executable from $url failed with HTTP response code" +
199- " $responseCode : ${connection.responseMessage} " +
200- " (expected HTTP response code ${HttpURLConnection .HTTP_OK } )"
201- )
202- }
203-
204- val startTime = System .nanoTime()
205- val debouncer = Debouncer (5 .seconds)
206- outputFile.outputStream().use { oStream ->
207- var downloadByteCount: Long = 0
208- fun logDownloadedBytes () {
209- val elapsedTime = (System .nanoTime() - startTime).toDuration(DurationUnit .NANOSECONDS )
210- logger.info(
211- " Downloaded {} bytes in {}" ,
212- downloadByteCount.toStringWithThousandsSeparator(),
213- elapsedTime
216+ val responseCode = connection.responseCode
217+ if (responseCode != HttpURLConnection .HTTP_OK ) {
218+ throw DataConnectGradleException (
219+ " n3mj6ahxwt" ,
220+ " Downloading Data Connect executable from $url failed with HTTP response code" +
221+ " $responseCode : ${connection.responseMessage} " +
222+ " (expected HTTP response code ${HttpURLConnection .HTTP_OK } )"
214223 )
215224 }
216- connection.inputStream.use { iStream ->
217- val buffer = ByteArray (8192 )
218- while (true ) {
219- val readCount = iStream.read(buffer)
220- if (readCount < 0 ) {
221- break
225+
226+ val startTime = System .nanoTime()
227+ val debouncer = Debouncer (5 .seconds)
228+ outputFile.outputStream().use { oStream ->
229+ var downloadByteCount: Long = 0
230+ fun logDownloadedBytes () {
231+ val elapsedTime = (System .nanoTime() - startTime).toDuration(DurationUnit .NANOSECONDS )
232+ logger.info(
233+ " Downloaded {} bytes in {}" ,
234+ downloadByteCount.toStringWithThousandsSeparator(),
235+ elapsedTime
236+ )
237+ }
238+ connection.inputStream.use { iStream ->
239+ val buffer = ByteArray (8192 )
240+ while (true ) {
241+ val readCount = iStream.read(buffer)
242+ if (readCount < 0 ) {
243+ break
244+ }
245+ downloadByteCount + = readCount
246+ debouncer.maybeRun(::logDownloadedBytes)
247+ oStream.write(buffer, 0 , readCount)
222248 }
223- downloadByteCount + = readCount
224- debouncer.maybeRun(::logDownloadedBytes)
225- oStream.write(buffer, 0 , readCount)
226249 }
250+ logDownloadedBytes()
227251 }
228- logDownloadedBytes()
229- }
230252
231- project.exec { execSpec ->
232- execSpec.run {
233- executable = " chmod"
234- args = listOf (" a+x" , outputFile.absolutePath)
253+ if (operatingSystem != OperatingSystem .Windows ) {
254+ project.exec { execSpec ->
255+ execSpec.run {
256+ executable = " chmod"
257+ args = listOf (" a+x" , outputFile.absolutePath)
258+ }
259+ }
235260 }
236261 }
237262 }
238-
239- private companion object {
240- val jsonPrettyPrint = Json { prettyPrint = true }
241- }
242263}
0 commit comments