IDEA-393089 jdk: fix version parsing for .sdkmanrc

#IDEA-393089 Fixed


(cherry picked from commit 6537a8d048014b2dc574017150e8a9ed455c4582)

IJ-CR-221165

GitOrigin-RevId: ce407c015361da6374d6ac5dbef41b920c56e84f
This commit is contained in:
Louis Vignier
2026-09-03 10:14:49 +00:00
committed by intellij-monorepo-bot
parent 5ba7a3e328
commit 2e40e8203c
2 changed files with 85 additions and 11 deletions
@@ -14,16 +14,35 @@ public data class SdkmanReleaseData(val target: String,
val flavour: String? = null,
val vendor: String? = null) : JdkReleaseData {
public companion object {
private val regex: Regex = Regex("(\\d+(?:\\.\\d+)*)(?:\\.([^-]+))?-?(\\S*)?")
private val versionRegex: Regex = Regex("\\d+(?:\\.\\d+)*")
private val vendorRegex: Regex = Regex("[a-z]+")
/**
* Parses a SDKMAN! java candidate identifier, as listed by `sdk list java`.
*
* An identifier consists of a dot-separated [version], an optional [flavour] holding the remaining
* qualifiers and build metadata (`fx`, `ea.11`, `hs`, `+1.1`, `r25`, ...),
* and an optional [vendor] suffix separated by the last `-`.
*
* For example: `8.0.504-amzn`, `28.0.0+ea.11-open`, `25.0.4-fx+1.1-librca`, `16.0.1.hs-adpt`.
*/
public fun parse(text: String): SdkmanReleaseData? {
val matchResult = regex.matchEntire(text) ?: return null
return SdkmanReleaseData(
text,
matchResult.groups[1]?.value ?: return null,
matchResult.groups[2]?.value,
matchResult.groups[3]?.value
)
if (text.isEmpty() || !text[0].isDigit()) return null
var rest = text
var vendor: String? = null
val separatorIndex = text.lastIndexOf('-')
if (separatorIndex > 0) {
val suffix = text.substring(separatorIndex + 1)
if (vendorRegex.matches(suffix)) {
vendor = suffix
rest = text.substring(0, separatorIndex)
}
}
val version = versionRegex.matchAt(rest, 0)?.value ?: return null
val flavour = rest.substring(version.length).trimStart('.', '-', '+').takeIf { it.isNotEmpty() }
return SdkmanReleaseData(text, version, flavour, vendor)
}
}
@@ -39,14 +58,14 @@ public data class SdkmanReleaseData(val target: String,
"graalce" -> JdkVersionDetector.Variant.GraalVMCE
"jbr" -> JdkVersionDetector.Variant.JBR
"kona" -> JdkVersionDetector.Variant.Kona
"librca" -> JdkVersionDetector.Variant.Liberica
"librca", "librcafx", "nik" -> JdkVersionDetector.Variant.Liberica
"ms" -> JdkVersionDetector.Variant.Microsoft
"oracle" -> JdkVersionDetector.Variant.Oracle
"open" -> JdkVersionDetector.Variant.Oracle
"sapmchn" -> JdkVersionDetector.Variant.SapMachine
"sem" -> JdkVersionDetector.Variant.Semeru
"tem" -> JdkVersionDetector.Variant.Temurin
"zulu" -> JdkVersionDetector.Variant.Zulu
"zulu", "zulufx" -> JdkVersionDetector.Variant.Zulu
else -> JdkVersionDetector.Variant.Unknown
}
}
@@ -5,6 +5,7 @@ import com.intellij.platform.util.coroutines.childScope
import com.intellij.testFramework.UsefulTestCase
import kotlinx.coroutines.cancel
import kotlinx.coroutines.runBlocking
import org.jetbrains.jps.model.java.JdkVersionDetector
class SdkmanrcWatcherHeavyTests : ExternalJavaConfigurationTest() {
override val mockJdkVersions: List<String> = listOf(
@@ -38,7 +39,7 @@ class SdkmanrcWatcherLightTests : UsefulTestCase() {
fun `test candidates parsing`() {
assertEquals(SdkmanReleaseData.parse("8"),
SdkmanReleaseData("8", "8", null, ""))
SdkmanReleaseData("8", "8", null, null))
assertEquals(SdkmanReleaseData.parse("19-zulu"),
SdkmanReleaseData("19-zulu", "19", null, "zulu"))
@@ -53,6 +54,60 @@ class SdkmanrcWatcherLightTests : UsefulTestCase() {
SdkmanReleaseData("16.0.1.hs-adpt", "16.0.1", "hs", "adpt"))
}
/**
* Identifiers as printed by `sdk list java`.
*/
fun `test identifiers parsing`() {
assertEquals(SdkmanReleaseData.parse("21.0.12+1.1-tem"),
SdkmanReleaseData("21.0.12+1.1-tem", "21.0.12", "1.1", "tem"))
assertEquals(SdkmanReleaseData.parse("28.0.0+ea.11-open"),
SdkmanReleaseData("28.0.0+ea.11-open", "28.0.0", "ea.11", "open"))
assertEquals(SdkmanReleaseData.parse("26.0.2-fx+1.1-librca"),
SdkmanReleaseData("26.0.2-fx+1.1-librca", "26.0.2", "fx+1.1", "librca"))
assertEquals(SdkmanReleaseData.parse("26.0.2.fx-zulu"),
SdkmanReleaseData("26.0.2.fx-zulu", "26.0.2", "fx", "zulu"))
assertEquals(SdkmanReleaseData.parse("11.0.14.1-jbr"),
SdkmanReleaseData("11.0.14.1-jbr", "11.0.14.1", null, "jbr"))
assertEquals(SdkmanReleaseData.parse("25.0.4+1.1.r25-nik"),
SdkmanReleaseData("25.0.4+1.1.r25-nik", "25.0.4", "1.1.r25", "nik"))
assertEquals(SdkmanReleaseData.parse("8.0.504+1-librca"),
SdkmanReleaseData("8.0.504+1-librca", "8.0.504", "1", "librca"))
assertNull(SdkmanReleaseData.parse("current"))
}
fun `test identifiers versions and variants`() {
for ((identifier, expected) in mapOf(
"26.0.2-amzn" to (JdkVersionDetector.Variant.Corretto to 26),
"25.2.4-graalce" to (JdkVersionDetector.Variant.GraalVMCE to 25),
"25.0.4-graal" to (JdkVersionDetector.Variant.GraalVM to 25),
"28.0.0+ea.11-open" to (JdkVersionDetector.Variant.Oracle to 28),
"25.0.4-jbr" to (JdkVersionDetector.Variant.JBR to 25),
"26.0.2-fx+1.1-librca" to (JdkVersionDetector.Variant.Liberica to 26),
"25.0.4+1.1.r25-nik" to (JdkVersionDetector.Variant.Liberica to 25),
"25.0.4+1-ms" to (JdkVersionDetector.Variant.Microsoft to 25),
"26.0.2-oracle" to (JdkVersionDetector.Variant.Oracle to 26),
"26.0.2+1-sapmchn" to (JdkVersionDetector.Variant.SapMachine to 26),
"26.0.2-sem" to (JdkVersionDetector.Variant.Semeru to 26),
"21.0.12+1.1-tem" to (JdkVersionDetector.Variant.Temurin to 21),
"25.0.4+1-kona" to (JdkVersionDetector.Variant.Kona to 25),
"26.0.2+1.1-zulu" to (JdkVersionDetector.Variant.Zulu to 26),
"8.0.504+1-librca" to (JdkVersionDetector.Variant.Liberica to 8),
)) {
val releaseData = SdkmanReleaseData.parse(identifier)
assertNotNull("$identifier is not parsed", releaseData)
val (variant, feature) = expected
assertEquals("$identifier is not parsed as $variant", variant, releaseData!!.variant)
assertEquals("$identifier is not parsed as Java $feature", feature, releaseData.javaVersion?.feature)
}
}
fun `test candidates matching`() {
for ((candidate, version) in mapOf(
"11.0.11.hs-adpt" to "AdoptOpenJDK (HotSpot) 11.0.11",