Skip to content

Commit f4a09e5

Browse files
committed
Simplify and fix ibm-semeru version handling
Instead of allowing version components to be strings, remove the specific strings. The only strings that actually appear are '_openj9-' and '-m2'. I don't know what -m2 means but openj9 is definitely not a version element. Normalize to all numbers, taking into account that '.' binds more strongly than '+' (presumably) -- so zero-pad to 4 elements before the '+'. Version strings containing _openj9- but not containing '+' are skipped as invalid. (Assisted by Claude Code; any errors are mine.)
1 parent 407a700 commit f4a09e5

2 files changed

Lines changed: 37 additions & 41 deletions

File tree

src/cjdk/_index.py

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,10 @@ def _normalize_version(
196196
ver: str, *, remove_prefix_1: bool = False
197197
) -> tuple[int | str, ...]:
198198
# Normalize requested version and candidates:
199-
# - Split at dots and dashes (so we don't distinguish between '.' and '-')
200-
# - Try to convert elements to integers (so that we can compare elements
201-
# numerically where feasible)
199+
# - Handle _openj9- as a plain separator (for ibm-semeru-openj9-java*
200+
# versions); also handle -m2 suffix
201+
# - Split at dots, dashes, plus signs, and underscores
202+
# - Convert elements to integers (raise ValueError if not possible)
202203
# - If remove_prefix_1 and first element is 1, remove it (so JDK 1.8 == 8)
203204
# - Return as a tuple (so that we compare element by element)
204205
# - Trailing zero elements are NOT removed, so, e.g., 11 < 11.0 (for the
@@ -208,24 +209,38 @@ def _normalize_version(
208209
is_plus = ver.endswith("+")
209210
if is_plus:
210211
ver = ver[:-1]
212+
plus = ("+",) if is_plus else ()
213+
214+
if "_openj9-" in ver:
215+
# ibm-semeru-openj9-java* version numbers have a variable number of
216+
# '.'-separated numbers before the '+'. Pad so that comparisons work.
217+
first, second = ver.split("+", 1)
218+
nfirst = _normalize_version(first, remove_prefix_1=remove_prefix_1)
219+
while len(nfirst) < 4:
220+
nfirst = nfirst + (0,)
221+
nsecond = _normalize_version(
222+
second.replace("-m", "-").replace("_openj9-", "-")
223+
)
224+
return nfirst + nsecond + plus
225+
211226
if ver:
212-
norm = tuple(re.split(_VER_SEPS, ver))
213-
norm = tuple(_intify(e) for e in norm)
227+
parts = re.split(_VER_SEPS, ver)
228+
norm = []
229+
for part in parts:
230+
try:
231+
norm.append(int(part))
232+
except ValueError:
233+
raise ValueError(
234+
f"Non-integer element '{part}' in version"
235+
) from None
236+
norm = tuple(norm)
214237
else:
215238
norm = ()
216-
plus = ("+",) if is_plus else ()
217239
if remove_prefix_1 and len(norm) and norm[0] == 1:
218240
return norm[1:] + plus
219241
return norm + plus
220242

221243

222-
def _intify(s: str) -> int | str:
223-
try:
224-
return int(s)
225-
except ValueError:
226-
return s
227-
228-
229244
def _is_version_compatible_with_spec(
230245
version: tuple[int | str, ...], spec: tuple[int | str, ...]
231246
) -> bool:
@@ -243,25 +258,6 @@ def _is_version_compatible_with_spec(
243258
return len(version) >= len(spec) and version[: len(spec)] == spec
244259

245260

246-
class _VersionElement:
247-
"""Wrapper for version tuple elements enabling mixed int/str comparison."""
248-
249-
def __init__(self, value: int | str) -> None:
250-
self.value = value
251-
252-
def __eq__(self, other: object) -> bool:
253-
if not isinstance(other, _VersionElement):
254-
return NotImplemented
255-
if isinstance(self.value, int) and isinstance(other.value, int):
256-
return self.value == other.value
257-
return str(self.value) == str(other.value)
258-
259-
def __lt__(self, other: _VersionElement) -> bool:
260-
if isinstance(self.value, int) and isinstance(other.value, int):
261-
return self.value < other.value
262-
return str(self.value) < str(other.value)
263-
264-
265261
def matching_jdk_versions(index: Index, conf: Configuration) -> list[str]:
266262
"""
267263
Return all version strings matching the configuration, sorted by version.
@@ -274,10 +270,4 @@ def matching_jdk_versions(index: Index, conf: Configuration) -> list[str]:
274270
if not versions:
275271
return []
276272
matched = _match_versions(conf.vendor, versions, conf.version)
277-
278-
def version_sort_key(
279-
item: tuple[tuple[int | str, ...], str],
280-
) -> tuple[_VersionElement, ...]:
281-
return tuple(_VersionElement(e) for e in item[0])
282-
283-
return [v for _, v in sorted(matched.items(), key=version_sort_key)]
273+
return [v for _, v in sorted(matched.items())]

tests/test_index.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,14 @@ def test_normalize_version():
210210
assert f("1", remove_prefix_1=True) == ()
211211
assert f("1.8", remove_prefix_1=True) == (8,)
212212
assert f("1.8.0", remove_prefix_1=True) == (8, 0)
213-
assert f("1.8u300", remove_prefix_1=True) == ("8u300",)
214-
assert f("21.0.1+12_openj9-0.42.0") == (21, 0, 1, 12, "openj9", 0, 42, 0)
213+
assert f("17.0.4.1+1_openj9-0.33.1") == (17, 0, 4, 1, 1, 0, 33, 1)
214+
assert f("21.0.1+12_openj9-0.42.0") == (21, 0, 1, 0, 12, 0, 42, 0)
215+
assert f("23+37_openj9-0.47.0.0.0") == (23, 0, 0, 0, 37, 0, 47, 0, 0, 0)
216+
assert f("23.0.1+11_openj9-0.49.0-m2") == (23, 0, 1, 0, 11, 0, 49, 0, 2)
217+
with pytest.raises(ValueError):
218+
f("23.4.5_openj9-42") # No '+' despite having _openj9-
219+
with pytest.raises(ValueError):
220+
f("1.8u300") # No longer seen in index
215221

216222

217223
def test_is_version_compatible_with_spec():

0 commit comments

Comments
 (0)