From 7014a8905121b278fce1f1097c0e87dfa868d443 Mon Sep 17 00:00:00 2001 From: Qiheng He Date: Sun, 18 Oct 2026 11:39:42 +0800 Subject: [PATCH] fix: select early-access builds that `.sdkmanrc` names as `vfox list java` shows them --- docs/e2e.md | 9 ++++++--- hooks/parse_legacy_file.lua | 29 ++++++++++++++++++----------- tests/e2e/linux/verify.go | 16 ++++++++++------ tests/e2e/windows/verify.go | 16 ++++++++++------ tests/parse_legacy_file_test.lua | 8 ++++++++ 5 files changed, 52 insertions(+), 26 deletions(-) diff --git a/docs/e2e.md b/docs/e2e.md index 67b8c57..98a8555 100644 --- a/docs/e2e.md +++ b/docs/e2e.md @@ -93,9 +93,12 @@ JDK, so `java` can only come from what vfox installs: OpenJDK's (`28.0.0.0+ea.20-open`), must select that build: `java=21.0.0.0+ea.1-tem` selects `21-ea+1-tem`, not the release, which `ParseLegacyFile` took while it understood only SDKMAN's older - `21.ea.1-tem`. jdk.java.net removes each early-access build within weeks, - so that install is faked: its `bin` holds a stand-in `java` that only - prints the name. On Windows the file is written with CRLF line endings. + `21.ea.1-tem`. So must the installed name itself (`java=21-ea+1-tem`), + for which `ParseLegacyFile`, unable to parse it, selected nothing, while + `vfox use` selects it. jdk.java.net removes each early-access build within + weeks, so that install is faked: its `bin` holds a stand-in `java` that + only prints the name. On Windows the file is written with CRLF line + endings. 5. After `vfox use --global`, the JDK on `PATH` reports the requested `java.version`, the runner's `os.arch` (`amd64` / `aarch64`, which also catches an x64 JDK emulated on Windows ARM64) and the distribution's diff --git a/hooks/parse_legacy_file.lua b/hooks/parse_legacy_file.lua index 1b0682e..e42d216 100644 --- a/hooks/parse_legacy_file.lua +++ b/hooks/parse_legacy_file.lua @@ -54,7 +54,7 @@ function PLUGIN:ParseLegacyFile(ctx) for line in io.lines(filepath) do if strings.has_prefix(line, "java=") then - javaVersion = plugin_spelling(strings.trim_prefix(line, "java=")) + javaVersion = strings.trim_prefix(line, "java=") break end end @@ -63,7 +63,23 @@ function PLUGIN:ParseLegacyFile(ctx) return {} end - local distributionVersion = distribution_version_parser.parse_version(javaVersion) + --- Get the list of versions of the current plugin installed + --- (a plain call: vfox 1.x rejects the extra ctx argument of ctx:...). + --- vfox sorts it as strings, descending (21.0.8+9-tem, 21.0.12+8-tem, + --- 21.0.1+12-tem), so the first match is not the one to take. + local installed = {} + for _, v in ipairs(ctx.getInstalledVersions()) do + installed[v] = true + end + + --- An installed version written as vfox lists it selects itself, as in + --- vfox use, even one that parse_version cannot read: an early-access + --- build (28-ea+19, 28-ea+18-zulu). + if installed[javaVersion] then + return { version = javaVersion } + end + + local distributionVersion = distribution_version_parser.parse_version(plugin_spelling(javaVersion)) if not distributionVersion then return {} end @@ -82,15 +98,6 @@ function PLUGIN:ParseLegacyFile(ctx) --- JavaFX builds: 21.0.8+9-tem, 21.0.12+7-zulu-fx, 25.0.2+10. local suffix = (vendor == "open" and "" or "-" .. vendor) .. (distributionVersion.javafx_bundled and "-fx" or "") - --- Get the list of versions of the current plugin installed - --- (a plain call: vfox 1.x rejects the extra ctx argument of ctx:...). - --- vfox sorts it as strings, descending (21.0.8+9-tem, 21.0.12+8-tem, - --- 21.0.1+12-tem), so the first match is not the one to take. - local installed = {} - for _, v in ipairs(ctx.getInstalledVersions()) do - installed[v] = true - end - --- The version itself (21.0.5+63130-jb), else the release itself or its --- newest build, as SDKMAN's build numbers count its own rebuilds --- (21.0.12+1.1-tem), else the newest installed release of the major diff --git a/tests/e2e/linux/verify.go b/tests/e2e/linux/verify.go index 1563a07..2d798f1 100644 --- a/tests/e2e/linux/verify.go +++ b/tests/e2e/linux/verify.go @@ -62,8 +62,9 @@ func verifySearch(ctx context.Context, t *testing.T, ctr tc.Container, distribut // itself (e.g. java=21.0.8+9-tem), while vfox lists an empty install of // another release first (see common.Decoy). SDKMAN's identifier of an // early-access build (e.g. java=21.0.0.0+ea.1-tem) must then select a faked -// install of that build (see common.EarlyAccess), not the release. It runs -// before any `vfox use`, so java can only come from the legacy file. +// install of that build (see common.EarlyAccess), not the release, and so +// must its installed name (e.g. java=21-ea+1-tem). It runs before any +// `vfox use`, so java can only come from the legacy file. func verifyLegacyFile(ctx context.Context, t *testing.T, ctr tc.Container, distribution, version, installed, arch string) { t.Helper() // vfox counts a version as installed once its directory holds @@ -93,10 +94,13 @@ func verifyLegacyFile(ctx context.Context, t *testing.T, ctr tc.Container, distr bin := eaDir + "/" + shQuote("java-"+ea) + "/bin" execOK(ctx, t, ctr, fmt.Sprintf("mkdir --parents %s && printf '%%s' %s > %s/java && chmod +x %s/java", bin, shQuote("#!/bin/sh\necho "+shQuote(ea)+"\n"), bin, bin)) - identifier := common.EarlyAccessIdentifier(distribution, version) - out := legacyJava(ctx, t, ctr, identifier) - require.Containsf(t, out, ea, ".sdkmanrc java=%s must select %s, not %s", identifier, ea, installed) - t.Logf("PASS .sdkmanrc java=%s selects %s, not %s", identifier, ea, installed) + // ParseLegacyFile could not parse the installed name, so it selected + // nothing for it, while `vfox use` selects it (vfox-java#91). + for _, identifier := range []string{common.EarlyAccessIdentifier(distribution, version), ea} { + out := legacyJava(ctx, t, ctr, identifier) + require.Containsf(t, out, ea, ".sdkmanrc java=%s must select %s, not %s", identifier, ea, installed) + t.Logf("PASS .sdkmanrc java=%s selects %s, not %s", identifier, ea, installed) + } execOK(ctx, t, ctr, "rm --recursive "+eaDir) } diff --git a/tests/e2e/windows/verify.go b/tests/e2e/windows/verify.go index c6f9b6f..9a7e5af 100644 --- a/tests/e2e/windows/verify.go +++ b/tests/e2e/windows/verify.go @@ -65,8 +65,9 @@ func verifySearch(ctx context.Context, t *testing.T, ctr tc.Container, box slotB // endings, while vfox lists an empty install of another release first (see // common.Decoy). SDKMAN's identifier of an early-access build (e.g. // java=21.0.0.0+ea.1-tem) must then select a faked install of that build -// (see common.EarlyAccess), not the release. It runs before any `vfox use`, -// so java can only come from the legacy file. +// (see common.EarlyAccess), not the release, and so must its installed name +// (e.g. java=21-ea+1-tem). It runs before any `vfox use`, so java can only +// come from the legacy file. func verifyLegacyFile(ctx context.Context, t *testing.T, ctr tc.Container, box slotBox, distribution, version, installed, arch string) { t.Helper() // vfox counts a version as installed once its directory holds @@ -98,10 +99,13 @@ func verifyLegacyFile(ctx context.Context, t *testing.T, ctr tc.Container, box s "$bin = Join-Path %s %s; New-Item -ItemType Directory -Force -Path $bin | Out-Null; "+ "Set-Content -Path (Join-Path $bin 'java.cmd') -Value %s", eaDir, pwshQuote(`java-`+ea+`\bin`), pwshQuote("@echo "+ea)), box.vars...) - identifier := common.EarlyAccessIdentifier(distribution, version) - out := legacyJava(ctx, t, ctr, box, identifier) - require.Containsf(t, out, ea, ".sdkmanrc java=%s must select %s, not %s", identifier, ea, installed) - t.Logf("PASS .sdkmanrc java=%s selects %s, not %s", identifier, ea, installed) + // ParseLegacyFile could not parse the installed name, so it selected + // nothing for it, while `vfox use` selects it (vfox-java#91). + for _, identifier := range []string{common.EarlyAccessIdentifier(distribution, version), ea} { + out := legacyJava(ctx, t, ctr, box, identifier) + require.Containsf(t, out, ea, ".sdkmanrc java=%s must select %s, not %s", identifier, ea, installed) + t.Logf("PASS .sdkmanrc java=%s selects %s, not %s", identifier, ea, installed) + } execOK(ctx, t, ctr, fmt.Sprintf("Remove-Item -LiteralPath %s -Recurse -Force", eaDir), box.vars...) } diff --git a/tests/parse_legacy_file_test.lua b/tests/parse_legacy_file_test.lua index 993d341..94b3e5d 100644 --- a/tests/parse_legacy_file_test.lua +++ b/tests/parse_legacy_file_test.lua @@ -112,6 +112,14 @@ local cases = { -- Never a release for an early-access build, nor the other way round. { "java=28.0.0.0+ea.19-open\n", { "28+36", "28.0.1+3" }, nil }, { "java=28.0.0+36-open\n", { "28-ea+19" }, nil }, + -- The installed name of an early-access build selects it, as in vfox use, + -- although parse_version cannot read it (vfox-java#91). Not installed, it + -- selects nothing, as vfox use reports it not installed. + { "java=28-ea+19\n", { "21.0.8+9-tem", "28-ea+19", "28-ea+18-zulu" }, "28-ea+19" }, + { "java=28-ea+18-zulu\n", { "21.0.8+9-tem", "28-ea+19", "28-ea+18-zulu" }, "28-ea+18-zulu" }, + { "java=28-ea+19-zulu-fx\n", { "28-ea+19-zulu", "28-ea+19-zulu-fx" }, "28-ea+19-zulu-fx" }, + { "java=26-ea+13-graal\n", { "26-ea+2-graal", "26-ea+13-graal" }, "26-ea+13-graal" }, + { "java=28-ea+20\n", { "28-ea+18", "28-ea+19" }, nil }, -- No java line at all selects nothing. { "maven=3.9.9\n", { "21.0.8+9-tem" }, nil }, }