Skip to content

Commit d740f7f

Browse files
committed
fix: match zero-padded versions in vfox use to the installed version
1 parent bfcdbcc commit d740f7f

8 files changed

Lines changed: 107 additions & 8 deletions

File tree

‎docs/e2e.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ JDK, so `java` can only come from what vfox installs:
109109
build number `PreUse` finds among the installed versions) and the
110110
asdf-style `<long-name>-<version>[-fx]` (`java@temurin-21.0.8+9`,
111111
rewritten to `21.0.8+9-tem`; `java@openjdk-25.0.2+10` to `25.0.2+10`).
112+
So does the release padded with a zero, as SDKMAN writes releases
113+
(`java@21.0.8.0-tem`, `java@21.0.8.0+9-tem`), which `vfox install` must
114+
first find already installed: `PreInstall` passes the zero on to Foojay,
115+
which leaves it out, while `PreUse` looked for an installed version
116+
starting with the padded release and reported it not installed.
112117

113118
The default matrix runs every distribution against both vfox channels
114119
(`latest`, `main`):

‎hooks/parse_legacy_file.lua‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,7 @@ function PLUGIN:ParseLegacyFile(ctx)
7575

7676
--- SDKMAN pads the release with zeros that Foojay, and so the installed
7777
--- name, leaves out: 27.0.0+36 is 27+36, 25.0.1.0+8 is 25.0.1+8.
78-
local version, build = fullVersion:match("^([^+]*)(.*)$")
79-
while version:find("%.0$") do
80-
version = version:sub(1, -3)
81-
end
78+
local version, build = installed_version.unpad(fullVersion):match("^([^+]*)(.*)$")
8279
local majorVersion = strings.split(version, ".")[1]
8380

8481
--- Installed versions end in -<vendor> (OpenJDK's in nothing), then -fx for

‎lib/installed_version.lua‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,24 @@ function installed_version.major(installed, major, suffix)
8282
return installed_version.newest(installed, major, "^[.+][%d.+]*$", suffix) or installed[name] and name
8383
end
8484

85+
--- Returns a Java version without the zeros SDKMAN pads releases with, which
86+
--- Foojay, and so the installed name, leaves out even when asked for them:
87+
--- 27.0.0+36 is 27+36, 25.0.1.0 is 25.0.1.
88+
function installed_version.unpad(version)
89+
local release, build = version:match("^([^+]*)(.*)$")
90+
while release:find("%.0$") do
91+
release = release:sub(1, -3)
92+
end
93+
return release .. build
94+
end
95+
8596
--- Returns the installed version that version .. suffix names, or nil. The
8697
--- input may leave out the build number PreInstall found, so, like PreInstall,
8798
--- take the newest build of a release (21.0.8-tem selects 21.0.8+9-tem) and
8899
--- the newest release of a bare major (21-tem selects 21.0.12.1+1-tem), unless
89-
--- the name itself is installed.
100+
--- the name itself is installed. It may also pad the release with zeros, which
101+
--- PreInstall passes on to Foojay: 27.0.0-librca installs, and so selects, the
102+
--- release 27 (27+36-librca), not the newest one of the major.
90103
function installed_version.find(installed, version, suffix)
91104
local name = version .. suffix
92105
if installed[name] then
@@ -95,7 +108,7 @@ function installed_version.find(installed, version, suffix)
95108
if version:match("^%d+$") then
96109
return installed_version.major(installed, version, suffix)
97110
end
98-
return installed_version.release(installed, version, suffix)
111+
return installed_version.release(installed, installed_version.unpad(version), suffix)
99112
end
100113

101114
return installed_version

‎tests/e2e/common/common.go‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,21 @@ func Alias(distribution, installed string) (string, bool) {
352352
return alias, true
353353
}
354354

355+
// PaddedSpecs renders the pinned release padded with a zero, as SDKMAN
356+
// writes releases (27.0.0-librca, 25.0.1.0-open), in the plugin's spelling:
357+
// "<version>.0[-<distribution>]" and, when the installed version has a
358+
// build number, "<version>.0+<build>[-<distribution>]" (21.0.8.0-tem,
359+
// 21.0.8.0+9-tem). PreInstall passes the zero on to Foojay, which leaves it
360+
// out, so both install the pinned JDK, but PreUse looked for an installed
361+
// version starting with the padded release and found none (vfox-java#87).
362+
func PaddedSpecs(distribution, version, installed string) []string {
363+
specs := []string{Spec(distribution, version+".0")}
364+
if build := buildNumber.FindString(installed); build != "" {
365+
specs = append(specs, Spec(distribution, version+".0"+build))
366+
}
367+
return specs
368+
}
369+
355370
// Vendor returns the java.vendor property the distribution's builds report,
356371
// when the suite knows it.
357372
func Vendor(distribution string) (string, bool) {

‎tests/e2e/common/common_test.go‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package common
1616

1717
import (
18+
"slices"
1819
"testing"
1920
)
2021

@@ -261,6 +262,24 @@ func TestAlias(t *testing.T) {
261262
}
262263
}
263264

265+
func TestPaddedSpecs(t *testing.T) {
266+
for _, c := range []struct {
267+
dist, version, installed string
268+
want []string
269+
}{
270+
{"open", "25.0.2", "25.0.2+10", []string{"25.0.2.0", "25.0.2.0+10"}},
271+
{"tem", "21.0.8", "21.0.8+9-tem", []string{"21.0.8.0-tem", "21.0.8.0+9-tem"}},
272+
{"librca-fx", "25.0.4", "25.0.4+9-librca-fx", []string{"25.0.4.0-librca-fx", "25.0.4.0+9-librca-fx"}},
273+
{"jb", "21.0.5", "21.0.5+79248-jb", []string{"21.0.5.0-jb", "21.0.5.0+79248-jb"}},
274+
// GraalVM's versions carry no build number.
275+
{"graalce", "25.0.2", "25.0.2-graalce", []string{"25.0.2.0-graalce"}},
276+
} {
277+
if got := PaddedSpecs(c.dist, c.version, c.installed); !slices.Equal(got, c.want) {
278+
t.Errorf("PaddedSpecs(%s, %s, %s) = %q, want %q", c.dist, c.version, c.installed, got, c.want)
279+
}
280+
}
281+
}
282+
264283
func TestDistributionFacts(t *testing.T) {
265284
if v, ok := Vendor("librca-fx"); !ok || v != "BellSoft" {
266285
t.Errorf("Vendor(librca-fx) = %q, %v", v, ok)

‎tests/e2e/linux/verify.go‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,10 @@ func verifyToolchain(ctx context.Context, t *testing.T, ctr tc.Container, distri
161161
// build number PreUse finds among the installed versions;
162162
// 3. the asdf-style <long-name>-<version>[-fx] spelling (e.g.
163163
// java@temurin-21.0.8+9), which PreUse rewrites to <version>-<short>
164-
// (<version> for OpenJDK, installed without a suffix).
164+
// (<version> for OpenJDK, installed without a suffix);
165+
// 4. the release padded with a zero, as SDKMAN writes releases (e.g.
166+
// java@21.0.8.0-tem, java@21.0.8.0+9-tem, see common.PaddedSpecs),
167+
// which `vfox install` must first find already installed.
165168
//
166169
// After each `vfox use`, java on PATH must still be the installed JDK.
167170
func verifyPreUse(ctx context.Context, t *testing.T, ctr tc.Container, distribution, version, installed string) {
@@ -170,6 +173,16 @@ func verifyPreUse(ctx context.Context, t *testing.T, ctr tc.Container, distribut
170173
if alias, ok := common.Alias(distribution, installed); ok {
171174
spellings = append(spellings, alias)
172175
}
176+
// Foojay leaves the zero out, so PreInstall names the installed JDK and
177+
// vfox downloads nothing.
178+
padded := common.PaddedSpecs(distribution, version, installed)
179+
for _, spec := range padded {
180+
out := execRetry(ctx, t, ctr, "vfox install java@"+spec, "vfox install java@"+spec)
181+
require.Containsf(t, common.StripANSI(out), "java@"+installed+" is already installed",
182+
"vfox install java@%s must find the installed %s", spec, installed)
183+
}
184+
t.Logf("PASS vfox install java@%s finds %s installed", strings.Join(padded, ", java@"), installed)
185+
spellings = append(spellings, padded...)
173186
for _, spelling := range spellings {
174187
out := execOK(ctx, t, ctr, activated("vfox use --global java@"+spelling))
175188
require.Containsf(t, common.StripANSI(out), "Now using java@"+installed+".",

‎tests/e2e/windows/verify.go‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,10 @@ func verifyToolchain(ctx context.Context, t *testing.T, ctr tc.Container, box sl
174174
// build number PreUse finds among the installed versions;
175175
// 3. the asdf-style <long-name>-<version>[-fx] spelling (e.g.
176176
// java@temurin-21.0.8+9), which PreUse rewrites to <version>-<short>
177-
// (<version> for OpenJDK, installed without a suffix).
177+
// (<version> for OpenJDK, installed without a suffix);
178+
// 4. the release padded with a zero, as SDKMAN writes releases (e.g.
179+
// java@21.0.8.0-tem, java@21.0.8.0+9-tem, see common.PaddedSpecs),
180+
// which `vfox install` must first find already installed.
178181
//
179182
// After each `vfox use`, java on PATH must still be the installed JDK.
180183
func verifyPreUse(ctx context.Context, t *testing.T, ctr tc.Container, box slotBox, activation, distribution, version, installed string) {
@@ -183,6 +186,16 @@ func verifyPreUse(ctx context.Context, t *testing.T, ctr tc.Container, box slotB
183186
if alias, ok := common.Alias(distribution, installed); ok {
184187
spellings = append(spellings, alias)
185188
}
189+
// Foojay leaves the zero out, so PreInstall names the installed JDK and
190+
// vfox downloads nothing.
191+
padded := common.PaddedSpecs(distribution, version, installed)
192+
for _, spec := range padded {
193+
out := execRetry(ctx, t, ctr, "vfox install java@"+spec, "vfox install "+pwshQuote("java@"+spec), box.vars...)
194+
require.Containsf(t, common.StripANSI(out), "java@"+installed+" is already installed",
195+
"vfox install java@%s must find the installed %s", spec, installed)
196+
}
197+
t.Logf("PASS vfox install java@%s finds %s installed", strings.Join(padded, ", java@"), installed)
198+
spellings = append(spellings, padded...)
186199
for _, spelling := range spellings {
187200
out := execOK(ctx, t, ctr, activated(activation, "vfox use --global "+pwshQuote("java@"+spelling)), box.vars...)
188201
require.Containsf(t, common.StripANSI(out), "Now using java@"+installed+".",

‎tests/pre_use_test.lua‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ for _, version in ipairs({
2525
"21.0.12.1+1-tem",
2626
"25.0.4+9-librca",
2727
"25.0.4+9-librca-fx",
28+
"27+36-librca",
29+
"27+36-librca-fx",
2830
"21.0.5+63130-jb",
2931
"21.0.5+79248-jb",
3032
"17.0.12-graal",
@@ -34,6 +36,7 @@ for _, version in ipairs({
3436
"21.0.12+8-lnxabi2-fx",
3537
-- OpenJDK versions carry no distribution suffix.
3638
"25.0.2+10",
39+
"25.0.1+8",
3740
"21+35",
3841
"21.0.2+13",
3942
"28-ea+18",
@@ -89,6 +92,27 @@ local cases = {
8992
{ "25.0.2-open-fx", "25.0.2-fx" },
9093
{ "17-open", "17" },
9194
{ "28-open", "28" },
95+
-- A release padded with zeros, as SDKMAN writes it, selects what PreInstall
96+
-- installs for it, as Foojay leaves the zeros out (vfox-java#87): that
97+
-- release, not the newest one of its major (21.0.0-open is 21+35).
98+
{ "27.0.0-librca", "27+36-librca" },
99+
{ "27.0.0+36-librca", "27+36-librca" },
100+
{ "27.0-librca", "27+36-librca" },
101+
{ "27.0.0-librca-fx", "27+36-librca-fx" },
102+
{ "liberica-27.0.0+36-fx", "27+36-librca-fx" },
103+
{ "21.0.8.0-tem", "21.0.8+9-tem" },
104+
{ "21.0.8.0+9-tem", "21.0.8+9-tem" },
105+
{ "21.0.12.0-tem", "21.0.12+8-tem" },
106+
{ "17.0.12.0-graal", "17.0.12-graal" },
107+
{ "25.0.1.0-open", "25.0.1+8" },
108+
{ "25.0.1.0", "25.0.1+8" },
109+
{ "openjdk-25.0.1.0+8", "25.0.1+8" },
110+
{ "21.0.0-open", "21+35" },
111+
{ "21.0.0", "21+35" },
112+
-- Padded or not, never another build or an EA build.
113+
{ "21.0.8.0+7-tem", "21.0.8.0+7-tem" },
114+
{ "27.0.0+35-librca", "27.0.0+35-librca" },
115+
{ "26.0.0-graal", "26.0.0-graal" },
92116
}
93117
for _, case in ipairs(cases) do
94118
local result = PLUGIN:PreUse({ version = case[1], installedSdks = installed })

0 commit comments

Comments
 (0)