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
19 changes: 13 additions & 6 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
# amd64/arm64 through Docker Desktop's Linux-container mode. It carries the
# pinned Go toolchain the E2E suites and the local checks need, matching the
# setup-go version CI uses, plus the Lua and license tooling pinned in the
# lint and license workflows.
# lint and license workflows, and the vfox release that runs the hook tests
# (vfox plugin test) in the test workflow.
#
# The suites themselves run testcontainers against the host daemon through
# the socket mounted by devcontainer.json (Docker-out-of-Docker), so the
# target containers are spawned exactly as a native CI runner spawns them.
#
# The image is multi-arch (linux/amd64 and linux/arm64); the Lua downloads
# below select their asset per target arch.
# The image is multi-arch (linux/amd64 and linux/arm64); the Lua and vfox
# downloads below select their asset per target arch.

FROM golang:1.27.1

Expand All @@ -34,9 +35,10 @@ FROM golang:1.27.1
COPY --from=docker:29-cli /usr/local/bin/docker /usr/local/bin/docker

# Keep the tool versions below in step with .github/workflows/lint.yml
# (stylua-action's version and the `mise x aqua:...` line).
# (stylua-action's version and the `mise x aqua:...` line) and test.yml (vfox).
ARG STYLUA_VERSION=2.5.2
ARG LUA_LANGUAGE_SERVER_VERSION=3.19.1
ARG VFOX_VERSION=1.0.13

# Heredocs need BuildKit, which the dev container tooling uses by default. The
# E2E target Dockerfiles stay on the chained-`;` form: testcontainers-go's
Expand All @@ -53,8 +55,8 @@ apt-get install --assume-yes --no-install-recommends \
zip
rm --recursive --force /var/lib/apt/lists/*
case "$(dpkg --print-architecture)" in
amd64) stylua_asset=stylua-linux-x86_64.zip; luals_asset="lua-language-server-${LUA_LANGUAGE_SERVER_VERSION}-linux-x64.tar.gz" ;;
arm64) stylua_asset=stylua-linux-aarch64.zip; luals_asset="lua-language-server-${LUA_LANGUAGE_SERVER_VERSION}-linux-arm64.tar.gz" ;;
amd64) stylua_asset=stylua-linux-x86_64.zip; luals_asset="lua-language-server-${LUA_LANGUAGE_SERVER_VERSION}-linux-x64.tar.gz"; vfox_dir="vfox_${VFOX_VERSION}_linux_x86_64" ;;
arm64) stylua_asset=stylua-linux-aarch64.zip; luals_asset="lua-language-server-${LUA_LANGUAGE_SERVER_VERSION}-linux-arm64.tar.gz"; vfox_dir="vfox_${VFOX_VERSION}_linux_aarch64" ;;
*) echo "FAIL unsupported architecture $(dpkg --print-architecture)" >&2; exit 1 ;;
esac
curl --fail --silent --show-error --location --output /tmp/stylua.zip \
Expand All @@ -67,8 +69,13 @@ mkdir --parents /opt/lua-language-server
tar --extract --gzip --file /tmp/luals.tar.gz --directory /opt/lua-language-server
rm --force /tmp/luals.tar.gz
ln --symbolic /opt/lua-language-server/bin/lua-language-server /usr/local/bin/lua-language-server
curl --fail --silent --show-error --location --output /tmp/vfox.tar.gz \
"https://github.com/version-fox/vfox/releases/download/v${VFOX_VERSION}/${vfox_dir}.tar.gz"
tar --extract --gzip --file /tmp/vfox.tar.gz --directory /usr/local/bin --strip-components=1 "${vfox_dir}/vfox"
rm --force /tmp/vfox.tar.gz
stylua --version
lua-language-server --version
vfox --version
EOF

# License-header tooling at the versions pinned by .github/workflows/license.yml
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ permissions:
contents: read

concurrency:
group: e2e-${{ github.ref }}
cancel-in-progress: true
# A new push to a pull request replaces the run of the push before it. Every
# commit on main gets a group of its own instead: in one shared group a newer
# commit cancels the run of the older, and re-running the older cancels the
# newer in turn, so one of the two never ends with a result.
group: e2e-${{ github.event_name == 'pull_request' && github.ref || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

# The Linux job runs the suite natively, the way the dev container runs it
# locally: Go at the dev container's version (.devcontainer/Dockerfile) plus
Expand Down
36 changes: 26 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,32 @@ jobs:
with:
go-version: '1.24.0'
cache: false
- name: Test Java version resolution with vfox's Lua interpreter
# vfox plugin test came with vfox 1.0.13. The release is pinned and its
# checksum checked, as the actions are pinned by their commits; change the
# two together to move to another release.
- name: Install vfox
env:
VFOX_VERSION: 1.0.13
VFOX_SHA256: 7ad0a4c82c8173f09393e09abecc3e27468253bab5fe53ffbf58f2b12b3fc768
run: |
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/pre_install_test.lua
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/parse_legacy_file_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/loongnix_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/github_mirror_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/checksum_test.lua
- name: Test macOS Java home normalization
run: go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/post_install_test.lua
archive="$RUNNER_TEMP/vfox.tar.gz"
curl --fail --silent --show-error --location --output "$archive" \
"https://github.com/version-fox/vfox/releases/download/v${VFOX_VERSION}/vfox_${VFOX_VERSION}_linux_x86_64.tar.gz"
echo "$VFOX_SHA256 $archive" | sha256sum --check
mkdir "$RUNNER_TEMP/vfox"
tar --extract --gzip --file "$archive" --directory "$RUNNER_TEMP/vfox" --strip-components=1 \
"vfox_${VFOX_VERSION}_linux_x86_64/vfox"
echo "$RUNNER_TEMP/vfox" >> "$GITHUB_PATH"
# It finds tests/**/*_test.lua and runs each file in a VM of its own. A file
# that does not call test.load() from vfox.test fails, and so does a run
# that finds no test file.
- name: Run the offline hook tests with vfox
run: vfox plugin test .
# PostInstall's shell script runs for real here, on directories the test
# makes, and vfox plugin test disables os.execute. So this file is not a
# *_test.lua, and it runs under glua, as it does on macOS below.
- name: Test the macOS Java home layouts with vfox's Lua interpreter
run: go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/post_install_layouts.lua
macos-layout:
runs-on: macos-latest
steps:
Expand All @@ -55,4 +71,4 @@ jobs:
go-version: '1.24.0'
cache: false
- name: Test actual macOS filesystem layouts
run: go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/post_install_test.lua
run: go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/post_install_layouts.lua
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ Not every distribution has builds for arm64, Alpine or Windows on ARM. Only Temu

Zulu, Liberica, Liberica NIK and Corretto (Java 8 only) have builds with JavaFX bundled. Add `-fx` after the distribution, as in `java@21-zulu-fx`. See [docs/javafx.md](docs/javafx.md) for details.

## Native Image

A GraalVM installs and runs like any other JDK. Only `native-image`, which builds native executables, needs a C compiler and zlib's headers on top, and a minimal Ubuntu, such as its container image, has neither. Install them once, before the first native build:

```bash
sudo apt install --assume-yes build-essential zlib1g-dev
```

GraalVM CE 8 to 19 come without `native-image` and need it added first. See [docs/distributions.md](docs/distributions.md#native-image-and-the-c-toolchain) for what `native-image` prints without these packages, for other systems, and for adding it.

## `.sdkmanrc`

vfox reads the `java=` line of SDKMAN's `.sdkmanrc` through this plugin and selects a JDK that is already installed. See [docs/sdkmanrc.md](docs/sdkmanrc.md) for details.
Expand All @@ -92,7 +102,7 @@ To see which JDKs exist for your platform, ask Foojay yourself. [docs/foojay.md]

## Troubleshooting

See [docs/troubleshooting.md](docs/troubleshooting.md) for the messages the plugin prints, proxies and where the JDK is.
See [docs/troubleshooting.md](docs/troubleshooting.md) for the messages the plugin and `native-image` print, proxies and where the JDK is.

## Install from source

Expand Down
12 changes: 11 additions & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ java -version

Zulu、Liberica、Liberica NIK 和 Corretto(只有 Java 8)提供内置 JavaFX 的构建,在发行版后面加 `-fx` 即可,比如 `java@21-zulu-fx`。详见 [docs/zh-CN/javafx.md](docs/zh-CN/javafx.md)。

## Native Image

GraalVM 的安装和使用与别的 JDK 没有两样。只有用来构建原生可执行文件的 `native-image` 还需要 C 编译器和 zlib 的头文件,而最小化的 Ubuntu(比如它的容器镜像)两样都没有。第一次构建原生镜像之前装一次:

```bash
sudo apt install --assume-yes build-essential zlib1g-dev
```

GraalVM CE 8 到 19 不带 `native-image`,要先添加。没有这些包时 `native-image` 的报错、其他系统的做法以及怎样添加,见 [docs/zh-CN/distributions.md](docs/zh-CN/distributions.md#native-image-与-c-工具链)。

## `.sdkmanrc`

vfox 通过这个插件读取 SDKMAN 的 `.sdkmanrc` 里的 `java=` 一行,并选中已经安装的 JDK。详见 [docs/zh-CN/sdkmanrc.md](docs/zh-CN/sdkmanrc.md)。
Expand All @@ -92,7 +102,7 @@ vfox 通过这个插件读取 SDKMAN 的 `.sdkmanrc` 里的 `java=` 一行,并

## 问题排查

插件的各种提示、代理设置和 JDK 的位置,见 [docs/zh-CN/troubleshooting.md](docs/zh-CN/troubleshooting.md)。
插件和 `native-image` 的各种提示、代理设置和 JDK 的位置,见 [docs/zh-CN/troubleshooting.md](docs/zh-CN/troubleshooting.md)。

## 从源码安装

Expand Down
28 changes: 18 additions & 10 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ lib/foojay.lua the Foojay request, and fixes to what it answers
lib/github_mirror.lua the mirror of the downloads from GitHub
lib/installed_version.lua matching against installed names
lib/loongnix.lua the Loongnix archive
tests/*_test.lua offline hook tests
tests/*_test.lua offline hook tests, run by vfox plugin test
tests/post_install_layouts.lua the macOS layouts PostInstall handles, with its real shell script
tests/fixtures/loongnix/ a saved copy of the Loongnix archive listing
tests/e2e/ container tests, see e2e.md
Injection.lua type hints for what vfox injects, never loaded
Expand Down Expand Up @@ -69,19 +70,26 @@ SDKMAN spells some things differently (`jbr`, `21.0.12.fx-zulu`, `21.0.12-fx+1.1

## Tests

The hook tests run offline under `gopher-lua`, the Lua interpreter vfox embeds:
The hook tests run offline under `vfox plugin test`, which vfox 1.0.13 and later has. It finds every `tests/**/*_test.lua` and runs each file in a VM of its own, so a new test file needs no entry anywhere:

```bash
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/pre_install_test.lua
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/parse_legacy_file_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/loongnix_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/github_mirror_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/checksum_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/post_install_test.lua
vfox plugin test .
vfox plugin test . --file tests/pre_use_test.lua
```

Run them from the repository root. All seven load `tests/support.lua`, which stubs `vfox.strings`, and `tests/pre_install_test.lua` and `tests/loongnix_test.lua` stub `http` and `json` themselves. `tests/pre_install_test.lua` keeps Foojay's answers in a table at the top, keyed by `<distribution> [<version>]`, with `windows` or `macos` in front for those systems. Add the answer a new case needs there, and note the day you observed it. Lint, license headers and the container tests are in [e2e.md](e2e.md#local-checks).
Run it from the repository root. The Test Plugin workflow installs the release pinned in `.github/workflows/test.yml`, and the dev container carries the same one.

A test file calls `test.load()` from `vfox.test` once, and calls the real hooks through what it returns, as in `plugin:PreInstall({ version = "21-tem" })`. `test.load` takes the platform (`os`, `arch`), the environment variables (`env`) and a function that answers every HTTP request (`http`). The modules in `lib` can be required after it, and `RUNTIME.osType` and `RUNTIME.archType` can be changed to try another platform. See vfox's [Test and debug a plugin](https://vfox.dev/plugins/create/testing.html). The context and the result of a hook go through the decoding vfox does, so a hook that returns a bare string where vfox wants a table fails the test, and a string the result lacks comes back as `""`, not `nil`.

The VM disables `os.execute` and `io.popen`, so `tests/pre_install_test.lua` answers the `ldd --version` that decides between glibc and musl itself. It keeps Foojay's answers in a table at the top, keyed by `<distribution> [<version>]`, with `windows` or `macos` in front for those systems, and its `http` function sends them as JSON. Add the answer a new case needs there, and note the day you observed it.

`tests/post_install_layouts.lua` is the one test that is not a `*_test.lua`: it runs the shell script of `PostInstall` on directories it makes, which the VM does not allow. It runs under `gopher-lua`, the Lua interpreter vfox embeds:

```bash
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/post_install_layouts.lua
```

Lint, license headers and the container tests are in [e2e.md](e2e.md#local-checks).

To call a single hook against the real Foojay, vfox 1.0.13 and later has `vfox plugin run`. It does not register the plugin, and `--os` and `--arch` answer for another platform:

Expand Down
20 changes: 20 additions & 0 deletions docs/distributions.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,26 @@ GraalVM CE 8 to 19, Gluon GraalVM before 23, and Mandrel and Liberica NIK before
- The plugin sets `JAVA_HOME` and `PATH`, and no `GRAALVM_HOME`. A `GRAALVM_HOME` that points at a GraalVM of your own stays as it is, and the native-image build plugins fall back to `JAVA_HOME` when it is unset.
- There is no Windows ARM64 and no Alpine build, and Intel Macs get nothing after 25.0.1. See [platforms.md](platforms.md#graalvm).

### Native Image and the C toolchain

A GraalVM installs and runs like any other JDK. After `vfox install java@25.0.2-graalce` and `vfox use`, `java` and `javac` work on a system with no compiler and no zlib headers. `sudo apt install --assume-yes build-essential zlib1g-dev` is for `native-image` alone, the tool that compiles a program into a native executable. It links the executable with the system's `gcc` against the C library and zlib, so it needs them, and so does whatever calls it, such as the Maven and Gradle plugins for Native Image. The plugin installs the JDK and nothing else.

On Ubuntu 26.04, execute in Bash,

```bash
sudo apt install --assume-yes build-essential zlib1g-dev
```

- `native-image` is in the `bin` directory of Oracle GraalVM, GraalVM Community, Liberica NIK, Mandrel and Gluon GraalVM. GraalVM CE 8 to 19 are the exception, see below.
- Without `gcc` the build stops within seconds with `Error: Default native-compiler executable 'gcc' not found via environment variable PATH`, and `zlib1g-dev` alone does not change that.
- With `gcc` but without `zlib1g-dev`, which is what `build-essential` alone gives, the build goes through the analysis and the compilation first, which took between 20 seconds and two minutes for a hello world, and fails when it links: `There was an error linking the native image: Linker command exited with 1`, GraalVM's hint `It appears as though libz:.a is missing. Please install it.`, and `cannot find -lz: No such file or directory`.
- `gcc`, `libc6-dev` and `zlib1g-dev` were enough to build a hello world, without `g++` and `make`. `build-essential` brings both, and is what GraalVM's documentation lists.
- Other systems need other packages. GraalVM's [prerequisites](https://www.graalvm.org/latest/reference-manual/native-image/#prerequisites) list `sudo dnf install gcc glibc-devel zlib-devel libstdc++-static` for Fedora and the other systems that use dnf, `xcode-select --install` for macOS, and the Visual Studio Build Tools with the Windows SDK for Windows. On Fedora 44, `gcc`, `glibc-devel` and `zlib-devel` built a hello world without `libstdc++-static`.

GraalVM CE 8 to 19 (`grl8`, `grl11`, `grl16`, `grl17`, `grl19`) come without `native-image`. Their `bin` directory holds `gu`, the GraalVM Updater, and `native-image` is `command not found` until `gu install native-image` has added it from GitHub. That worked for `22.3.3-grl11`, `21.2-grl16`, `22.3.3-grl17` and `22.3.1-grl19` on 2026-11-02, and the packages above are needed after it as before. It failed for `21.3.1-grl8` with `Internal error occurred: A JSONObject text must begin with '{'`, because the release index that this `gu` downloads, `https://oca.opensource.oracle.com/gds/meta-data.json`, is a web page now. For that release, download `native-image-installable-svm-java8-linux-amd64-21.3.1.jar` from the [`vm-21.3.1` release](https://github.com/graalvm/graalvm-ce-builds/releases/tag/vm-21.3.1) and run `gu -L install` on the file.

Checked on 2026-11-02 with vfox 1.0.13 in Ubuntu 26.04 container images (x64) that had no compiler. GraalVM Community 25.0.2 and 25.4.4.1.1, Oracle GraalVM 25.0.5, Mandrel 25.0.5, Liberica NIK 25.0.4.1 and Gluon GraalVM 22.1.0.1 stopped as described without the packages, and with them built a hello world that ran. So did `22.3.3-grl17` after `gu install native-image`, and GraalVM Community 25.0.2 in a Fedora 44 image.

## Others

### JetBrains Runtime (`jb`)
Expand Down
12 changes: 4 additions & 8 deletions docs/e2e.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

[中文](zh-CN/e2e.md) | [English](e2e.md)

The offline Lua hook tests (`tests/*_test.lua`) run in the **Test Plugin**
The offline Lua hook tests (`tests/*_test.lua` under `vfox plugin test`, and
`tests/post_install_layouts.lua` under `glua`) run in the **Test Plugin**
workflow. The end-to-end suite runs in containers against real vfox on Linux
and Windows; each `vfox` x `distribution` combination gets its own throwaway
container. CI runs the suite natively on the stock runners (Docker plus Go
Expand Down Expand Up @@ -406,13 +407,8 @@ lua-language-server --check . --checklevel=Warning

```bash
# Offline hook tests (.github/workflows/test.yml).
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/pre_install_test.lua
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/parse_legacy_file_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/loongnix_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/github_mirror_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/checksum_test.lua
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/post_install_test.lua
vfox plugin test .
go run github.com/yuin/gopher-lua/cmd/glua@v1.1.1 tests/post_install_layouts.lua
```

```bash
Expand Down
Loading
Loading