Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ jobs:
go-version: '1.24.0'
cache: false
- name: Test Java version resolution with vfox's Lua interpreter
run: go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/pre_use_test.lua
run: |
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/pre_use_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/loongnix_test.lua
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,25 @@ In an interactive terminal, run `vfox search java tem` to select and install a v

For a known version, use `vfox install java@17.0.17-tem`. Space-separated arguments to `install` identify multiple SDKs, so `vfox install java tem` does not pass `tem` as a Java distribution filter.

## LoongArch (Linux)

On Linux `loong64`, `vfox search java` (or `vfox search java loongnix`) lists JDKs from the [Loongnix official archive](https://ftp.loongnix.cn/Java/). Other architectures continue to use Foojay.

Choose the ABI matching your operating system; the plugin does not guess it:

- `lnxabi1` / `loongnix_abi1`: Linux 4.19 UAPI builds, intended for systems such as Loongnix 20 and Loongnix Server 8.4.
- `lnxabi2` / `loongnix_abi2`: Linux 5.10 UAPI builds, named `glibc2.34` upstream, intended for systems such as Debian 12 and openEuler.

See the [upstream compatibility notes](https://www.loongnix.cn/zh/api/java/) for your system. Do not choose solely from the running kernel version. This source provides glibc builds, not musl builds.

```shell
vfox search java lnxabi2
vfox install java@21-lnxabi2-fx # latest matching Java 21 with JavaFX, ABI2
vfox install java@21.0.12+8-lnxabi2-fx
```

Versions use the Java version and build number, not the Loongson release number. ABI and JavaFX suffixes are preserved when switching versions. Only GA LoongArch tarballs listed in the archive are supported; MIPS packages are excluded. Select `-fx` only for JavaFX builds. Bare installation requests require an explicit ABI; selecting a search result supplies it automatically.

## JavaFX Support

Some distributions provide JDK versions bundled with JavaFX. These versions are displayed with the `-fx` suffix after the distribution name in the version list and marked with "JavaFX" in the notes. To install a JavaFX bundled version, add `-fx` after the distribution name:
Expand Down
19 changes: 19 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@ vfox search java graal # 查看所有graalvm版本

已知版本时,使用 `vfox install java@17.0.17-tem`。`install` 的空格分隔参数用于指定多个 SDK,因此 `vfox install java tem` 不会将 `tem` 作为 Java 发行版筛选条件。

## 龙架构(Linux)

在 Linux `loong64` 上,`vfox search java`(或 `vfox search java loongnix`)从 [Loongnix 官方归档](https://ftp.loongnix.cn/Java/)列出 JDK。其他架构继续使用 Foojay。

请按操作系统选择 ABI,插件不会自动猜测:

- `lnxabi1` / `loongnix_abi1`:Linux 4.19 UAPI 构建,适用于 Loongnix 20、Loongnix Server 8.4 等系统。
- `lnxabi2` / `loongnix_abi2`:Linux 5.10 UAPI 构建,上游文件名标记为 `glibc2.34`,适用于 Debian 12、openEuler 等系统。

请核对[上游兼容性说明](https://www.loongnix.cn/zh/api/java/),不能仅凭当前内核版本选择 ABI。该源提供 glibc 构建,不提供 musl 构建。

```shell
vfox search java lnxabi2
vfox install java@21-lnxabi2-fx # 匹配最新的 Java 21,带 JavaFX,使用 ABI2
vfox install java@21.0.12+8-lnxabi2-fx
```

版本号采用 Java 版本及构建号,不是 Loongson 发行版本号。切换版本时保留 ABI 和 JavaFX 后缀。仅支持归档中的正式版 LoongArch tar 包,排除 MIPS 包;JavaFX 构建需使用 `-fx`。直接安装时必须明确 ABI,从搜索结果选择安装则会自动带上该标识。

## JavaFX 支持

部分发行版提供了捆绑 JavaFX 的 JDK 版本。这些版本在版本列表中会在发行版名称后显示 `-fx` 后缀,并在备注中标注 "JavaFX"。安装带 JavaFX 的版本时,需要在发行版名称后添加 `-fx`:
Expand Down
14 changes: 12 additions & 2 deletions hooks/available.lua
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
local foojay = require("foojay")
local loongnix = require("loongnix")
local distribution_version_parser = require("distribution_version")

--- Return all available versions provided by this plugin
--- @param ctx table Empty table used as context, for future extension
--- @return table Descriptions of available versions and accompanying tool descriptions
function PLUGIN:Available(ctx)
local query = ctx.args[1] or "open"
local query = ctx.args[1] or (loongnix.supported() and "loongnix" or "open")
if query == "loongnix" or loongnix.is_distribution(query) or (loongnix.supported() and query == "all") then
return loongnix.available(query)
end
if loongnix.supported() then
error("Foojay does not support loong64; use vfox search java loongnix")
end
local jdks = {}
local distribution = nil

if query == "all" then
for _, dist in ipairs(distribution_version_parser.distributions) do
local tempJdks = foojay.fetchtJdkList(dist.name, "")
local tempJdks = {}
if not loongnix.is_distribution(dist.name) then
tempJdks = foojay.fetchtJdkList(dist.name, "")
end
for _, jdk in ipairs(tempJdks) do
jdk.short = dist.short_name
table.insert(jdks, jdk)
Expand Down
4 changes: 4 additions & 0 deletions hooks/pre_install.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ local http = require("http")
local json = require("json")

local foojay = require("foojay")
local loongnix = require("loongnix")
local distribution_version_parser = require("distribution_version")
--- Returns some pre-installed information, such as version number, download address, local files, etc.
--- If checksum is provided, vfox will automatically check it for you.
Expand All @@ -13,6 +14,9 @@ function PLUGIN:PreInstall(ctx)
if not distribution_version then
error("Could not extract a valid distribution: " .. ctx.version)
end
if loongnix.supported() or loongnix.is_distribution(distribution_version.distribution.name) then
return loongnix.pre_install(distribution_version)
end
local jdks = foojay.fetchtJdkList(distribution_version.distribution.name, distribution_version.version)
if not jdks or #jdks == 0 then
error("No JDK found for " .. ctx.version .. " on " .. RUNTIME.osType .. "/" .. RUNTIME.archType .. ". Please check available versions with 'vfox search java'")
Expand Down
2 changes: 2 additions & 0 deletions lib/distribution_version.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ local strings = require("vfox.strings")

local short_name = {
["open"] = "openjdk",
["lnxabi1"] = "loongnix_abi1",
["lnxabi2"] = "loongnix_abi2",
["bsg"] = "bisheng",
["amzn"] = "corretto",
["albba"] = "dragonwell",
Expand Down
143 changes: 143 additions & 0 deletions lib/loongnix.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
local http = require('http')
local loongnix = {}
local base_url = 'https://ftp.loongnix.cn/Java/'

function loongnix.supported()
return RUNTIME.osType == 'linux' and RUNTIME.archType == 'loong64'
end

function loongnix.is_distribution(name)
return name == 'lnxabi1' or name == 'lnxabi2'
or name == 'loongnix_abi1' or name == 'loongnix_abi2'
end

local function require_platform()
if not loongnix.supported() then
error('Loongnix JDKs require linux/loong64')
end
end

local function get(url)
local response, err = http.get({url = url})
if err then error('Failed to fetch Loongnix JDKs: ' .. err) end
if response.status_code ~= 200 then
error('Failed to fetch Loongnix JDKs: status_code => ' .. response.status_code)
end
return response.body
end

local function numbers(version)
local result = {}
for number in version:gmatch('%d+') do table.insert(result, tonumber(number)) end
return result
end

local function newer(left, right)
local a, b = numbers(left), numbers(right)
for i = 1, math.max(#a, #b) do
if (a[i] or 0) ~= (b[i] or 0) then return (a[i] or 0) > (b[i] or 0) end
end
return false
end

local function newer_java(left, right)
local av, ab = left:match('^(.-)%+(%d+)$')
local bv, bb = right:match('^(.-)%+(%d+)$')
if newer(av, bv) then return true end
if newer(bv, av) then return false end
return tonumber(ab) > tonumber(bb)
end

-- Parse only GA LoongArch tarballs; exclude MIPS, EA, installers and checksum files.
local function parse(filename, major)
local release, rest = filename:match('^loongson([%d%.]+)%-(.+)$')
if not release then release, rest = filename:match('^loongson_openjdk([%d%.]+)%-(.+)$') end
if not release then return nil end
local fx = rest:sub(1, 3) == 'fx-'
if fx then rest = rest:sub(4) end
local jdk, suffix = rest:match('^jdk([%w%._]+)%-linux%-loongarch64(.*)$')
local abi
if suffix == '.tar.gz' then abi = 'lnxabi1'
elseif suffix == '-glibc2.34.tar.gz' then abi = 'lnxabi2'
else return nil end
local version, build = jdk:match('^(%d+%.?[%d%.]*)_(%d+)$')
if not version then
local update
update, build = jdk:match('^8u(%d+)b(%d+)$')
if update then version = '8.0.' .. update end
end
if not version or tonumber(version:match('^%d+')) ~= tonumber(major) then return nil end
version = version .. '+' .. tonumber(build)
return {
version = version .. '-' .. abi .. (fx and '-fx' or ''),
java_version = version, release = release, abi = abi, fx = fx,
url = base_url .. 'openjdk' .. major .. '/' .. filename,
note = 'JDK ' .. version .. '; ' .. (abi == 'lnxabi1' and 'ABI1 (Linux 4.19 UAPI)' or 'ABI2 (Linux 5.10 UAPI, glibc 2.34)')
.. (fx and '; JavaFX' or ''),
}
end

local function packages(version)
require_platform()
local index = get(base_url)
local majors, seen = {}, {}
local requested_major = version and version:match('^(%d+)')
for major in index:gmatch('href=["\']openjdk(%d+)/["\']') do
if not seen[major] and (not requested_major or tonumber(major) == tonumber(requested_major)) then
seen[major] = true
table.insert(majors, major)
end
end
local result, by_version = {}, {}
for _, major in ipairs(majors) do
local body = get(base_url .. 'openjdk' .. major .. '/')
for filename in body:gmatch('href=["\']([^"\'/]+)["\']') do
local item = parse(filename, major)
if item then
local previous = by_version[item.version]
if not previous or newer(item.release, previous.release) then by_version[item.version] = item end
end
end
end
for _, item in pairs(by_version) do table.insert(result, item) end
table.sort(result, function(a, b)
if a.java_version ~= b.java_version then return newer_java(a.java_version, b.java_version) end
return a.version < b.version
end)
if #result == 0 then error('No Loongnix JDK packages found; check the requested version and upstream directory format') end
return result
end

function loongnix.available(query)
local abi = query == 'loongnix_abi1' and 'lnxabi1' or query == 'loongnix_abi2' and 'lnxabi2' or query
local result = {}
for _, item in ipairs(packages()) do
if not loongnix.is_distribution(abi) or item.abi == abi then
table.insert(result, {version = item.version, note = item.note})
end
end
return result
end

local function matches(candidate, requested)
if candidate == requested then return true end
if candidate:sub(1, #requested) ~= requested then return false end
local boundary = candidate:sub(#requested + 1, #requested + 1)
return boundary == '.' or boundary == '+'
end

function loongnix.pre_install(parsed)
require_platform()
local abi = parsed.distribution.short_name
if not loongnix.is_distribution(abi) then
error('Choose a Loongnix ABI explicitly: run vfox search java and select lnxabi1 or lnxabi2')
end
for _, item in ipairs(packages(parsed.version)) do
if item.abi == abi and item.fx == parsed.javafx_bundled and matches(item.java_version, parsed.version) then
return {version = item.version, url = item.url, note = item.note}
end
end
error('No Loongnix JDK found for ' .. parsed.version .. '-' .. abi .. (parsed.javafx_bundled and '-fx' or ''))
end

return loongnix
4 changes: 4 additions & 0 deletions tests/fixtures/loongnix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
These fixtures preserve the tarball link names from https://ftp.loongnix.cn/Java/
and its openjdk*/ directories, retrieved on 2026-09-12. Styling and unrelated
links were removed. They include both LoongArch ABIs, MIPS and early-access
packages so the tests can verify filtering without network access.
9 changes: 9 additions & 0 deletions tests/fixtures/loongnix/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<a href="openjdk11/">openjdk11/</a>
<a href="openjdk17/">openjdk17/</a>
<a href="openjdk21/">openjdk21/</a>
<a href="openjdk22/">openjdk22/</a>
<a href="openjdk23/">openjdk23/</a>
<a href="openjdk24/">openjdk24/</a>
<a href="openjdk25/">openjdk25/</a>
<a href="openjdk26/">openjdk26/</a>
<a href="openjdk8/">openjdk8/</a>
41 changes: 41 additions & 0 deletions tests/fixtures/loongnix/openjdk11.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<a href="loongson11.0.2138-ea-jdk11.0.12_7-linux-loongarch64.tar.gz">loongson11.0.2138-ea-jdk11.0.12_7-linux-loongarch64.tar.gz</a>
<a href="loongson11.0.2138-ea-jdk11.0.12_7-linux-loongson3a.tar.gz">loongson11.0.2138-ea-jdk11.0.12_7-linux-loongson3a.tar.gz</a>
<a href="loongson11.1.0-jdk11.0.13_8-linux-loongarch64.tar.gz">loongson11.1.0-jdk11.0.13_8-linux-loongarch64.tar.gz</a>
<a href="loongson11.1.0-jdk11.0.13_8-linux-loongson3a.tar.gz">loongson11.1.0-jdk11.0.13_8-linux-loongson3a.tar.gz</a>
<a href="loongson11.10.0-fx-jdk11.0.23_9-linux-loongarch64.tar.gz">loongson11.10.0-fx-jdk11.0.23_9-linux-loongarch64.tar.gz</a>
<a href="loongson11.10.0-fx-jdk11.0.23_9-linux-loongson3a.tar.gz">loongson11.10.0-fx-jdk11.0.23_9-linux-loongson3a.tar.gz</a>
<a href="loongson11.11.25-fx-jdk11.0.24_8-linux-loongarch64.tar.gz">loongson11.11.25-fx-jdk11.0.24_8-linux-loongarch64.tar.gz</a>
<a href="loongson11.11.25-fx-jdk11.0.24_8-linux-loongson3a.tar.gz">loongson11.11.25-fx-jdk11.0.24_8-linux-loongson3a.tar.gz</a>
<a href="loongson11.12.20-fx-jdk11.0.25_9-linux-loongarch64-glibc2.34.tar.gz">loongson11.12.20-fx-jdk11.0.25_9-linux-loongarch64-glibc2.34.tar.gz</a>
<a href="loongson11.12.20-fx-jdk11.0.25_9-linux-loongarch64.tar.gz">loongson11.12.20-fx-jdk11.0.25_9-linux-loongarch64.tar.gz</a>
<a href="loongson11.12.20-fx-jdk11.0.25_9-linux-loongson3a.tar.gz">loongson11.12.20-fx-jdk11.0.25_9-linux-loongson3a.tar.gz</a>
<a href="loongson11.13.21-fx-jdk11.0.26_4-linux-loongarch64-glibc2.34.tar.gz">loongson11.13.21-fx-jdk11.0.26_4-linux-loongarch64-glibc2.34.tar.gz</a>
<a href="loongson11.13.21-fx-jdk11.0.26_4-linux-loongarch64.tar.gz">loongson11.13.21-fx-jdk11.0.26_4-linux-loongarch64.tar.gz</a>
<a href="loongson11.13.21-fx-jdk11.0.26_4-linux-loongson3a.tar.gz">loongson11.13.21-fx-jdk11.0.26_4-linux-loongson3a.tar.gz</a>
<a href="loongson11.14.18-fx-jdk11.0.27_6-linux-loongarch64-glibc2.34.tar.gz">loongson11.14.18-fx-jdk11.0.27_6-linux-loongarch64-glibc2.34.tar.gz</a>
<a href="loongson11.14.18-fx-jdk11.0.27_6-linux-loongarch64.tar.gz">loongson11.14.18-fx-jdk11.0.27_6-linux-loongarch64.tar.gz</a>
<a href="loongson11.15.21-fx-jdk11.0.28_6-linux-loongarch64-glibc2.34.tar.gz">loongson11.15.21-fx-jdk11.0.28_6-linux-loongarch64-glibc2.34.tar.gz</a>
<a href="loongson11.15.21-fx-jdk11.0.28_6-linux-loongarch64.tar.gz">loongson11.15.21-fx-jdk11.0.28_6-linux-loongarch64.tar.gz</a>
<a href="loongson11.16.22-fx-jdk11.0.29_7-linux-loongarch64-glibc2.34.tar.gz">loongson11.16.22-fx-jdk11.0.29_7-linux-loongarch64-glibc2.34.tar.gz</a>
<a href="loongson11.16.22-fx-jdk11.0.29_7-linux-loongarch64.tar.gz">loongson11.16.22-fx-jdk11.0.29_7-linux-loongarch64.tar.gz</a>
<a href="loongson11.17.26-fx-jdk11.0.30_7-linux-loongarch64-glibc2.34.tar.gz">loongson11.17.26-fx-jdk11.0.30_7-linux-loongarch64-glibc2.34.tar.gz</a>
<a href="loongson11.17.26-fx-jdk11.0.30_7-linux-loongarch64.tar.gz">loongson11.17.26-fx-jdk11.0.30_7-linux-loongarch64.tar.gz</a>
<a href="loongson11.18.27-fx-jdk11.0.31_11-linux-loongarch64-glibc2.34.tar.gz">loongson11.18.27-fx-jdk11.0.31_11-linux-loongarch64-glibc2.34.tar.gz</a>
<a href="loongson11.18.27-fx-jdk11.0.31_11-linux-loongarch64.tar.gz">loongson11.18.27-fx-jdk11.0.31_11-linux-loongarch64.tar.gz</a>
<a href="loongson11.19.27-fx-jdk11.0.32_9-linux-loongarch64-glibc2.34.tar.gz">loongson11.19.27-fx-jdk11.0.32_9-linux-loongarch64-glibc2.34.tar.gz</a>
<a href="loongson11.19.27-fx-jdk11.0.32_9-linux-loongarch64.tar.gz">loongson11.19.27-fx-jdk11.0.32_9-linux-loongarch64.tar.gz</a>
<a href="loongson11.2.0-jdk11.0.15_10-linux-loongarch64.tar.gz">loongson11.2.0-jdk11.0.15_10-linux-loongarch64.tar.gz</a>
<a href="loongson11.2.0-jdk11.0.15_10-linux-loongson3a.tar.gz">loongson11.2.0-jdk11.0.15_10-linux-loongson3a.tar.gz</a>
<a href="loongson11.3.0-fx-jdk11.0.17_8-linux-loongarch64.tar.gz">loongson11.3.0-fx-jdk11.0.17_8-linux-loongarch64.tar.gz</a>
<a href="loongson11.3.0-fx-jdk11.0.17_8-linux-loongson3a.tar.gz">loongson11.3.0-fx-jdk11.0.17_8-linux-loongson3a.tar.gz</a>
<a href="loongson11.4.0-fx-jdk11.0.18_10-linux-loongarch64.tar.gz">loongson11.4.0-fx-jdk11.0.18_10-linux-loongarch64.tar.gz</a>
<a href="loongson11.4.0-fx-jdk11.0.18_10-linux-loongson3a.tar.gz">loongson11.4.0-fx-jdk11.0.18_10-linux-loongson3a.tar.gz</a>
<a href="loongson11.5.0-fx-jdk11.0.19_7-linux-loongarch64.tar.gz">loongson11.5.0-fx-jdk11.0.19_7-linux-loongarch64.tar.gz</a>
<a href="loongson11.5.0-fx-jdk11.0.19_7-linux-loongson3a.tar.gz">loongson11.5.0-fx-jdk11.0.19_7-linux-loongson3a.tar.gz</a>
<a href="loongson11.6.0-fx-jdk11.0.19_7-linux-loongarch64.tar.gz">loongson11.6.0-fx-jdk11.0.19_7-linux-loongarch64.tar.gz</a>
<a href="loongson11.7.0-fx-jdk11.0.20_8-linux-loongarch64.tar.gz">loongson11.7.0-fx-jdk11.0.20_8-linux-loongarch64.tar.gz</a>
<a href="loongson11.7.0-fx-jdk11.0.20_8-linux-loongson3a.tar.gz">loongson11.7.0-fx-jdk11.0.20_8-linux-loongson3a.tar.gz</a>
<a href="loongson11.8.0-fx-jdk11.0.21_9-linux-loongarch64.tar.gz">loongson11.8.0-fx-jdk11.0.21_9-linux-loongarch64.tar.gz</a>
<a href="loongson11.8.0-fx-jdk11.0.21_9-linux-loongson3a.tar.gz">loongson11.8.0-fx-jdk11.0.21_9-linux-loongson3a.tar.gz</a>
<a href="loongson11.9.0-fx-jdk11.0.22_7-linux-loongarch64.tar.gz">loongson11.9.0-fx-jdk11.0.22_7-linux-loongarch64.tar.gz</a>
<a href="loongson11.9.0-fx-jdk11.0.22_7-linux-loongson3a.tar.gz">loongson11.9.0-fx-jdk11.0.22_7-linux-loongson3a.tar.gz</a>
Loading