From bbd01af89a5b617f47f098ad719b2fa67c824687 Mon Sep 17 00:00:00 2001 From: Qiheng He Date: Tue, 20 Oct 2026 23:09:43 +0800 Subject: [PATCH] fix: install Mandrel and Liberica NIK by their own versions, which Foojay now gives as distribution_version --- docs/changes.md | 1 + docs/development.md | 7 +- docs/distributions.md | 14 ++- docs/e2e.md | 13 +- docs/foojay.md | 25 +++- docs/javafx.md | 4 +- docs/platforms.md | 2 +- docs/troubleshooting.md | 3 +- docs/versions.md | 6 +- docs/zh-CN/changes.md | 1 + docs/zh-CN/development.md | 7 +- docs/zh-CN/distributions.md | 14 ++- docs/zh-CN/e2e.md | 4 +- docs/zh-CN/foojay.md | 25 +++- docs/zh-CN/javafx.md | 4 +- docs/zh-CN/platforms.md | 2 +- docs/zh-CN/troubleshooting.md | 3 +- docs/zh-CN/versions.md | 6 +- hooks/available.lua | 9 +- lib/foojay.lua | 59 +++++++++ lib/installed_version.lua | 4 +- tests/e2e/common/common.go | 66 ++++++++++ tests/e2e/common/common_test.go | 53 ++++++++ tests/e2e/linux/e2e_test.go | 3 + tests/e2e/linux/setup.go | 34 ++++++ tests/e2e/windows/e2e_test.go | 3 + tests/e2e/windows/setup.go | 36 ++++++ tests/pre_install_test.lua | 206 ++++++++++++++++++++++++++++++-- 28 files changed, 565 insertions(+), 49 deletions(-) diff --git a/docs/changes.md b/docs/changes.md index f17ea10..d4428a2 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -7,6 +7,7 @@ What changed in each release, as a user notices it. GitHub's release pages list ## Unreleased - 13 more distributions, the rest of what Foojay lists: AdoptOpenJDK (`adpt`, `adptj9`), Eliya (`eliya`), OJDKBuild (`ojdkbld`), OpenLogic (`opnlgc`), Red Hat (`rdht`), Semeru certified (`semcrt`), Gluon GraalVM (`gln`) and GraalVM CE for JDK 8 to 19 (`grl8`, `grl11`, `grl16`, `grl17`, `grl19`). Red Hat installs from tar.xz, and OJDKBuild on Linux, OpenLogic on macOS and Gluon GraalVM before 22.1 from zips. A `.sdkmanrc` takes SDKMAN's old identifiers for them, such as `11.0.10.j9-adpt` and `22.3.3.r17-grl`. See [distributions.md](distributions.md). +- Mandrel and Liberica NIK install by the GraalVM version they carry again: `java@23.1.12-mandrel` and `java@23.1.8-nik` work, `vfox search java mandrel` lists every release, and `java@23-mandrel` installs the newest 23.x, `23.1.12.1-mandrel`, which runs Java 21. In October 2026 Foojay moved that version from `java_version` to `distribution_version`, and since then release 0.6.2 fails on such versions with `No JDK found`, lists one Mandrel per Java major and installs Mandrel 23.1.8 for `java@21-mandrel`. Installs it made since then keep names after the Java version (`21-mandrel`, `21.0.12.1+2-nik`), and vfox still finds them by those names; uninstall one to get what the spec means now. See [distributions.md](distributions.md#behavior-of-mandrel-and-liberica-nik) ([#106](https://github.com/version-fox/vfox-java/issues/106)). - The notes printed by `vfox add java`, `vfox update java` and `vfox info java` are a link to the README, which lists every short name and shows how to search a distribution. Release 0.6.2 gives five short names there but not how to list their versions, while `vfox search java` lists OpenJDK only ([vfox#390](https://github.com/version-fox/vfox/issues/390)). ## 0.6.2 (2026-10-18) diff --git a/docs/development.md b/docs/development.md index 5897cbd..b9578a6 100644 --- a/docs/development.md +++ b/docs/development.md @@ -44,7 +44,7 @@ A few contracts that cost time to find: ## Names -Installed names are `[-][-fx]`, with no short name for OpenJDK ([versions.md](versions.md#installed-names)). `lib/distribution_version.lua` reads a spec into a version, a distribution and the JavaFX flag, in either order (`21-tem`, `tem-21`). `lib/installed_version.lua` turns a version the user typed into an installed name: the name itself first. A bare major then takes the newest installed release of it, and any other version takes the release itself or its newest build. `PreUse` stops there. `ParseLegacyFile` goes one step further and falls back to the newest installed release of the major. +Installed names are `[-][-fx]`, with no short name for OpenJDK and Foojay's `distribution_version` in place of `java_version` for Mandrel and Liberica NIK ([versions.md](versions.md#installed-names)). `lib/distribution_version.lua` reads a spec into a version, a distribution and the JavaFX flag, in either order (`21-tem`, `tem-21`). `lib/installed_version.lua` turns a version the user typed into an installed name: the name itself first. A bare major then takes the newest installed release of it, and any other version takes the release itself or its newest build. `PreUse` stops there. `ParseLegacyFile` goes one step further and falls back to the newest installed release of the major. SDKMAN spells some things differently (`jbr`, `21.0.12.fx-zulu`, `21.0.12-fx+1.1-librca`, `28.0.0+ea.19-open`), and `plugin_spelling` in `hooks/parse_legacy_file.lua` rewrites them into the plugin's before parsing. For the distributions SDKMAN no longer lists, `sdkman_flavours` there turns the virtual machine or JDK in SDKMAN's version into the short name (`22.3.3.r17-grl` is `22.3.3-grl17`). `installed_version.unpad` drops the zeros SDKMAN pads releases with (`27.0.0+36` is `27+36`). Where the short names differ from SDKMAN's is in [distributions.md](distributions.md#short-names-and-sdkman). @@ -54,9 +54,10 @@ SDKMAN spells some things differently (`jbr`, `21.0.12.fx-zulu`, `21.0.12-fx+1.1 - `version=21` is the GA build `21+35`. A bare major adds `latest=available` to get the newest 21.x. - Windows asks for `zip` and `tar.gz` in one request. JetBrains Runtime ships Windows zips for its newer builds only. `PreInstall` takes the zip when a version has both. - Elsewhere `other_archive_type` in `lib/foojay.lua` adds one archive type for the distributions that ship no tar.gz there for some or all releases: `tar.xz` for Red Hat, `zip` for OJDKBuild, OpenLogic and Gluon GraalVM. vfox unpacks both, and the zips carry their Unix permissions, so `bin/java` stays executable. +- `own_numbers` in `lib/foojay.lua` holds Mandrel and Liberica NIK, which carry the GraalVM version they are built from. Foojay gives it as `distribution_version` and the Java version as `java_version`, for Mandrel the major only, so these two are asked for with `distribution_version` and an empty `version`. Foojay matches the numbers given (`23.1.12` lists 23.1.12.1 too), so a longer version keeps only its own release, and a bare major takes the newest itself, as `latest=available` picks an older one for them. The answer is sorted newest first, then by the newest Java for a release that comes for several, then by BellSoft's later build for the same Java, which only the file name carries. `distribution_version` then goes into `java_version`, so the hooks name and list them like the rest. - `fixes` in `lib/foojay.lua` drops packages before the hooks see them: the JREs, installer bundles and RHEL 6 builds that Foojay lists among OJDKBuild's Windows JDKs, and the JDK 11 builds of Gluon GraalVM's 22.x releases, which share their version with the JDK 17 ones. For a bare major `latest=available` answers with one package per archive type, which can be one the fix drops, so for these two the plugin then asks for that release in full. - `Available` lists a name once where Foojay has two records for it. -- Foojay marks GraalVM's monthly feature releases (`25.1.3` and on) as LTS. `is_feature_release` in `lib/distribution_version.lua` recognises them, by the minor number, and `Available` drops the note. It is for `graal` and `graalce` only: Mandrel and Liberica NIK numbered their releases after themselves up to 24 (`mandrel` `23.1.12` is LTS) and follow the JDK from 25 on. +- Foojay marks GraalVM's monthly feature releases (`25.1.3` and on) as LTS. `is_feature_release` in `lib/distribution_version.lua` recognises them, by the minor number, and `Available` drops the note. It is for `graal` and `graalce` only: Mandrel and Liberica NIK carry GraalVM's older numbers up to 24, whose minor is no feature release (`mandrel` `23.1.12` is LTS), and the JDK's from 25 on. - For a bare major of Oracle GraalVM (`graal`) only, `PreInstall` skips the feature releases, so the 25.0 line is installed. A major that has nothing but feature releases keeps them. GraalVM Community is not filtered, because its feature releases are what it still ships. - The CPU names are `arm64` to `aarch64`, and on Windows `amd64` to `x64`. `darwin` becomes `macos`. On Linux `ldd --version` decides between glibc and musl. @@ -126,7 +127,7 @@ The ids are Foojay's (`oracle_open_jdk` is `open`). It prints `redhat` for Linux - Downloads are not verified, see above. - `vfox search` lists GA releases only. Early-access builds install by name. -- JRE packages are not offered, and neither are the JDK 11 builds of Gluon GraalVM's 22.x releases. +- JRE packages are not offered, and neither are the JDK 11 builds of Gluon GraalVM's 22.x releases. Of a Mandrel or Liberica NIK release only the build for its newest Java installs, so Mandrel 21.3.6 for Java 11 does not. - Only Linux loong64 has a source besides Foojay. ## Releasing diff --git a/docs/distributions.md b/docs/distributions.md index fd925a4..32f0f7e 100644 --- a/docs/distributions.md +++ b/docs/distributions.md @@ -138,13 +138,19 @@ The open-source edition of GraalVM, built on OpenJDK. ### Liberica Native Image Kit (`nik`) -[BellSoft's](https://bell-sw.com/) distribution for building native images, based on GraalVM. Java 21 to 25, with `-fx` builds on some platforms. +[BellSoft's](https://bell-sw.com/) distribution for building native images, based on GraalVM. Releases 21 to 25, which run Java 11, 17 and 20 to 25, with `-fx` builds on some platforms. ### Mandrel (`mandrel`) -[Red Hat's](https://github.com/graalvm/mandrel) distribution for building Quarkus native executables, which concentrates on `native-image`. +[Red Hat's](https://github.com/graalvm/mandrel) distribution for building Quarkus native executables, which concentrates on `native-image`. Releases 20.3 to 25, which run Java 11, 17 and 20 to 25. -Mandrel and Liberica NIK numbered their releases after themselves up to version 24 (Mandrel `23.1.12`), and number them after the JDK from 25 on (`25.0.4.1`). +### Behavior of Mandrel and Liberica NIK + +- Both carry the version of the GraalVM they are built from, and their installs are named after it: `23.1.12.1-mandrel`, `23.1.8-nik`. Up to 24 that is not the Java version. 23.1 runs Java 21, 24.0 Java 22, 24.1 Java 23 and 24.2 Java 24, and older releases run Java 11, 17 or 20. From 25 on the two agree (`25.0.4.1`). +- A bare major is GraalVM's as well: `java@23-mandrel` installs the newest 23.x, `23.1.12.1-mandrel`, which runs Java 21, and `java@21-mandrel` installs `21.3.6-mandrel`, which runs Java 17. A longer version installs the release it names: `java@23.1.12-mandrel` is 23.1.12, not 23.1.12.1, and `java@23.1-mandrel` is the first 23.1 release, 23.1.0. A build number finds nothing (`java@23.1.8+1-nik`). +- The releases ending in `.0.0` are listed under the bare major (`24-mandrel` is Mandrel 24.0.0) and install with a longer version, `java@24.0.0-mandrel`. Once one is installed, vfox finds `java@24-mandrel` by that name, for `vfox install` and `vfox use` alike. +- Some releases come for several Java versions under one number, such as Mandrel 21.3.6 for Java 11 and 17. The plugin installs the build for the newest Java, which for Mandrel 23.0.1.2 and Liberica NIK 23.0.1 is Java 20, not 17. Liberica NIK built a few releases twice for the same Java (`25.0.3`), and the later build installs. The name shows neither the Java version nor BellSoft's build, so the other builds cannot be installed. +- Unreleased: release 0.6.2 names them after Foojay's `java_version`, which held these numbers until Foojay put the Java version there in October 2026. Since then 0.6.2 fails on `java@23.1.12-mandrel` and `java@23.1.8-nik` with `No JDK found`, lists Mandrel in `vfox search` as one name per Java major (`21-mandrel`), installs Mandrel 23.1.8 for `java@21-mandrel` and Liberica NIK 24.1.2, built for Java 23, for `java@23-nik`. ### GraalVM CE 8 to 19 (`grl8`, `grl11`, `grl16`, `grl17`, `grl19`) @@ -156,7 +162,7 @@ GraalVM Community Edition up to 22.3, from before it numbered its releases after ### Versions numbered after GraalVM -GraalVM CE 8 to 19, and Gluon GraalVM before 23, carry GraalVM's version numbers, not Java's: `22.3.3-grl17` is GraalVM 22.3.3 and runs Java 17.0.8, and `21.3.1-grl11` runs Java 11. For a bare major vfox takes the highest installed version that starts with it, from any distribution, so with `21.3.1-grl11` and `21.0.12.1+1-tem` installed, `vfox use java@21` selects `21.3.1-grl11`. Name the distribution, as in `java@21-tem`. +GraalVM CE 8 to 19, Gluon GraalVM before 23, and Mandrel and Liberica NIK before 25 carry GraalVM's version numbers, not Java's: `22.3.3-grl17` is GraalVM 22.3.3 and runs Java 17.0.8, `21.3.1-grl11` runs Java 11, and `23.1.12.1-mandrel` runs Java 21. For a bare major vfox takes the highest installed version that starts with it, from any distribution, so with `21.3.1-grl11` and `21.0.12.1+1-tem` installed, `vfox use java@21` selects `21.3.1-grl11`. Name the distribution, as in `java@21-tem`. ### Behavior of Oracle GraalVM and GraalVM Community diff --git a/docs/e2e.md b/docs/e2e.md index 5ac7f46..504c6ce 100644 --- a/docs/e2e.md +++ b/docs/e2e.md @@ -98,6 +98,17 @@ JDK, so `java` can only come from what vfox installs: already installed, so nothing downloads. Before they had short names, the two failed with `Unsupported distribution` and `Could not extract a valid distribution`. + + On the same rows Mandrel and Liberica NIK go by the GraalVM version they + carry (`ownNumbers` in `tests/e2e/common`; Windows arm64 has neither): + `vfox search java mandrel` lists `23.1.12-mandrel` (`23.1.8-nik` for + Liberica NIK), and with it and the newest 23.x the search lists faked as + installed, `vfox install java@mandrel-23.1.12` and + `vfox install java@23-mandrel` report those two as already installed. + Before the plugin read `distribution_version`, where Foojay moved that + version in October 2026, the search listed one name per Java major, + `23.1.12-mandrel` was not found, and `java@23-mandrel` installed Mandrel + 24.1.2, built for Java 23. 5. The pinned release installs under the name `PreInstall` gives it: the requested version plus the build number (`21.0.8-tem` installs as `21.0.8+9-tem`). `vfox search java ` (the `Available` hook) @@ -157,7 +168,7 @@ The default matrix runs every distribution against both vfox channels | Distribution | Release | Covers | amd64 | arm64 | | ------------ | ------- | ---------------------------------------------------------------------------------------- | ----- | ----- | | `open` | 25.0.2 | the default distribution, versions without a suffix | ✓ | | -| `tem` | 21.0.8 | the common path (tar.gz on Linux, zip on Windows); the distributions checked by name | ✓ | ✓ | +| `tem` | 21.0.8 | the common path (tar.gz on Linux, zip on Windows); the name and number checks of item 4 | ✓ | ✓ | | `librca-fx` | 25.0.4 | JavaFX bundled builds (`-fx`) | ✓ | ✓ | | `jb` | 21.0.5 | the tar.gz path on Windows, which has no zip for it | ✓ | ✓ | | `graalce` | 25.0.2 | a `GRAALVM_HOME` set beforehand keeps its value; Oracle GraalVM's `25-graal` | ✓ | | diff --git a/docs/foojay.md b/docs/foojay.md index e94d304..aead521 100644 --- a/docs/foojay.md +++ b/docs/foojay.md @@ -24,20 +24,37 @@ https://api.foojay.io/disco/v3.0/packages/jdks | Parameter | Value | | --- | --- | | `distribution` | the long name, see [distributions.md](distributions.md) | -| `version` | empty for `vfox search`, else the version part of what you typed. A `+` is percent-encoded, because Foojay reads a bare one as a space and drops the build. `28.ea.19` becomes `28-ea+19` | +| `version` | empty for `vfox search`, else the version part of what you typed. A `+` is percent-encoded, because Foojay reads a bare one as a space and drops the build. `28.ea.19` becomes `28-ea+19`. Always empty for Mandrel and Liberica NIK | +| `distribution_version` | for Mandrel and Liberica NIK only, the version part of what you typed, see [below](#mandrel-and-liberica-nik) | | `architecture` | `aarch64` for arm64, `x64` on Windows x64, `amd64` for x64 elsewhere, and the name vfox reports for other CPUs | | `operating_system` | `linux`, `macos` or `windows` | | `archive_type` | `tar.gz`, and `zip` plus `tar.gz` on Windows. Elsewhere `tar.xz` comes in for Red Hat, and `zip` for OJDKBuild, OpenLogic and Gluon GraalVM | | `lib_c_type` | `glibc` or `musl` on Linux, empty elsewhere | | `directly_downloadable` | always `true` | -| `latest` | `available`, added only when the version is a bare major such as `21` | +| `latest` | `available`, added only when the version is a bare major such as `21`, and never for Mandrel and Liberica NIK | Without `latest=available`, `version=21` matches the 21 GA build only (`21+35`). With it Foojay picks the newest 21.x, which is what `java@21-tem` installs. Longer versions match as they are. -The answer is a list of packages. The plugin names a release after `java_version`, adds `-fx` where `javafx_bundled` is true, marks it LTS where `term_of_support` is `lts`, and prefers a `zip` over a `tar.gz` of the same version on Windows. It leaves out the JREs, installer bundles and RHEL 6 builds that Foojay lists among OJDKBuild's Windows JDKs, and the JDK 11 builds of Gluon GraalVM's 22.x releases, see [distributions.md](distributions.md). For the install it then fetches the package's `links.pkg_info_uri` and downloads its `direct_download_uri`, which is a vendor's own server (GitHub Releases for Temurin). That record also holds a `checksum`. The plugin does not pass it on, so vfox prints `WARNING: Checksum is not provided, skip verify...` and does not verify the download. +The answer is a list of packages. The plugin names a release after `java_version` (Mandrel and Liberica NIK after `distribution_version`), adds `-fx` where `javafx_bundled` is true, marks it LTS where `term_of_support` is `lts`, and prefers a `zip` over a `tar.gz` of the same version on Windows. It leaves out the JREs, installer bundles and RHEL 6 builds that Foojay lists among OJDKBuild's Windows JDKs, and the JDK 11 builds of Gluon GraalVM's 22.x releases, see [distributions.md](distributions.md). For the install it then fetches the package's `links.pkg_info_uri` and downloads its `direct_download_uri`, which is a vendor's own server (GitHub Releases for Temurin). That record also holds a `checksum`. The plugin does not pass it on, so vfox prints `WARNING: Checksum is not provided, skip verify...` and does not verify the download. `vfox search` differs from the raw list in a few ways. It lists a name once where Foojay has two records for it, and it leaves the LTS note off GraalVM's feature releases (see [distributions.md](distributions.md#behavior-of-oracle-graalvm-and-graalvm-community)). It only lists GA releases. +### Mandrel and Liberica NIK + +Foojay gives the GraalVM version these two carry as `distribution_version`, and the Java version as `java_version`, for Mandrel the major only (2026-10-20): + +```bash +curl -s 'https://api.foojay.io/disco/v3.0/packages/jdks?distribution=mandrel&distribution_version=23.1.12&architecture=amd64&operating_system=linux&lib_c_type=glibc&archive_type=tar.gz&directly_downloadable=true' \ + | jq -r '.result[] | [.java_version, .distribution_version, .filename] | @tsv' +``` + +``` +21 23.1.12.1 mandrel-java21-linux-amd64-23.1.12.1-Final.tar.gz +21 23.1.12 mandrel-java21-linux-amd64-23.1.12.0-Final.tar.gz +``` + +So the plugin asks for them with `distribution_version` and an empty `version`. Foojay matches the numbers given, which is why `23.1.12` also lists 23.1.12.1, and the plugin keeps only the release named. For a bare major it picks the newest release in the answer itself, as `latest=available` does not: for `distribution_version=23` it answered with 23.1.8 and two builds of 23.0.1.2, although 23.1.12.1 was out. Where a release comes for several Java versions the plugin takes the build for the newest, and of two Liberica NIK builds for the same Java the later one, which only the file name tells apart (`...-25.0.3+2-linux-amd64.tar.gz`). Searching sorts them by `distribution_version`, newest first. + ## Which distributions have a build for my platform `latest=per_distro` returns the newest package of every distribution that has one. Do not combine it with `version`, which it ignores. @@ -105,7 +122,7 @@ curl -s 'https://api.foojay.io/disco/v3.0/packages/jdks?distribution=temurin&ver {"java_version":"21.0.8+9","distribution_version":"21.0.8","term_of_support":"lts","javafx_bundled":false,"archive_type":"tar.gz","filename":"OpenJDK21U-jdk_x64_linux_hotspot_21.0.8_9.tar.gz"} ``` -`java_version` is Java's version and the one the plugin uses. `distribution_version` is the vendor's own (Zulu's `27.28.101` for Java `27+35`). +`java_version` is Java's version and the one the plugin uses. `distribution_version` is the vendor's own (Zulu's `27.28.101` for Java `27+35`), which the plugin uses for Mandrel and Liberica NIK only, see [above](#mandrel-and-liberica-nik). ## Releases and support terms diff --git a/docs/javafx.md b/docs/javafx.md index 0510464..067b853 100644 --- a/docs/javafx.md +++ b/docs/javafx.md @@ -33,13 +33,13 @@ A build with JavaFX lists `javafx.base` and the others, one without lists none. ## Where JavaFX builds exist -As of 2026-10-18 four distributions have them, and not for every platform. The table lists the LTS releases that have a JavaFX build. The releases in between have some too, with gaps. +As of 2026-10-20 four distributions have them, and not for every platform. The table lists the LTS releases that have a JavaFX build. The releases in between have some too, with gaps. For Liberica NIK it gives the Java version, not the GraalVM version in its names (see [distributions.md](distributions.md#behavior-of-mandrel-and-liberica-nik)): its JavaFX builds for Java 21 are `23.1.x-nik-fx`. | Distribution | Linux x64 | Linux arm64 | Alpine x64 | macOS Intel | macOS Apple silicon | Windows x64 | Windows arm64 | | --- | --- | --- | --- | --- | --- | --- | --- | | Zulu (`zulu`) | 8, 11, 17, 21, 25 | 8, 11, 17, 21, 25 | – | 8, 11, 17, 21, 25 | 8, 11, 17, 21, 25 | 8, 11, 17, 21, 25 | – | | Liberica (`librca`) | 8, 11, 17, 21, 25 | 11, 17, 21, 25 | 11 | 8, 11, 17, 21, 25 | 8, 11, 17, 21, 25 | 8, 11, 17, 21, 25 | 11, 17, 21, 25 | | Corretto (`amzn`) | 8 | 8 | – | 8 | – | 8 | – | -| Liberica NIK (`nik`) | 21, 25 | – | – | 25 | 25 | 21, 25 | – | +| Liberica NIK (`nik`) | 11, 17, 21, 25 | – | – | 11, 17, 21, 25 | 11, 17, 21, 25 | 11, 17, 21, 25 | – | Nothing has JavaFX for Alpine arm64. Loongnix has JavaFX builds for LoongArch, selected the same way, see [loongnix.md](loongnix.md). To see the current picture for a platform, add `javafx_bundled=true` to a query like the ones in [foojay.md](foojay.md). diff --git a/docs/platforms.md b/docs/platforms.md index bbbb7c7..30b6192 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -53,7 +53,7 @@ Foojay changes, and the table with it. To get the current one, ask Foojay the wa A ✅ does not mean every release is there. As of the same date: - Windows on ARM64 has no Java 8 from anyone. Temurin has 21 and 23 there, Zulu 16 to 19, 21 and 25, Liberica 11 and 16 to 27, Microsoft 11, 16, 17, 21 and 25, and JetBrains Runtime 17, 21 and 25. -- On Apple silicon Java 8 comes from Zulu, Liberica, Corretto and Kona. Temurin and Semeru have 11 and 17 to 27 there, and OpenJDK 17 to 27. Mandrel has 23 to 25, and Liberica NIK 22 to 25. +- On Apple silicon Java 8 comes from Zulu, Liberica, Corretto and Kona. Temurin and Semeru have 11 and 17 to 27 there, and OpenJDK 17 to 27. Mandrel has releases 23.1 to 25, for Java 21 to 25, and Liberica NIK 22.2 to 25, for Java 11, 17 and 20 to 25 (see [their numbers](distributions.md#behavior-of-mandrel-and-liberica-nik)). - Intel Macs get new releases later or not at all. OpenJDK and Temurin stop at 26 where Linux has 27, SapMachine stops at 24, and Oracle GraalVM and GraalVM Community stop at 25.0.1. Mandrel has no Intel Mac build. - On Alpine, Temurin has arm64 builds from 21 only. For x64, Microsoft has 11 and 17, SapMachine 17 and 20 to 27, Kona 8 and 21, Dragonwell 11, 17, 21 and 25, and JetBrains Runtime 17. Kona has Java 8 for arm64, and JetBrains Runtime 17 for both. - Trava has a single build for Linux arm64, 11.0.10+6. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index a1a637f..d98f4c8 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -66,7 +66,8 @@ While `proxy.enable` is `false`, the usual `HTTP_PROXY`, `HTTPS_PROXY` and `NO_P - **The installed name has a build number you did not type.** `java@21.0.8-tem` installs `21.0.8+9-tem`. The build is part of the name, see [versions.md](versions.md#installed-names). - **`vfox install java@21-tem` and `vfox install java tem` do different things.** The second one is two SDKs, `java` and `tem`. - **A `GRAALVM_HOME` you set is left alone.** The plugin sets `JAVA_HOME` and `PATH` only. -- **`vfox use java@21` selects `21.3.1-grl11`, which runs Java 11.** GraalVM CE 8 to 19 and Gluon GraalVM before 23 carry GraalVM's version numbers, and vfox matches a bare major against those, see [distributions.md](distributions.md#versions-numbered-after-graalvm). Write `java@21-tem`. +- **`vfox use java@21` selects `21.3.1-grl11`, which runs Java 11.** GraalVM CE 8 to 19, Gluon GraalVM before 23, and Mandrel and Liberica NIK before 25 carry GraalVM's version numbers, and vfox matches a bare major against those, see [distributions.md](distributions.md#versions-numbered-after-graalvm). Write `java@21-tem`. +- **`java@21-mandrel` installs a Mandrel that runs Java 17.** Mandrel's and Liberica NIK's majors are GraalVM's: `21.3.6-mandrel` is the newest Mandrel 21.x. Their releases for Java 21 are 23.1.x, so write `java@23-mandrel`, see [distributions.md](distributions.md#behavior-of-mandrel-and-liberica-nik). ## Where the JDK is diff --git a/docs/versions.md b/docs/versions.md index 2e743fb..c1d74e8 100644 --- a/docs/versions.md +++ b/docs/versions.md @@ -29,6 +29,7 @@ The distribution is a short name (`tem`) or a long name (`temurin`). Both lists - A release padded with zeros, as SDKMAN writes it, is accepted: `27.0.0-librca` installs `27+36-librca`. - Oracle GraalVM's bare major installs the newest build of its 25.0 line, not one of the monthly feature releases, which have to be named in full (`25.4.4.1-graal`). See [GraalVM](distributions.md#graalvm-family). - With `-fx` only JavaFX builds are considered, without it only builds without JavaFX. The two are never mixed. +- Mandrel and Liberica NIK go by the GraalVM version they carry, for a bare major too: `java@23-mandrel` installs `23.1.12.1-mandrel`, which runs Java 21. See [Mandrel and Liberica NIK](distributions.md#behavior-of-mandrel-and-liberica-nik). - On Windows a release shipped as zip and as tar.gz installs from the zip. - A distribution without a version (`java@tem`, `java@-tem`, `java@zulu-fx`) is rejected with a message that asks for one. @@ -36,7 +37,7 @@ An install that finds the name already present prints `java@21.0.12.1+1-tem is a ## Installed names -The plugin names an install after the `java_version` that Foojay reports, which is also what `vfox search` prints: +The plugin names an install after the `java_version` that Foojay reports, or the `distribution_version` for Mandrel and Liberica NIK. `vfox search` prints the same names: ``` [-][-fx] @@ -49,6 +50,7 @@ The plugin names an install after the `java_version` that Foojay reports, which | `25.0.2+10` | OpenJDK, no suffix | | `17.0.12-graal` | GraalVM, which has no build number | | `8.0.482+8-zulu` | Java 8 is `8.0.+` | +| `23.1.12.1-mandrel` | Mandrel, numbered after GraalVM: it runs Java 21 | | `28-ea+19` | early-access build, see below | These are the names `vfox list java` shows and `vfox uninstall` needs: @@ -73,7 +75,7 @@ vfox uninstall java@21.0.8+9-tem If you name a build or a release, it does not cross over to another one (`21.0.12-tem` does not select `21.0.12.1+1-tem`). It does not cross to another distribution, between JavaFX and plain, or between early-access and GA either. A name that matches nothing is reported as `java@99-tem is not installed`. -vfox's own match for `21` goes by the version alone, so it also takes GraalVM CE 8 to 19 and Gluon GraalVM, whose versions are GraalVM's: `21.3.1-grl11` runs Java 11, and `vfox use java@21` selects it over `21.0.12.1+1-tem`. See [distributions.md](distributions.md#versions-numbered-after-graalvm). +vfox's own match for `21` goes by the version alone, so it also takes GraalVM CE 8 to 19, Gluon GraalVM, Mandrel and Liberica NIK, whose versions are GraalVM's: `21.3.1-grl11` runs Java 11, and `vfox use java@21` selects it over `21.0.12.1+1-tem`. See [distributions.md](distributions.md#versions-numbered-after-graalvm). Pick the scope with `vfox use`'s flags: `--global`, `--project` or `--session`, the default. In a shell without vfox's hook, Windows switches to the global scope with a warning, while Linux and macOS stop with `vfox requires hook support`. `--project` writes a `.vfox.toml` that holds the installed name (`java = "17.0.10+7-tem"`). A `.sdkmanrc` is read as well, see [sdkmanrc.md](sdkmanrc.md). diff --git a/docs/zh-CN/changes.md b/docs/zh-CN/changes.md index f61f4db..75854bc 100644 --- a/docs/zh-CN/changes.md +++ b/docs/zh-CN/changes.md @@ -7,6 +7,7 @@ ## 未发布 - 新增 13 个发行版,Foojay 列出的发行版从此全都有了:AdoptOpenJDK(`adpt`、`adptj9`)、Eliya(`eliya`)、OJDKBuild(`ojdkbld`)、OpenLogic(`opnlgc`)、Red Hat(`rdht`)、Semeru 认证版(`semcrt`)、Gluon GraalVM(`gln`),以及基于 JDK 8 到 19 的 GraalVM CE(`grl8`、`grl11`、`grl16`、`grl17`、`grl19`)。Red Hat 从 tar.xz 包安装;Linux 上的 OJDKBuild、macOS 上的 OpenLogic 和 22.1 以前的 Gluon GraalVM 从 zip 包安装。`.sdkmanrc` 里写 SDKMAN 以前给它们的标识符也认,例如 `11.0.10.j9-adpt`、`22.3.3.r17-grl`。见 [distributions.md](distributions.md)。 +- Mandrel 和 Liberica NIK 重新按它们沿用的 GraalVM 版本号安装:`java@23.1.12-mandrel` 和 `java@23.1.8-nik` 能装了,`vfox search java mandrel` 列出全部版本,`java@23-mandrel` 装最新的 23.x,即运行 Java 21 的 `23.1.12.1-mandrel`。2026 年 10 月,Foojay 把这个版本号从 `java_version` 挪到了 `distribution_version`,此后 0.6.2 装这样的版本都报 `No JDK found`,每个 Java 大版本只列一个 Mandrel,`java@21-mandrel` 装的是 Mandrel 23.1.8。这段时间里它装上的版本按 Java 版本号命名(`21-mandrel`、`21.0.12.1+2-nik`),vfox 仍会按这些名字找到它们;想要这个写法现在所指的版本,先把旧的卸载。见 [distributions.md](distributions.md#mandrel-与-liberica-nik-的行为)([#106](https://github.com/version-fox/vfox-java/issues/106))。 - `vfox add java`、`vfox update java` 和 `vfox info java` 打印的 Notes 改成了一个 README 链接,README 里列了全部简称,也写了怎样搜索某个发行版。0.6.2 的 Notes 只给了五个简称,没说怎样列出它们的版本,而 `vfox search java` 只列 OpenJDK([vfox#390](https://github.com/version-fox/vfox/issues/390))。 ## 0.6.2(2026-10-18) diff --git a/docs/zh-CN/development.md b/docs/zh-CN/development.md index 799a0fb..9487cb8 100644 --- a/docs/zh-CN/development.md +++ b/docs/zh-CN/development.md @@ -44,7 +44,7 @@ vfox 加载 `metadata.lua`,命令需要时调用相应的钩子,并向钩子 ## 命名 -安装后的版本名是 `[-<简称>][-fx]`,OpenJDK 没有简称([versions.md](versions.md#安装后的版本名))。`lib/distribution_version.lua` 把一个写法解析成版本、发行版和 JavaFX 标志,两种顺序都接受(`21-tem`、`tem-21`)。`lib/installed_version.lua` 把用户输入的版本变成已安装的版本名:先看这个名字本身。只写大版本号时,取这个大版本里已安装的最新版本;其他写法则取这个版本本身,或它的最新构建。`PreUse` 到此为止。`ParseLegacyFile` 还会再退一步,取同一大版本里已安装的最新版本。 +安装后的版本名是 `[-<简称>][-fx]`,OpenJDK 没有简称,Mandrel 和 Liberica NIK 用 Foojay 的 `distribution_version` 代替 `java_version`([versions.md](versions.md#安装后的版本名))。`lib/distribution_version.lua` 把一个写法解析成版本、发行版和 JavaFX 标志,两种顺序都接受(`21-tem`、`tem-21`)。`lib/installed_version.lua` 把用户输入的版本变成已安装的版本名:先看这个名字本身。只写大版本号时,取这个大版本里已安装的最新版本;其他写法则取这个版本本身,或它的最新构建。`PreUse` 到此为止。`ParseLegacyFile` 还会再退一步,取同一大版本里已安装的最新版本。 SDKMAN 有些写法不同(`jbr`、`21.0.12.fx-zulu`、`21.0.12-fx+1.1-librca`、`28.0.0+ea.19-open`),`hooks/parse_legacy_file.lua` 里的 `plugin_spelling` 会在解析之前把它们改写成插件自己的写法。对 SDKMAN 已经不再提供的发行版,同一文件里的 `sdkman_flavours` 把 SDKMAN 写在版本号里的虚拟机或 JDK 版本换成简称(`22.3.3.r17-grl` 就是 `22.3.3-grl17`)。SDKMAN 给版本补的零由 `installed_version.unpad` 去掉(`27.0.0+36` 就是 `27+36`)。简称与 SDKMAN 不同的地方见 [distributions.md](distributions.md#简称与-sdkman-的不同)。 @@ -54,9 +54,10 @@ SDKMAN 有些写法不同(`jbr`、`21.0.12.fx-zulu`、`21.0.12-fx+1.1-librca` - `version=21` 只是 GA 构建 `21+35`。只写大版本号时会加上 `latest=available`,才能拿到最新的 21.x。 - Windows 在同一次请求里同时要 `zip` 和 `tar.gz`。JetBrains Runtime 只为较新的构建提供 Windows 的 zip。同一版本两种都有时,`PreInstall` 取 zip。 - 在其他系统上,有几个发行版的部分或全部版本没有 tar.gz,`lib/foojay.lua` 里的 `other_archive_type` 会为它们多要一种格式:Red Hat 要 `tar.xz`,OJDKBuild、OpenLogic 和 Gluon GraalVM 要 `zip`。这两种 vfox 都能解压,这些 zip 包也带着 Unix 权限,所以 `bin/java` 仍然可以执行。 +- `lib/foojay.lua` 里的 `own_numbers` 列的是 Mandrel 和 Liberica NIK,它们沿用所基于的 GraalVM 的版本号。Foojay 把这个版本号放在 `distribution_version` 里,把 Java 的版本号放在 `java_version` 里(Mandrel 的 `java_version` 只有大版本号),所以查这两个发行版时用 `distribution_version`,`version` 留空。Foojay 按给出的几段数字匹配(查 `23.1.12` 也会返回 23.1.12.1),所以写得更具体的版本,插件只保留与它完全相同的那个;只写大版本号时由插件自己挑最新的,因为 `latest=available` 对它们会挑出旧版本。结果按版本从新到旧排;同一版本有几个 Java 版本的构建时,Java 最新的在前;为同一个 Java 构建了两次时,BellSoft 后一次的构建在前,两次构建只能从文件名区分。之后 `distribution_version` 写进 `java_version`,钩子就能像对其他发行版一样给它们命名、列出它们。 - `lib/foojay.lua` 里的 `fixes` 会在钩子拿到结果之前去掉一些包:Foojay 列在 OJDKBuild 的 Windows JDK 里的 JRE、installer bundle 包和 RHEL 6 构建,以及 Gluon GraalVM 22.x 的 JDK 11 构建,它们和 JDK 17 构建共用一个版本号。只写大版本号时,`latest=available` 每种格式只返回一个包,这个包可能正好是要去掉的,所以对这两个发行版,插件会再按那个版本完整地查一次。 - Foojay 里同一个名字有两条记录时,`Available` 只列一次。 -- Foojay 把 GraalVM 每月发布的特性版本(`25.1.3` 起)标成 LTS。`lib/distribution_version.lua` 里的 `is_feature_release` 按次版本号识别它们,`Available` 去掉它们的备注。它只适用于 `graal` 和 `graalce`:Mandrel 和 Liberica NIK 在 24 及以前按自己的版本号编号(`mandrel` 的 `23.1.12` 就是 LTS),从 25 起沿用 JDK 的编号。 +- Foojay 把 GraalVM 每月发布的特性版本(`25.1.3` 起)标成 LTS。`lib/distribution_version.lua` 里的 `is_feature_release` 按次版本号识别它们,`Available` 去掉它们的备注。它只适用于 `graal` 和 `graalce`:Mandrel 和 Liberica NIK 在 24 及以前沿用 GraalVM 的旧版本号,次版本号并不表示特性版本(`mandrel` 的 `23.1.12` 就是 LTS),从 25 起和 JDK 的版本号一致。 - 只有 Oracle GraalVM(`graal`)在只写大版本号时,`PreInstall` 才会跳过特性版本,所以装的是 25.0 系列。一个大版本里只有特性版本时,则保留它们。GraalVM 社区版不做这个过滤,因为特性版本就是它现在发布的全部。 - CPU 名字:`arm64` 改成 `aarch64`,Windows 上 `amd64` 改成 `x64`;`darwin` 改成 `macos`。在 Linux 上,由 `ldd --version` 决定是 glibc 还是 musl。 @@ -126,7 +127,7 @@ id 是 Foojay 的(`oracle_open_jdk` 对应 `open`)。这段命令在 Linux a - 下载内容没有校验,见上文。 - `vfox search` 只列 GA 版本。EA 构建要自己写出名字来安装。 -- 插件不提供 JRE 包,也不提供 Gluon GraalVM 22.x 的 JDK 11 构建。 +- 插件不提供 JRE 包,也不提供 Gluon GraalVM 22.x 的 JDK 11 构建。Mandrel 和 Liberica NIK 的一个版本只能装 Java 最新的那个构建,所以基于 Java 11 的 Mandrel 21.3.6 装不了。 - 只有 Linux loong64 有 Foojay 以外的来源。 ## 发布 diff --git a/docs/zh-CN/distributions.md b/docs/zh-CN/distributions.md index b874848..71c50a6 100644 --- a/docs/zh-CN/distributions.md +++ b/docs/zh-CN/distributions.md @@ -138,13 +138,19 @@ GraalVM 的开源版本,基于 OpenJDK。 ### Liberica Native Image Kit(`nik`) -[BellSoft](https://bell-sw.com/) 用来构建原生镜像的发行版,基于 GraalVM。覆盖 Java 21 到 25,部分平台有带 `-fx` 的构建。 +[BellSoft](https://bell-sw.com/) 用来构建原生镜像的发行版,基于 GraalVM。版本号从 21 到 25,运行的是 Java 11、17 和 20 到 25,部分平台有带 `-fx` 的构建。 ### Mandrel(`mandrel`) -[Red Hat](https://github.com/graalvm/mandrel) 为构建 Quarkus 原生可执行文件提供的发行版,专注于 `native-image`。 +[Red Hat](https://github.com/graalvm/mandrel) 为构建 Quarkus 原生可执行文件提供的发行版,专注于 `native-image`。版本号从 20.3 到 25,运行的是 Java 11、17 和 20 到 25。 -Mandrel 和 Liberica NIK 在 24 及以前用自己的版本号体系(Mandrel 的 `23.1.12`),从 25 起沿用 JDK 的版本号(`25.0.4.1`)。 +### Mandrel 与 Liberica NIK 的行为 + +- 两者都沿用所基于的 GraalVM 的版本号,安装后的版本名用的也是它:`23.1.12.1-mandrel`、`23.1.8-nik`。到 24 为止,这个版本号和 Java 的版本号对不上:23.1 运行的是 Java 21,24.0 是 Java 22,24.1 是 Java 23,24.2 是 Java 24,更早的版本运行 Java 11、17 或 20。从 25 起两者一致(`25.0.4.1`)。 +- 只写大版本号时,这个大版本号同样是 GraalVM 的:`java@23-mandrel` 装最新的 23.x,即 `23.1.12.1-mandrel`,运行的是 Java 21;`java@21-mandrel` 装的是 `21.3.6-mandrel`,运行的是 Java 17。写得更具体的版本只装它指定的那一个:`java@23.1.12-mandrel` 装的是 23.1.12,不是 23.1.12.1;`java@23.1-mandrel` 装的是 23.1 系列的第一个版本 23.1.0。写了构建号则什么也找不到(`java@23.1.8+1-nik`)。 +- 以 `.0.0` 结尾的版本在列表里显示为只有大版本号的名字(`24-mandrel` 是 Mandrel 24.0.0),要写全版本号才能装:`java@24.0.0-mandrel`。装上之后,vfox 会按这个名字找到 `java@24-mandrel`,`vfox install` 和 `vfox use` 都一样。 +- 有些版本号下有几个构建,分别对应不同的 Java,比如 Mandrel 21.3.6 有 Java 11 和 Java 17 两个构建,插件装 Java 最新的那个;对 Mandrel 23.0.1.2 和 Liberica NIK 23.0.1 来说,那是 Java 20,不是 17。Liberica NIK 有几个版本为同一个 Java 构建了两次(`25.0.3`),装的是后一次的构建。版本名里既看不出 Java 版本,也看不出 BellSoft 的构建号,所以其他构建装不了。 +- 未发布:0.6.2 按 Foojay 的 `java_version` 给它们命名。这个字段原先放的就是这些版本号,2026 年 10 月起 Foojay 在这里改放 Java 的版本号。从那以后,0.6.2 装 `java@23.1.12-mandrel` 和 `java@23.1.8-nik` 都报 `No JDK found`,`vfox search` 里的 Mandrel 每个 Java 大版本只列一个名字(`21-mandrel`),`java@21-mandrel` 装的是 Mandrel 23.1.8,`java@23-nik` 装的是为 Java 23 构建的 Liberica NIK 24.1.2。 ### GraalVM CE 8 到 19(`grl8`、`grl11`、`grl16`、`grl17`、`grl19`) @@ -156,7 +162,7 @@ Mandrel 和 Liberica NIK 在 24 及以前用自己的版本号体系(Mandrel ### 按 GraalVM 编号的版本 -GraalVM CE 8 到 19,以及 23 以前的 Gluon GraalVM,版本号是 GraalVM 自己的,不是 Java 的:`22.3.3-grl17` 是 GraalVM 22.3.3,运行的是 Java 17.0.8;`21.3.1-grl11` 运行的是 Java 11。对只写大版本号的写法,vfox 只按版本号匹配,不分发行版,取以它开头的最高已安装版本,所以同时装了 `21.3.1-grl11` 和 `21.0.12.1+1-tem` 时,`vfox use java@21` 选中的是 `21.3.1-grl11`。请写上发行版,比如 `java@21-tem`。 +GraalVM CE 8 到 19、23 以前的 Gluon GraalVM,以及 25 以前的 Mandrel 和 Liberica NIK,版本号是 GraalVM 自己的,不是 Java 的:`22.3.3-grl17` 是 GraalVM 22.3.3,运行的是 Java 17.0.8;`21.3.1-grl11` 运行的是 Java 11;`23.1.12.1-mandrel` 运行的是 Java 21。对只写大版本号的写法,vfox 只按版本号匹配,不分发行版,取以它开头的最高已安装版本,所以同时装了 `21.3.1-grl11` 和 `21.0.12.1+1-tem` 时,`vfox use java@21` 选中的是 `21.3.1-grl11`。请写上发行版,比如 `java@21-tem`。 ### Oracle GraalVM 与 GraalVM 社区版的行为 diff --git a/docs/zh-CN/e2e.md b/docs/zh-CN/e2e.md index f3f41f2..a3b94f9 100644 --- a/docs/zh-CN/e2e.md +++ b/docs/zh-CN/e2e.md @@ -34,6 +34,8 @@ Windows 容器的覆盖(`tests/e2e/windows`)无法在开发容器里运行 2. 只写发行版不写版本,无论单独写还是跟在空版本后面(`java@tem`、`java@-tem`),`vfox install` 和 `vfox use` 都应失败,并提示补上版本。以前,`java@tem` 会让钩子报 Lua 错误;`java@-tem` 则让 `PreInstall` 把空版本发给 Foojay,Foojay 列出所有版本,结果装上了最新的。没有任何发行版发布过的版本(`<大版本>.0.99`)应该安装失败,并且 `PreInstall` 要指出它搜索的平台(`linux/amd64`、`windows/arm64` 等),以此确认向 Foojay 查询的就是 runner 所在的平台。已固定版本里从未发布过的构建(`<版本>+99`,例如 `21.0.8+99-tem`)也一样,这证明查询保留了构建号:Foojay 会把没编码的 `+` 当成空格并丢掉构建号,于是会装上这个版本的最新构建。 3. 在 `graalce` 这一行里,Oracle GraalVM 只写大版本号的 `25-graal` 应该装 25.0 系列的最新构建(`25.0.4.1-graal`),也就是 Oracle 官方 `25/latest` 下载跟的那个系列,而不是 Foojay 列在它前面的某个每月特性版本(比如 `25.4.4.1-graal`)。`vfox search java graal` 列出的 25 的各构建会先被模拟成已安装,这样 `vfox install` 报出的就是 `PreInstall` 选中的那个,而且不会下载任何东西。GA 版本 25 不放进去,因为那样 vfox 会发现 `25-graal` 已安装,根本不会去问 `PreInstall`。 4. 在 `tem` 这几行里(这几行在每个 runner 上都会运行),只按名字检查的发行版(`adpt` 到 `semcrt`,即 `tests/e2e/common` 里的 `nameOnly`),只要 Foojay 在这个 runner 上有它的包,都要能用简称找到:`vfox search java <简称>` 能列出它;把它列出的最新版本模拟成已安装后,`vfox install java@<大版本>-<简称>`(`22-grl17`)要报告这个版本已经安装,所以不会下载任何东西。以前没有这些简称时,这两条命令分别报 `Unsupported distribution` 和 `Could not extract a valid distribution`。 + + 同样在这几行里,Mandrel 和 Liberica NIK 要按它们沿用的 GraalVM 版本号来(`tests/e2e/common` 里的 `ownNumbers`;Windows arm64 上两者都没有):`vfox search java mandrel` 要列出 `23.1.12-mandrel`(Liberica NIK 是 `23.1.8-nik`);把它和搜索结果里最新的 23.x 模拟成已安装后,`vfox install java@mandrel-23.1.12` 和 `vfox install java@23-mandrel` 要报告这两个版本已经安装。2026 年 10 月 Foojay 把这个版本号挪到了 `distribution_version`,插件改读它之前,搜索结果每个 Java 大版本只列一个名字,找不到 `23.1.12-mandrel`,`java@23-mandrel` 装上的是为 Java 23 构建的 Mandrel 24.1.2。 5. 固定的版本按 `PreInstall` 给它起的名字安装:请求的版本加上构建号(`21.0.8-tem` 安装为 `21.0.8+9-tem`)。`vfox search java <发行版>`(`Available` 钩子)把同一个名字列为已安装,带 JavaFX 的构建会标注 JavaFX。对 GraalVM,它还必须列出自 25.1 起每月发布的特性版本(`25.4.4.1-graalce`),这些版本都不标 LTS(Foojay 标了,因为它们基于的 JDK 是 LTS);每个版本大约只存在一个月。在 Windows 上,列表里要包含 JetBrains Runtime 21.0.5,它在 Windows 上只有 tar.gz。 6. 在执行任何 `vfox use` 之前,`.sdkmanrc` 要能通过 `ParseLegacyFile` 选中 JDK。测试时,`vfox list java` 里排在最前面的是另一个版本的空安装(`21.0.80+1-tem`,它的版本号以固定的版本开头;vfox 按字符串降序给已安装版本排序)。以前 `ParseLegacyFile` 会把它当成第一个以该版本开头的版本,对补零的版本(见下面第二条),则当成该大版本里最新的版本。要覆盖的写法有: - 不含构建号的 SDKMAN 标识符:`java=21.0.8-tem`、`java=21.0.5-jbr`(SDKMAN 对 JetBrains 的叫法)、`java=25.0.4.fx-librca`(它对 JavaFX 构建的写法)。 @@ -50,7 +52,7 @@ Windows 容器的覆盖(`tests/e2e/windows`)无法在开发容器里运行 | 发行版 | 版本 | 覆盖内容 | amd64 | arm64 | | ------------ | ------- | ---------------------------------------------------------------------------- | ----- | ----- | | `open` | 25.0.2 | 默认发行版,版本不带后缀 | ✓ | | -| `tem` | 21.0.8 | 常规路径(Linux 上是 tar.gz,Windows 上是 zip);只按名字检查的那些发行版 | ✓ | ✓ | +| `tem` | 21.0.8 | 常规路径(Linux 上是 tar.gz,Windows 上是 zip);第 4 条里按名字和按版本号的检查 | ✓ | ✓ | | `librca-fx` | 25.0.4 | 带 JavaFX 的构建(`-fx`) | ✓ | ✓ | | `jb` | 21.0.5 | Windows 上走 tar.gz 的路径,那里没有 zip | ✓ | ✓ | | `graalce` | 25.0.2 | 事先设置的 `GRAALVM_HOME` 保持原值;Oracle GraalVM 的 `25-graal` | ✓ | | diff --git a/docs/zh-CN/foojay.md b/docs/zh-CN/foojay.md index b0a4d72..e588f44 100644 --- a/docs/zh-CN/foojay.md +++ b/docs/zh-CN/foojay.md @@ -24,20 +24,37 @@ https://api.foojay.io/disco/v3.0/packages/jdks | 参数 | 取值 | | --- | --- | | `distribution` | 发行版的长名,见 [distributions.md](distributions.md) | -| `version` | `vfox search` 时为空,否则是你输入内容里的版本部分。`+` 会做百分号编码,因为 Foojay 会把没编码的 `+` 当成空格,进而丢掉构建号。`28.ea.19` 会变成 `28-ea+19` | +| `version` | `vfox search` 时为空,否则是你输入内容里的版本部分。`+` 会做百分号编码,因为 Foojay 会把没编码的 `+` 当成空格,进而丢掉构建号。`28.ea.19` 会变成 `28-ea+19`。查 Mandrel 和 Liberica NIK 时始终为空 | +| `distribution_version` | 只用于 Mandrel 和 Liberica NIK,是你输入内容里的版本部分,见[下文](#mandrel-与-liberica-nik) | | `architecture` | arm64 用 `aarch64`,Windows x64 用 `x64`,其他系统的 x64 用 `amd64`,其他 CPU 用 vfox 报告的名字 | | `operating_system` | `linux`、`macos` 或 `windows` | | `archive_type` | `tar.gz`;Windows 上是 `zip` 加 `tar.gz`。其他系统上,Red Hat 还要 `tar.xz`,OJDKBuild、OpenLogic 和 Gluon GraalVM 还要 `zip` | | `lib_c_type` | Linux 上是 `glibc` 或 `musl`,其他系统为空 | | `directly_downloadable` | 始终是 `true` | -| `latest` | `available`,仅当版本只有大版本号(如 `21`)时才加 | +| `latest` | `available`,仅当版本只有大版本号(如 `21`)时才加;查 Mandrel 和 Liberica NIK 时一律不加 | 不加 `latest=available` 时,`version=21` 只匹配 21 的 GA 构建(`21+35`);加上之后,Foojay 会挑出最新的 21.x,`java@21-tem` 装的就是它。更具体的版本则按原样匹配。 -返回的是一个包列表。插件用 `java_version` 给版本命名;`javafx_bundled` 为真时加上 `-fx`;`term_of_support` 是 `lts` 时标注 LTS;在 Windows 上,同一版本既有 `zip` 又有 `tar.gz` 时优先用 `zip`。Foojay 混在 OJDKBuild 的 Windows JDK 里的 JRE、installer bundle 包和 RHEL 6 构建,以及 Gluon GraalVM 22.x 的 JDK 11 构建,插件都会略过,见 [distributions.md](distributions.md)。安装时,插件再取这个包的 `links.pkg_info_uri`,并从其中的 `direct_download_uri` 下载,那是厂商自己的服务器(Temurin 是 GitHub Releases)。这条记录里还有 `checksum`,但插件没有把它交给 vfox,所以 vfox 会打印 `WARNING: Checksum is not provided, skip verify...`,下载内容不做校验。 +返回的是一个包列表。插件用 `java_version` 给版本命名(Mandrel 和 Liberica NIK 用 `distribution_version`);`javafx_bundled` 为真时加上 `-fx`;`term_of_support` 是 `lts` 时标注 LTS;在 Windows 上,同一版本既有 `zip` 又有 `tar.gz` 时优先用 `zip`。Foojay 混在 OJDKBuild 的 Windows JDK 里的 JRE、installer bundle 包和 RHEL 6 构建,以及 Gluon GraalVM 22.x 的 JDK 11 构建,插件都会略过,见 [distributions.md](distributions.md)。安装时,插件再取这个包的 `links.pkg_info_uri`,并从其中的 `direct_download_uri` 下载,那是厂商自己的服务器(Temurin 是 GitHub Releases)。这条记录里还有 `checksum`,但插件没有把它交给 vfox,所以 vfox 会打印 `WARNING: Checksum is not provided, skip verify...`,下载内容不做校验。 `vfox search` 与原始列表有几处不同:Foojay 里同一个名字有两条记录时,它只列一次;不给 GraalVM 的特性版本加 LTS 备注(见 [distributions.md](distributions.md#oracle-graalvm-与-graalvm-社区版的行为));只列 GA 版本。 +### Mandrel 与 Liberica NIK + +截至 2026-10-20,这两个发行版沿用的 GraalVM 版本号,Foojay 放在 `distribution_version` 里,Java 的版本号放在 `java_version` 里,其中 Mandrel 的 `java_version` 只有大版本号: + +```bash +curl -s 'https://api.foojay.io/disco/v3.0/packages/jdks?distribution=mandrel&distribution_version=23.1.12&architecture=amd64&operating_system=linux&lib_c_type=glibc&archive_type=tar.gz&directly_downloadable=true' \ + | jq -r '.result[] | [.java_version, .distribution_version, .filename] | @tsv' +``` + +``` +21 23.1.12.1 mandrel-java21-linux-amd64-23.1.12.1-Final.tar.gz +21 23.1.12 mandrel-java21-linux-amd64-23.1.12.0-Final.tar.gz +``` + +所以插件查这两个发行版时用 `distribution_version`,`version` 留空。Foojay 按给出的几段数字匹配,所以查 `23.1.12` 也会返回 23.1.12.1,插件只保留指定的那个版本。只写大版本号时,插件自己从结果里挑最新的版本,因为 `latest=available` 挑不对:查 `distribution_version=23` 时,它返回的是 23.1.8 和 23.0.1.2 的两个构建,而 23.1.12.1 已经发布。同一个版本有几个 Java 版本的构建时,插件取 Java 最新的那个;Liberica NIK 为同一个 Java 构建了两次时,取后一次的,两次构建只能从文件名里区分(`...-25.0.3+2-linux-amd64.tar.gz`)。搜索时按 `distribution_version` 从新到旧排列。 + ## 我的平台上有哪些发行版 `latest=per_distro` 为每个有包的发行版返回最新的一个包。不要和 `version` 一起用,`version` 会被忽略。 @@ -105,7 +122,7 @@ curl -s 'https://api.foojay.io/disco/v3.0/packages/jdks?distribution=temurin&ver {"java_version":"21.0.8+9","distribution_version":"21.0.8","term_of_support":"lts","javafx_bundled":false,"archive_type":"tar.gz","filename":"OpenJDK21U-jdk_x64_linux_hotspot_21.0.8_9.tar.gz"} ``` -`java_version` 是 Java 的版本号,插件用的就是它。`distribution_version` 是厂商自己的版本号(Java `27+35` 对应 Zulu 的 `27.28.101`)。 +`java_version` 是 Java 的版本号,插件用的就是它。`distribution_version` 是厂商自己的版本号(Java `27+35` 对应 Zulu 的 `27.28.101`),插件只对 Mandrel 和 Liberica NIK 用它,见[上文](#mandrel-与-liberica-nik)。 ## 版本与支持期限 diff --git a/docs/zh-CN/javafx.md b/docs/zh-CN/javafx.md index 47a3fc6..9f9a60a 100644 --- a/docs/zh-CN/javafx.md +++ b/docs/zh-CN/javafx.md @@ -33,13 +33,13 @@ java --list-modules | grep javafx ## 哪些平台有 JavaFX 构建 -截至 2026-10-18,提供 JavaFX 构建的发行版有四个,而且并非每个平台都有。下表列出有 JavaFX 构建的 LTS 版本,中间的非 LTS 版本也有一些,但有缺口。 +截至 2026-10-20,提供 JavaFX 构建的发行版有四个,而且并非每个平台都有。下表列出有 JavaFX 构建的 LTS 版本,中间的非 LTS 版本也有一些,但有缺口。Liberica NIK 一行写的是 Java 版本,不是它名字里的 GraalVM 版本号(见 [distributions.md](distributions.md#mandrel-与-liberica-nik-的行为)):它为 Java 21 提供的 JavaFX 构建是 `23.1.x-nik-fx`。 | 发行版 | Linux x64 | Linux arm64 | Alpine x64 | macOS Intel | macOS Apple Silicon | Windows x64 | Windows arm64 | | --- | --- | --- | --- | --- | --- | --- | --- | | Zulu(`zulu`) | 8、11、17、21、25 | 8、11、17、21、25 | – | 8、11、17、21、25 | 8、11、17、21、25 | 8、11、17、21、25 | – | | Liberica(`librca`) | 8、11、17、21、25 | 11、17、21、25 | 11 | 8、11、17、21、25 | 8、11、17、21、25 | 8、11、17、21、25 | 11、17、21、25 | | Corretto(`amzn`) | 8 | 8 | – | 8 | – | 8 | – | -| Liberica NIK(`nik`) | 21、25 | – | – | 25 | 25 | 21、25 | – | +| Liberica NIK(`nik`) | 11、17、21、25 | – | – | 11、17、21、25 | 11、17、21、25 | 11、17、21、25 | – | Alpine arm64 上没有任何发行版提供 JavaFX。Loongnix 为龙架构提供带 JavaFX 的构建,选择方式相同,见 [loongnix.md](loongnix.md)。想看某个平台当前的情况,在 [foojay.md](foojay.md) 的查询里加上 `javafx_bundled=true` 即可。 diff --git a/docs/zh-CN/platforms.md b/docs/zh-CN/platforms.md index 6645f04..ee8130a 100644 --- a/docs/zh-CN/platforms.md +++ b/docs/zh-CN/platforms.md @@ -53,7 +53,7 @@ Foojay 的数据会变,这张表也会过时。想看当前的情况,按 [fo 标了 ✅ 也不代表所有版本都有。以下同样截至 2026-10-18: - Windows ARM64 上,没有任何发行版提供 Java 8。Temurin 有 21 和 23,Zulu 有 16 到 19、21 和 25,Liberica 有 11 和 16 到 27,Microsoft 有 11、16、17、21 和 25,JetBrains Runtime 有 17、21 和 25。 -- Apple Silicon 上,Java 8 来自 Zulu、Liberica、Corretto 和 Kona。Temurin 和 Semeru 在那里有 11 和 17 到 27,OpenJDK 有 17 到 27。Mandrel 有 23 到 25,Liberica NIK 有 22 到 25。 +- Apple Silicon 上,Java 8 来自 Zulu、Liberica、Corretto 和 Kona。Temurin 和 Semeru 在那里有 11 和 17 到 27,OpenJDK 有 17 到 27。Mandrel 有 23.1 到 25 的版本,运行 Java 21 到 25;Liberica NIK 有 22.2 到 25 的版本,运行 Java 11、17 和 20 到 25(见[它们的版本号](distributions.md#mandrel-与-liberica-nik-的行为))。 - Intel Mac 上的新版本来得更晚,有的干脆没有。OpenJDK 和 Temurin 停在 26,而 Linux 上已有 27;SapMachine 停在 24;Oracle GraalVM 和 GraalVM 社区版停在 25.0.1。Mandrel 没有 Intel Mac 的构建。 - 在 Alpine 上,Temurin 的 arm64 构建只有 21 及以后。x64 方面,Microsoft 只有 11 和 17,SapMachine 有 17 和 20 到 27,Kona 有 8 和 21,Dragonwell 有 11、17、21 和 25,JetBrains Runtime 只有 17。arm64 方面,Kona 有 Java 8,JetBrains Runtime 有 17(x64 也有)。 - Trava 在 Linux arm64 上只有一个构建,11.0.10+6。 diff --git a/docs/zh-CN/troubleshooting.md b/docs/zh-CN/troubleshooting.md index e0d0b73..1c6c5f9 100644 --- a/docs/zh-CN/troubleshooting.md +++ b/docs/zh-CN/troubleshooting.md @@ -66,7 +66,8 @@ vfox config proxy.url http://127.0.0.1:7890 - **安装后的版本名里多了一个你没写的构建号。** `java@21.0.8-tem` 装出来是 `21.0.8+9-tem`。构建号是版本名的一部分,见 [versions.md](versions.md#安装后的版本名)。 - **`vfox install java@21-tem` 和 `vfox install java tem` 做的是不同的事。** 后者是两个 SDK,`java` 和 `tem`。 - **你设置的 `GRAALVM_HOME` 不会被改动。** 插件只设置 `JAVA_HOME` 和 `PATH`。 -- **`vfox use java@21` 选中了 `21.3.1-grl11`,而它运行的是 Java 11。** GraalVM CE 8 到 19 和 23 以前的 Gluon GraalVM 用的是 GraalVM 的版本号,对只写大版本号的写法,vfox 只按版本号匹配,不分发行版,见 [distributions.md](distributions.md#按-graalvm-编号的版本)。请写成 `java@21-tem`。 +- **`vfox use java@21` 选中了 `21.3.1-grl11`,而它运行的是 Java 11。** GraalVM CE 8 到 19、23 以前的 Gluon GraalVM,以及 25 以前的 Mandrel 和 Liberica NIK,用的都是 GraalVM 的版本号;对只写大版本号的写法,vfox 只按版本号匹配,不分发行版,见 [distributions.md](distributions.md#按-graalvm-编号的版本)。请写成 `java@21-tem`。 +- **`java@21-mandrel` 装上的 Mandrel 运行的是 Java 17。** Mandrel 和 Liberica NIK 的大版本号是 GraalVM 的:`21.3.6-mandrel` 是最新的 Mandrel 21.x。它们为 Java 21 发布的是 23.1.x,所以要写 `java@23-mandrel`,见 [distributions.md](distributions.md#mandrel-与-liberica-nik-的行为)。 ## JDK 在哪里 diff --git a/docs/zh-CN/versions.md b/docs/zh-CN/versions.md index 83e8a98..b8b5de6 100644 --- a/docs/zh-CN/versions.md +++ b/docs/zh-CN/versions.md @@ -29,6 +29,7 @@ vfox install java@21 # 不写发行版:jdk.java.net 上的 Open - SDKMAN 写法里补了零的版本也能识别:`27.0.0-librca` 装的是 `27+36-librca`。 - Oracle GraalVM 只写大版本号时,装 25.0 系列的最新构建,不装每月发布的特性版本(feature release)。特性版本要写全版本号(`25.4.4.1-graal`)。见 [GraalVM](distributions.md#graalvm-系列)。 - 写了 `-fx` 就只考虑带 JavaFX 的构建,没写就只考虑不带的,两者不会混用。 +- Mandrel 和 Liberica NIK 按它们沿用的 GraalVM 版本号来,只写大版本号时也一样:`java@23-mandrel` 装的是 `23.1.12.1-mandrel`,运行的是 Java 21。见 [Mandrel 与 Liberica NIK](distributions.md#mandrel-与-liberica-nik-的行为)。 - 在 Windows 上,同一版本既有 zip 又有 tar.gz 时,装 zip。 - 只写发行版不写版本(`java@tem`、`java@-tem`、`java@zulu-fx`)会被拒绝,并提示补上版本。 @@ -36,7 +37,7 @@ vfox install java@21 # 不写发行版:jdk.java.net 上的 Open ## 安装后的版本名 -安装后的版本名取自 Foojay 返回的 `java_version`,`vfox search` 里显示的也是它: +安装后的版本名取自 Foojay 返回的 `java_version`,Mandrel 和 Liberica NIK 取的是 `distribution_version`。`vfox search` 里显示的也是这些名字: ``` [-<简称>][-fx] @@ -49,6 +50,7 @@ vfox install java@21 # 不写发行版:jdk.java.net 上的 Open | `25.0.2+10` | OpenJDK,没有后缀 | | `17.0.12-graal` | GraalVM,没有构建号 | | `8.0.482+8-zulu` | Java 8 写成 `8.0.<更新号>+<构建号>` | +| `23.1.12.1-mandrel` | Mandrel,按 GraalVM 编号,运行的是 Java 21 | | `28-ea+19` | EA 构建,见下文 | `vfox list java` 显示的、`vfox uninstall` 需要的都是这种名字: @@ -73,7 +75,7 @@ vfox uninstall java@21.0.8+9-tem 写明了构建或版本时,不会跳到别的构建或版本(`21.0.12-tem` 不会选中 `21.0.12.1+1-tem`)。也不会跨发行版,不会在带 JavaFX 和不带 JavaFX 的构建之间串用,不会在 EA 和 GA 之间串用。什么都匹配不上时,报 `java@99-tem is not installed`。 -vfox 自己匹配 `21` 时只看版本号,所以 GraalVM CE 8 到 19 和 Gluon GraalVM 也会被它选中,它们的版本号是 GraalVM 的:`21.3.1-grl11` 运行的是 Java 11,`vfox use java@21` 却会选中它,而不是 `21.0.12.1+1-tem`。见 [distributions.md](distributions.md#按-graalvm-编号的版本)。 +vfox 自己匹配 `21` 时只看版本号,所以 GraalVM CE 8 到 19、Gluon GraalVM、Mandrel 和 Liberica NIK 也会被它选中,它们的版本号是 GraalVM 的:`21.3.1-grl11` 运行的是 Java 11,`vfox use java@21` 却会选中它,而不是 `21.0.12.1+1-tem`。见 [distributions.md](distributions.md#按-graalvm-编号的版本)。 作用域用 `vfox use` 的参数选择:`--global`、`--project` 或 `--session`,默认是会话作用域。如果 Shell 没有挂载 vfox,Windows 会警告并切到全局作用域,Linux 和 macOS 则报 `vfox requires hook support` 后退出。`--project` 会写出 `.vfox.toml`,里面记录的是安装后的版本名(`java = "17.0.10+7-tem"`)。`.sdkmanrc` 也会被读取,见 [sdkmanrc.md](sdkmanrc.md)。 diff --git a/hooks/available.lua b/hooks/available.lua index 0a22ad8..7186cce 100644 --- a/hooks/available.lua +++ b/hooks/available.lua @@ -16,10 +16,11 @@ local foojay = require("foojay") local loongnix = require("loongnix") local distribution_version_parser = require("distribution_version") --- is_feature_release reads GraalVM's numbering only. Liberica NIK and Mandrel --- numbered their releases after themselves up to 24 (Mandrel 23.1.12 is LTS) and --- follow the JDK from 25 on, so they stay out of it, and so do GraalVM CE 8 to --- 19 and Gluon GraalVM, which ended before the monthly feature releases began. +-- is_feature_release reads GraalVM's numbering since 25 only. Liberica NIK and +-- Mandrel carry GraalVM's older numbers up to 24, whose minor is no feature +-- release (Mandrel 23.1.12, on JDK 21, is LTS), and the JDK's from 25 on, so +-- they stay out of it, and so do GraalVM CE 8 to 19 and Gluon GraalVM, which +-- ended before the monthly feature releases began. local graalvm = { graal = true, graalce = true } --- Return all available versions provided by this plugin diff --git a/lib/foojay.lua b/lib/foojay.lua index eb2dd0d..881856f 100644 --- a/lib/foojay.lua +++ b/lib/foojay.lua @@ -15,6 +15,8 @@ local http = require("http") local json = require("json") +local installed_version = require("installed_version") + local foojay = {} local URL = @@ -72,6 +74,38 @@ local fixes = { end, } +-- Mandrel and Liberica NIK go by the numbers of the GraalVM they are built +-- from: Mandrel 23.1.12.1 runs on JDK 21, and only from 25 on do the numbers +-- follow the JDK's (25.0.4.1). Foojay gives them as distribution_version, and +-- the JDK as java_version, Mandrel's as the major alone (21), so the plugin +-- looks up and names their releases by distribution_version. +local own_numbers = { + mandrel = true, + liberica_native = true, +} + +--- Returns BellSoft's build number of a Liberica NIK release, which only the +--- file name carries (...-openjdk25.0.3+12-25.0.3+2-linux-amd64.tar.gz), or 0. +local function bellsoft_build(package) + local build = (package.filename or ""):match("%-[%d.]+%+(%d+)%-") + return tonumber(build) or 0 +end + +--- Whether package a goes before b among the releases of own_numbers: the +--- newer release first, then the build for the newer JDK, as some releases +--- come for several (Mandrel 21.3.6 for JDK 11 and 17), then BellSoft's later +--- build for the same JDK (25.0.3+2 before 25.0.3+1). +local function newest_first(a, b) + for _, field in ipairs({ "distribution_version", "java_version" }) do + if installed_version.newer(a[field], b[field]) then + return true + elseif installed_version.newer(b[field], a[field]) then + return false + end + end + return bellsoft_build(a) > bellsoft_build(b) +end + --- Detects the libc type on Linux systems (glibc or musl) --- @return string "glibc" or "musl" local function detect_lib_c_type() @@ -147,6 +181,31 @@ foojay.fetchtJdkList = function(distribution, version) return respBody.result end + if own_numbers[distribution] then + -- Foojay matches distribution_version by the numbers given, so 23.1.12 + -- lists 23.1.12.1 as well, and its latest=available takes an older + -- release (23.1.8 for 23.1). A bare major takes the newest release + -- itself, and a longer version the release it names, whose zeros + -- Foojay leaves out (23.1.12.0 is 23.1.12). + local bare = version == "" or version:match("^%d+$") + local release = installed_version.unpad(version) + local result = {} + local query = version ~= "" and "&distribution_version=" .. encode(version) or "" + for _, package in ipairs(request("", query) or {}) do + if + package.distribution_version + and (bare or installed_version.unpad(package.distribution_version) == release) + then + table.insert(result, package) + end + end + table.sort(result, newest_first) + for _, package in ipairs(result) do + package.java_version = package.distribution_version + end + return result + end + local result = request(version, latest) local fix = fixes[distribution] if fix and result then diff --git a/lib/installed_version.lua b/lib/installed_version.lua index 49b84d2..e54d93d 100644 --- a/lib/installed_version.lua +++ b/lib/installed_version.lua @@ -37,7 +37,7 @@ end --- Whether Java version a is newer than b: the release decides, then the --- build (21.0.12.1+1 > 21.0.8+9 > 21.0.8+7 > 21+35). -local function newer(a, b) +function installed_version.newer(a, b) local a_release, a_build = a:match("^([^+]*)(.*)$") local b_release, b_build = b:match("^([^+]*)(.*)$") local order = compare(a_release, b_release) @@ -54,7 +54,7 @@ function installed_version.newest(installed, prefix, rest, suffix) java_version .. suffix == candidate and java_version:sub(1, #prefix) == prefix and java_version:sub(#prefix + 1):find(rest) - and (not best or newer(java_version, best_version)) + and (not best or installed_version.newer(java_version, best_version)) then best, best_version = candidate, java_version end diff --git a/tests/e2e/common/common.go b/tests/e2e/common/common.go index b10fa44..2cae103 100644 --- a/tests/e2e/common/common.go +++ b/tests/e2e/common/common.go @@ -684,6 +684,72 @@ func NewestBareMajor(searched []string, short string) (spec, newest string, ok b return spec, newest, found && major != "" && spec != newest } +// ownNumbered describes a distribution that goes by the numbers of the +// GraalVM it is built from (Mandrel 23.1.12 runs on JDK 21): its long name, a +// release it has under such a number for every platform in platforms, and +// those runner platforms (2026-10-20). +type ownNumbered struct { + longName, release string + platforms []string +} + +// ownNumbers maps Mandrel and Liberica NIK, by short name, to what the suite +// checks of them. Foojay gives their numbers as distribution_version and the +// JDK as java_version, after which the plugin named them, so `vfox install +// java@23.1.12-mandrel` found no package, `vfox search java mandrel` listed +// one name per JDK major, and `java@23-mandrel` installed Mandrel 24.1.2, +// built for JDK 23 (vfox-java#106). +var ownNumbers = map[string]ownNumbered{ + "mandrel": {longName: "mandrel", release: "23.1.12", platforms: []string{"linux/amd64", "linux/arm64", "windows/amd64"}}, + "nik": {longName: "liberica_native", release: "23.1.8", platforms: []string{"linux/amd64", "linux/arm64", "windows/amd64"}}, +} + +// OwnNumberedDistributions returns, sorted, the distributions in ownNumbers +// that Foojay has packages of for platform ("linux/amd64", "windows/arm64"). +func OwnNumberedDistributions(platform string) []string { + var names []string + for name, d := range ownNumbers { + if slices.Contains(d.platforms, platform) { + names = append(names, name) + } + } + slices.Sort(names) + return names +} + +// OwnNumberSpecs renders, for a distribution in ownNumbers, its release in +// asdf's order ("mandrel-23.1.12"), which vfox does not find installed under +// that spelling and so passes to PreInstall, the installed name it must +// resolve to ("23.1.12-mandrel"), and the bare major of that release +// ("23-mandrel"). +func OwnNumberSpecs(short string) (spec, installed, bare string) { + d := ownNumbers[short] + return d.longName + "-" + d.release, d.release + "-" + short, Major(d.release) + "-" + short +} + +// NewestOfMajor picks out of the versions `vfox search` lists, newest first, +// the one a bare major spec ("23-mandrel") must install: the first release of +// that major and distribution without JavaFX ("23.1.12.1-mandrel"). The +// release named like the spec (Mandrel 23.0.0.0, "23-mandrel") does not +// count, as vfox would find it installed without asking PreInstall. +func NewestOfMajor(searched []string, bare string) (newest string, ok bool) { + major, short, _ := strings.Cut(bare, "-") + for _, version := range searched { + core, found := strings.CutSuffix(version, "-"+short) + if found && strings.HasPrefix(core, major+".") { + return version, true + } + } + return "", false +} + +// ChecksOwnNumbers reports whether a combo also checks the distributions in +// OwnNumberedDistributions, which downloads nothing. Temurin's combos do: they +// run on every runner. +func ChecksOwnNumbers(distribution string) bool { + return Base(distribution) == "tem" +} + // ContainerName returns a unique container name per run: the combo slug stays // greppable in `docker ps`, the random suffix avoids clashes with leftovers // from killed runs. diff --git a/tests/e2e/common/common_test.go b/tests/e2e/common/common_test.go index af83f44..08fc014 100644 --- a/tests/e2e/common/common_test.go +++ b/tests/e2e/common/common_test.go @@ -489,6 +489,59 @@ func TestNameOnlyDistributions(t *testing.T) { } } +func TestOwnNumbers(t *testing.T) { + for platform, want := range map[string][]string{ + "linux/amd64": {"mandrel", "nik"}, + "linux/arm64": {"mandrel", "nik"}, + "windows/amd64": {"mandrel", "nik"}, + "windows/arm64": nil, + } { + if got := OwnNumberedDistributions(platform); !slices.Equal(got, want) { + t.Errorf("OwnNumberedDistributions(%s) = %q, want %q", platform, got, want) + } + } + for short, want := range map[string][3]string{ + "mandrel": {"mandrel-23.1.12", "23.1.12-mandrel", "23-mandrel"}, + "nik": {"liberica_native-23.1.8", "23.1.8-nik", "23-nik"}, + } { + if spec, installed, bare := OwnNumberSpecs(short); [3]string{spec, installed, bare} != want { + t.Errorf("OwnNumberSpecs(%s) = %q, %q, %q; want %q", short, spec, installed, bare, want) + } + } + // Temurin's combos run on every runner, arm64 included. + for _, arch := range []string{"amd64", "arm64"} { + if !slices.ContainsFunc(DefaultDistributions(arch), ChecksOwnNumbers) { + t.Errorf("no %s default combo checks Mandrel and Liberica NIK", arch) + } + } + if ChecksOwnNumbers("graalce") { + t.Error("only the Temurin combos check Mandrel and Liberica NIK") + } +} + +func TestNewestOfMajor(t *testing.T) { + // Abridged `vfox search` output, observed on 2026-10-20. + mandrel := []string{"25.0.4.1-mandrel", "24.2.2-mandrel", "23.1.12.1-mandrel", "23.1.12-mandrel", "23-mandrel"} + nik := []string{"25.0.4.1-nik-fx", "25.0.4.1-nik", "23.1.12.1-nik-fx", "23.1.12.1-nik", "23.1.8-nik"} + for _, c := range []struct { + searched []string + bare, newest string + ok bool + }{ + {mandrel, "23-mandrel", "23.1.12.1-mandrel", true}, + {mandrel, "24-mandrel", "24.2.2-mandrel", true}, + {nik, "23-nik", "23.1.12.1-nik", true}, + // Before vfox-java#106 the search listed one name per JDK major. + {[]string{"25-mandrel", "24-mandrel", "23-mandrel"}, "23-mandrel", "", false}, + {mandrel, "21-mandrel", "", false}, + {nik, "23-mandrel", "", false}, + } { + if newest, ok := NewestOfMajor(c.searched, c.bare); newest != c.newest || ok != c.ok { + t.Errorf("NewestOfMajor(%q, %s) = %q, %v; want %q, %v", c.searched, c.bare, newest, ok, c.newest, c.ok) + } + } +} + func TestNewestBareMajor(t *testing.T) { for _, c := range []struct { searched []string diff --git a/tests/e2e/linux/e2e_test.go b/tests/e2e/linux/e2e_test.go index b127f5d..c5e56c8 100644 --- a/tests/e2e/linux/e2e_test.go +++ b/tests/e2e/linux/e2e_test.go @@ -175,6 +175,9 @@ func runOne(t *testing.T, ctx context.Context, image, platform, arch string, c c if common.ChecksNameOnly(c.Distribution) { checkNameOnly(ctx, t, ctr, platform) } + if common.ChecksOwnNumbers(c.Distribution) { + checkOwnNumbers(ctx, t, ctr, platform) + } installed := installJava(ctx, t, ctr, common.Spec(c.Distribution, version)) verifySearch(ctx, t, ctr, c.Distribution, installed) diff --git a/tests/e2e/linux/setup.go b/tests/e2e/linux/setup.go index 6714fd8..46c63d9 100644 --- a/tests/e2e/linux/setup.go +++ b/tests/e2e/linux/setup.go @@ -158,3 +158,37 @@ func checkNameOnly(ctx context.Context, t *testing.T, ctr tc.Container, platform } t.Logf("PASS %d distributions go by name on %s: %s", len(names), platform, strings.Join(names, ", ")) } + +// checkOwnNumbers proves Mandrel and Liberica NIK go by the GraalVM numbers +// they carry (see common.OwnNumberedDistributions): `vfox search java +// ` lists the release the suite names under its number, and with it +// and the newest release of its major faked as installed, `vfox install +// java@-` and `vfox install java@-` find those +// installed (see common.OwnNumberSpecs and common.NewestOfMajor), so nothing +// downloads. +func checkOwnNumbers(ctx context.Context, t *testing.T, ctr tc.Container, platform string) { + t.Helper() + names := common.OwnNumberedDistributions(platform) + for _, name := range names { + search := "vfox search java " + name + out := execRetry(ctx, t, ctr, search, search) + searched := common.SearchedVersions(out) + spec, installed, bare := common.OwnNumberSpecs(name) + require.Containsf(t, searched, installed, "%s must list %s\n--- output ---\n%s", search, installed, out) + newest, ok := common.NewestOfMajor(searched, bare) + require.Truef(t, ok, "%s lists no release that %s names\n--- output ---\n%s", search, bare, out) + var dirs []string + for _, version := range []string{installed, newest} { + dir := `"${VFOX_HOME:-$HOME/.vfox}"/cache/java/` + shQuote("v-"+version) + dirs = append(dirs, dir) + execOK(ctx, t, ctr, "mkdir --parents "+dir+"/"+shQuote("java-"+version)) + } + for _, c := range []struct{ spec, want string }{{spec, installed}, {bare, newest}} { + out = execRetry(ctx, t, ctr, "vfox install java@"+c.spec, "vfox install java@"+c.spec) + require.Containsf(t, common.StripANSI(out), "java@"+c.want+" is already installed", + "vfox install java@%s must take %s, which %s lists", c.spec, c.want, search) + } + execOK(ctx, t, ctr, "rm --recursive "+strings.Join(dirs, " ")) + t.Logf("PASS java@%s takes %s and java@%s %s", spec, installed, bare, newest) + } +} diff --git a/tests/e2e/windows/e2e_test.go b/tests/e2e/windows/e2e_test.go index f23651f..46bd395 100644 --- a/tests/e2e/windows/e2e_test.go +++ b/tests/e2e/windows/e2e_test.go @@ -252,6 +252,9 @@ func runOne(t *testing.T, ctx context.Context, image, platform, arch string, c c if common.ChecksNameOnly(c.Distribution) { checkNameOnly(ctx, t, ctr, box, platform) } + if common.ChecksOwnNumbers(c.Distribution) { + checkOwnNumbers(ctx, t, ctr, box, platform) + } installed := installJava(ctx, t, ctr, box, common.Spec(c.Distribution, version)) verifySearch(ctx, t, ctr, box, c.Distribution, installed) diff --git a/tests/e2e/windows/setup.go b/tests/e2e/windows/setup.go index 15b9b8c..caa1a68 100644 --- a/tests/e2e/windows/setup.go +++ b/tests/e2e/windows/setup.go @@ -379,3 +379,39 @@ func checkNameOnly(ctx context.Context, t *testing.T, ctr tc.Container, box slot } t.Logf("PASS %d distributions go by name on %s: %s", len(names), platform, strings.Join(names, ", ")) } + +// checkOwnNumbers proves Mandrel and Liberica NIK go by the GraalVM numbers +// they carry (see common.OwnNumberedDistributions): `vfox search java +// ` lists the release the suite names under its number, and with it +// and the newest release of its major faked as installed, `vfox install +// java@-` and `vfox install java@-` find those +// installed (see common.OwnNumberSpecs and common.NewestOfMajor), so nothing +// downloads. +func checkOwnNumbers(ctx context.Context, t *testing.T, ctr tc.Container, box slotBox, platform string) { + t.Helper() + names := common.OwnNumberedDistributions(platform) + for _, name := range names { + search := "vfox search java " + name + out := execRetry(ctx, t, ctr, search, search, box.vars...) + searched := common.SearchedVersions(out) + spec, installed, bare := common.OwnNumberSpecs(name) + require.Containsf(t, searched, installed, "%s must list %s\n--- output ---\n%s", search, installed, out) + newest, ok := common.NewestOfMajor(searched, bare) + require.Truef(t, ok, "%s lists no release that %s names\n--- output ---\n%s", search, bare, out) + var create, remove []string + for _, version := range []string{installed, newest} { + dir := fmt.Sprintf("(Join-Path $env:VFOX_HOME %s)", pwshQuote(`cache\java\v-`+version)) + create = append(create, fmt.Sprintf("New-Item -ItemType Directory -Force -Path (Join-Path %s %s) | Out-Null", + dir, pwshQuote("java-"+version))) + remove = append(remove, fmt.Sprintf("Remove-Item -LiteralPath %s -Recurse -Force", dir)) + } + execOK(ctx, t, ctr, strings.Join(create, "; "), box.vars...) + for _, c := range []struct{ spec, want string }{{spec, installed}, {bare, newest}} { + out = execRetry(ctx, t, ctr, "vfox install java@"+c.spec, "vfox install "+pwshQuote("java@"+c.spec), box.vars...) + require.Containsf(t, common.StripANSI(out), "java@"+c.want+" is already installed", + "vfox install java@%s must take %s, which %s lists", c.spec, c.want, search) + } + execOK(ctx, t, ctr, strings.Join(remove, "; "), box.vars...) + t.Logf("PASS java@%s takes %s and java@%s %s", spec, installed, bare, newest) + } +} diff --git a/tests/pre_install_test.lua b/tests/pre_install_test.lua index ac9bdbf..2a74206 100644 --- a/tests/pre_install_test.lua +++ b/tests/pre_install_test.lua @@ -88,10 +88,9 @@ local foojay = { ["openjdk"] = { pkg("25.0.2+10"), pkg("21.0.2+13") }, ["temurin"] = { pkg("25.0.2+10"), pkg("21.0.8+9") }, -- Observed on 2026-10-18: Foojay marks GraalVM's feature releases LTS, as - -- 25.0 is, and Mandrel 23.1 LTS, as the JDK 21 it builds on is; abridged. + -- 25.0 is; abridged. ["graalvm"] = { lts(pkg("25.4.4.1")), lts(pkg("25.1.3")), lts(pkg("25.0.4.1")), lts(pkg("25")), pkg("24.0.2") }, ["graalvm_community"] = { lts(pkg("25.4.4.1")), lts(pkg("25.0.2")) }, - ["mandrel"] = { lts(pkg("23.1.12")) }, -- JetBrains Runtime ships Windows zips for its newer builds only, and Foojay -- lists a version's zip and tar.gz in either order; abridged. ["windows jetbrains 21"] = { pkg("21+2121") }, @@ -186,6 +185,95 @@ for _, other in ipairs(others) do end end +-- A package of Mandrel or Liberica NIK: its JDK, the GraalVM number it goes by, +-- its file and term_of_support. +local function own(java_version, distribution_version, filename, term_of_support, fx) + local jdk = file(pkg(java_version, fx), filename, distribution_version) + jdk.term_of_support = term_of_support + return jdk +end + +-- Mandrel's file names carry the JDK major and Mandrel's number in four parts. +local function mandrel(jdk, number, term_of_support) + local parts = number + while select(2, parts:gsub("%.", "")) < 3 do + parts = parts .. ".0" + end + return own(jdk, number, ("mandrel-java%s-linux-amd64-%s-Final.tar.gz"):format(jdk, parts), term_of_support) +end + +-- BellSoft's file names carry the JDK and NIK's number with BellSoft's build, +-- which distribution_version leaves out, with full- for the JavaFX builds. +local function nik(jdk, number, term_of_support, fx) + local filename = "bellsoft-liberica-vm-" .. (fx and "full-" or "") .. "openjdk" .. jdk .. "-" .. number + return own(jdk, number:match("^[^+]*"), filename .. "-linux-amd64.tar.gz", term_of_support, fx) +end + +-- Observed on 2026-10-20 for linux/amd64: Foojay gives the numbers Mandrel and +-- Liberica NIK go by as distribution_version, and the JDK as java_version, +-- Mandrel's as the major alone; abridged, in Foojay's order. The plugin asks +-- for them by distribution_version, which lists the packages whose number +-- starts with the numbers given, a missing one counting as 0, so 23.1.12 +-- lists 23.1.12.1 as well and 23.1.12.0 does not. A build is ignored. +local own_numbers = { + mandrel = { + mandrel("25", "25.0.4.1", "lts"), + mandrel("25", "25.0.1", "lts"), + mandrel("24", "24.2.2", "sts"), + mandrel("22", "24.0.2", "sts"), + mandrel("22", "24", "sts"), + mandrel("21", "23.1.12.1", "lts"), + mandrel("21", "23.1.12", "lts"), + -- Foojay lists some files twice, as it did Oracle GraalVM 25.0.4. + mandrel("21", "23.1.12", "lts"), + mandrel("21", "23.1.8", "lts"), + mandrel("21", "23.1.3.1", "lts"), + mandrel("20", "23.0.1.2", "sts"), + mandrel("17", "23.0.6", "lts"), + mandrel("17", "23.0.1.2", "lts"), + mandrel("17", "21.3.6", "lts"), + mandrel("11", "21.3.6", "lts"), + }, + liberica_native = { + nik("25.0.4.1+2", "25.0.4.1+1", "lts"), + nik("25.0.4.1+2", "25.0.4.1+1", "lts", true), + -- BellSoft built 25.0.3 twice for the same JDK. + nik("25.0.3+12", "25.0.3+1", "lts"), + nik("25.0.3+12", "25.0.3+2", "lts", true), + nik("25.0.3+12", "25.0.3+2", "lts"), + nik("25.0.3+12", "25.0.3+1", "lts", true), + nik("23.0.2+9", "24.1.2+1", "sts"), + nik("21.0.12.1+2", "23.1.12.1+1", "lts"), + nik("21.0.8+13", "23.1.8+1", "lts", true), + nik("21.0.8+13", "23.1.8+1", "lts"), + nik("20.0.2+10", "23.0.1+1", "lts"), + nik("17.0.10+13", "23.0.3+1", "lts"), + nik("17.0.10+13", "22.3.5+1", "sts"), + nik("17.0.8.1+1", "23.0.1+2", "lts"), + nik("17.0.8+7", "23.0.1+1", "lts"), + nik("17.0.5+8", "21.3.3.1+1", "sts"), + nik("11.0.22+12", "22.3.5+1", "sts"), + nik("11.0.17+7", "21.3.3.1+1", "sts"), + }, +} + +-- Whether Foojay lists a package of own_numbers whose number is +-- distribution_version for the query value asked. +local function own_number_matches(distribution_version, asked) + local numbers = {} + for number in distribution_version:gmatch("%d+") do + table.insert(numbers, tonumber(number)) + end + local i = 0 + for number in asked:match("^[^+]*"):gmatch("%d+") do + i = i + 1 + if (numbers[i] or 0) ~= tonumber(number) then + return false + end + end + return true +end + local requests = {} local responses = {} package.preload.http = function() @@ -218,11 +306,26 @@ package.preload.http = function() if params.operating_system == "windows" or params.operating_system == "macos" then key = params.operating_system .. " " .. key end - -- Only the packages of the archive types asked for are listed. + local packages = foojay[key] or {} + if own_numbers[params.distribution] and key == params.distribution then + packages = {} + local asked = (params.distribution_version or ""):match("^[^ ]*") + for _, package in ipairs(own_numbers[params.distribution]) do + if own_number_matches(package.distribution_version, asked) then + table.insert(packages, package) + end + end + end + -- Only the packages of the archive types asked for are listed, + -- each a copy, as a decoded answer is. local result = {} - for _, package in ipairs(foojay[key] or {}) do + for _, package in ipairs(packages) do if archive_types[package.archive_type] then - table.insert(result, package) + local copy = {} + for field, value in pairs(package) do + copy[field] = value + end + table.insert(result, copy) end end body = { result = result } @@ -342,8 +445,8 @@ assert(all["25.0.2+10-tem"] and all["21.0.8+9-tem"], "Available all: Temurin ver -- Searching drops the LTS note from GraalVM's feature releases, each -- superseded within a month, whether it lists one distribution or all. --- GraalVM's other releases keep it, and so do Mandrel's, which Mandrel numbers --- after itself. +-- GraalVM's other releases keep it, and so do Mandrel's, though their GraalVM +-- numbers have a non-zero minor up to 24. for version, note in pairs({ ["25.4.4.1-graal"] = "", ["25.1.3-graal"] = "", @@ -421,6 +524,82 @@ RUNTIME.osType = "darwin" check("25-opnlgc", "25.0.4+7-opnlgc", true, "zip") RUNTIME.osType = "linux" +-- Installs version of Mandrel or Liberica NIK, which the plugin asks Foojay +-- for by distribution_version alone, and checks the end of the file name. +local function check_own_number(version, expected, file_end) + requests = {} + local result = PLUGIN:PreInstall({ version = version }) + assert(result.version == expected, version .. ": expected " .. expected .. ", got " .. tostring(result.version)) + assert(result.url:sub(-#file_end) == file_end, version .. ": expected ..." .. file_end .. ", got " .. result.url) + local asked = require("distribution_version").parse_version(version).version:gsub("%+", "%%2B") + local lookups = {} + for _, url in ipairs(requests) do + if url:sub(1, #JDKS) == JDKS then + table.insert(lookups, url) + end + end + assert( + #lookups == 1 + and lookups[1]:find("?version=&", 1, true) + and lookups[1]:sub(-#asked - 22) == "&distribution_version=" .. asked + and not lookups[1]:find("latest=", 1, true), + version .. ": unexpected lookups " .. table.concat(lookups, " ") + ) + cases = cases + 1 +end + +-- Mandrel and Liberica NIK install by the GraalVM numbers they go by, which +-- Foojay gave as java_version until October 2026 and now as +-- distribution_version (vfox-java#106). A longer version takes the release it +-- names, though Foojay lists 23.1.12.1 for 23.1.12 as well. +check_own_number("23.1.12-mandrel", "23.1.12-mandrel", "java21-linux-amd64-23.1.12.0-Final.tar.gz") +check_own_number("mandrel-23.1.12", "23.1.12-mandrel", "java21-linux-amd64-23.1.12.0-Final.tar.gz") +check_own_number("23.1.12.0-mandrel", "23.1.12-mandrel", "java21-linux-amd64-23.1.12.0-Final.tar.gz") +check_own_number("23.1.12.1-mandrel", "23.1.12.1-mandrel", "java21-linux-amd64-23.1.12.1-Final.tar.gz") +check_own_number("23.1.8-nik", "23.1.8-nik", "vm-openjdk21.0.8+13-23.1.8+1-linux-amd64.tar.gz") +check_own_number("23.1.8-nik-fx", "23.1.8-nik-fx", "vm-full-openjdk21.0.8+13-23.1.8+1-linux-amd64.tar.gz") +-- A bare major is theirs, not the JDK's, and takes the newest release, which +-- latest=available does not find: it answered 23.1.8 for 21 and 25.0.1 for 25. +check_own_number("23-mandrel", "23.1.12.1-mandrel", "java21-linux-amd64-23.1.12.1-Final.tar.gz") +check_own_number("25-mandrel", "25.0.4.1-mandrel", "java25-linux-amd64-25.0.4.1-Final.tar.gz") +check_own_number("24-mandrel", "24.2.2-mandrel", "java24-linux-amd64-24.2.2.0-Final.tar.gz") +check_own_number("23-nik", "23.1.12.1-nik", "vm-openjdk21.0.12.1+2-23.1.12.1+1-linux-amd64.tar.gz") +-- A release that comes for several JDKs installs the build for the newest. +check_own_number("21-mandrel", "21.3.6-mandrel", "java17-linux-amd64-21.3.6.0-Final.tar.gz") +check_own_number("23.0.1.2-mandrel", "23.0.1.2-mandrel", "java20-linux-amd64-23.0.1.2-Final.tar.gz") +check_own_number("liberica_native-21", "21.3.3.1-nik", "vm-openjdk17.0.5+8-21.3.3.1+1-linux-amd64.tar.gz") +check_own_number("22.3.5-nik", "22.3.5-nik", "vm-openjdk17.0.10+13-22.3.5+1-linux-amd64.tar.gz") +check_own_number("23.0.1-nik", "23.0.1-nik", "vm-openjdk20.0.2+10-23.0.1+1-linux-amd64.tar.gz") +-- Of two builds for the same JDK, BellSoft's later one installs. +check_own_number("25.0.3-nik", "25.0.3-nik", "vm-openjdk25.0.3+12-25.0.3+2-linux-amd64.tar.gz") +check_own_number("25.0.3-nik-fx", "25.0.3-nik-fx", "vm-full-openjdk25.0.3+12-25.0.3+2-linux-amd64.tar.gz") + +-- Searching lists their releases newest first by those numbers, each once with +-- the LTS note of the build that installs. Foojay lists them by JDK, 23.0.1.2 +-- for JDK 20 before 23.0.6 for JDK 17. JavaFX builds come in between. +for short, want in pairs({ + mandrel = "25.0.4.1-mandrel (LTS), 25.0.1-mandrel (LTS), 24.2.2-mandrel, 24.0.2-mandrel, 24-mandrel, " + .. "23.1.12.1-mandrel (LTS), 23.1.12-mandrel (LTS), 23.1.8-mandrel (LTS), 23.1.3.1-mandrel (LTS), " + .. "23.0.6-mandrel (LTS), 23.0.1.2-mandrel, 21.3.6-mandrel (LTS)", + nik = "25.0.4.1-nik (LTS), 25.0.3-nik (LTS), 24.1.2-nik, 23.1.12.1-nik (LTS), 23.1.8-nik (LTS), " + .. "23.0.3-nik (LTS), 23.0.1-nik (LTS), 22.3.5-nik, 21.3.3.1-nik", +}) do + for _, query in ipairs({ short, "all" }) do + local entries = {} + for _, item in ipairs(PLUGIN:Available({ args = { query } })) do + local entry = item.version .. (item.note == "" and "" or " (" .. item.note .. ")") + if item.version:sub(-#short - 1) == "-" .. short then + table.insert(entries, entry) + elseif item.version:sub(-#short - 4) == "-" .. short .. "-fx" then + assert(item.note:find("JavaFX$"), "Available " .. query .. ": " .. entry) + end + end + local got = table.concat(entries, ", ") + assert(got == want, ("Available %s lists %s, want %s"):format(query, got, want)) + end +end +assert(listed("nik")["23.1.8-nik-fx"] == "LTS, JavaFX", "Available nik: 23.1.8-nik-fx") + -- A distribution without a version, alone or after an empty one, asks for a -- version before any lookup (vfox-java#98). Alone it failed with a Lua error; -- the empty version reached Foojay, which listed every release, and the newest @@ -445,4 +624,17 @@ for _, case in ipairs({ assert(#requests == 0, case[1] .. ": unexpected lookup " .. tostring(requests[1])) end +-- A longer version of Mandrel or Liberica NIK installs only the release it +-- names, which has no build in its name: there is a Mandrel 23.1.3.1 but no +-- 23.1.3, and Liberica NIK 23.1.8 is named 23.1.8-nik. +for _, version in ipairs({ "23.1.3-mandrel", "23.1.8+1-nik", "26-mandrel" }) do + for i = #requests, 1, -1 do + requests[i] = nil + end + local ok, err = pcall(PLUGIN.PreInstall, PLUGIN, { version = version }) + local want = "No JDK found for " .. version .. " on linux/amd64" + assert(not ok and tostring(err):find(want, 1, true), version .. ": unexpected " .. tostring(err)) + assert(#requests == 1, version .. ": expected one lookup, got " .. #requests) +end + print("PASS: " .. cases .. " PreInstall Foojay lookup cases")