-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathFoojayApi.kt
119 lines (100 loc) · 4.3 KB
/
FoojayApi.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package org.gradle.toolchains.foojay
import org.gradle.api.GradleException
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JvmImplementation
import org.gradle.jvm.toolchain.JvmVendorSpec
import org.gradle.platform.Architecture
import org.gradle.platform.OperatingSystem
import java.io.BufferedReader
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URI
import java.net.URL
import java.net.URLEncoder
import java.nio.charset.StandardCharsets.UTF_8
import java.util.concurrent.TimeUnit.SECONDS
@Suppress("UnstableApiUsage")
class FoojayApi {
companion object {
val CONNECT_TIMEOUT = SECONDS.toMillis(10).toInt()
val READ_TIMEOUT = SECONDS.toMillis(20).toInt()
const val SCHEMA = "https"
private const val ENDPOINT_ROOT = "api.foojay.io/disco/v3.0"
const val DISTRIBUTIONS_ENDPOINT = "$ENDPOINT_ROOT/distributions"
const val PACKAGES_ENDPOINT = "$ENDPOINT_ROOT/packages"
}
val distributions = mutableListOf<Distribution>()
fun toUri(links: Links?): URI? = links?.pkg_download_redirect
@Suppress("LongParameterList")
fun toPackage(
version: JavaLanguageVersion,
vendor: JvmVendorSpec,
implementation: JvmImplementation,
nativeImageCapable: Boolean,
operatingSystem: OperatingSystem,
architecture: Architecture
): Package? {
val distributions = match(vendor, implementation, version, nativeImageCapable)
return distributions.asSequence().mapNotNull { distribution ->
match(distribution.api_parameter, version, operatingSystem, architecture)
}.firstOrNull()
}
internal fun match(vendor: JvmVendorSpec, implementation: JvmImplementation, version: JavaLanguageVersion, nativeImageCapable: Boolean): List<Distribution> {
fetchDistributionsIfMissing()
return match(distributions, vendor, implementation, version, nativeImageCapable)
}
private fun fetchDistributionsIfMissing() {
if (distributions.isEmpty()) {
val con = createConnection(
DISTRIBUTIONS_ENDPOINT,
mapOf("include_versions" to "true", "include_synonyms" to "true")
)
val json = readResponse(con)
con.disconnect()
distributions.addAll(parseDistributions(json))
}
}
internal fun match(distributionName: String, version: JavaLanguageVersion, operatingSystem: OperatingSystem, architecture: Architecture): Package? {
val versionApiKey = when {
distributionName.startsWith("graalvm_community") -> "version"
distributionName.equals("graalvm") -> "version"
else -> "jdk_version"
}
val con = createConnection(
PACKAGES_ENDPOINT,
mapOf(
versionApiKey to "$version",
"distro" to distributionName,
"operating_system" to operatingSystem.toApiValue(),
"latest" to "available",
"directly_downloadable" to "true"
)
)
val json = readResponse(con)
con.disconnect()
val packages = parsePackages(json)
return match(packages, architecture)
}
private fun createConnection(endpoint: String, parameters: Map<String, String>): HttpURLConnection {
val url = URL("$SCHEMA://$endpoint?${toParameterString(parameters)}")
val con = url.openConnection() as HttpURLConnection
con.setRequestProperty("Content-Type", "application/json")
con.requestMethod = "GET"
con.connectTimeout = CONNECT_TIMEOUT
con.readTimeout = READ_TIMEOUT
return con
}
private fun toParameterString(params: Map<String, String>): String {
return params.entries.joinToString("&") {
"${URLEncoder.encode(it.key, UTF_8.name())}=${URLEncoder.encode(it.value, UTF_8.name())}"
}
}
private fun readResponse(con: HttpURLConnection): String {
val status = con.responseCode
if (status != HttpURLConnection.HTTP_OK) {
throw GradleException("Requesting vendor list failed: ${readContent(con.errorStream)}")
}
return readContent(con.inputStream)
}
private fun readContent(stream: InputStream) = stream.bufferedReader().use(BufferedReader::readText)
}