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
52 changes: 51 additions & 1 deletion .github/workflows/e2e_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
- name: add vfox-lua plugin
if: runner.os == 'Windows'
run: |
vfox add --source https://github.com/${{ github.repository_owner }}/vfox-lua/archive/$env:GITHUB_REF.zip lua
vfox add --source "https://github.com/${{ github.repository_owner }}/vfox-lua/archive/${env:GITHUB_REF}.zip" lua

- name: add vfox-lua plugin
if: runner.os != 'Windows'
Expand Down Expand Up @@ -269,3 +269,53 @@ jobs:
$HOME/.local/bin/mise exec -- luarocks --version
$HOME/.local/bin/mise exec -- luarocks install luacheck
$HOME/.local/bin/mise exec -- luarocks list | grep luacheck

windows_luabinaries_tests:
strategy:
matrix:
lua_version: [5.5.0, 5.4.8, 5.3.6]
runs-on: windows-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: '^1.24.2'

- name: build & install vfox
shell: pwsh
run: |
git clone https://github.com/version-fox/vfox.git
cd vfox
go build -o vfox.exe
echo "$pwd" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
./vfox.exe -version

- name: add vfox-lua plugin
shell: pwsh
run: |
vfox add --source "https://github.com/${{ github.repository_owner }}/vfox-lua/archive/${env:GITHUB_REF}.zip" lua

- name: install Lua from LuaBinaries by vfox-lua plugin
shell: pwsh
env:
LUA_VERSION: "${{ matrix.lua_version }}"
VFOX_LUA_WINDOWS_LUABINARIES: "1"
run: |
vfox install "lua@$env:LUA_VERSION"
Invoke-Expression "$(vfox activate pwsh)"
vfox use -g "lua@$env:LUA_VERSION"
Invoke-Expression "$(vfox activate pwsh)"
echo "===============PATH==============="
echo $env:PATH
echo "===============PATH==============="
$luaVersion = lua.exe -v
$luacVersion = luac.exe -v
if ($luaVersion -notmatch "Lua $env:LUA_VERSION") {
Write-Output "lua@$env:LUA_VERSION installed from LuaBinaries failed!"
exit 1
}
if ($luacVersion -notmatch "Lua $env:LUA_VERSION") {
Write-Output "luac@$env:LUA_VERSION installed from LuaBinaries failed!"
exit 1
}
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Lua [vfox](https://github.com/version-fox) plugin. Use the vfox to manage multip
- GCC compiler
- Make

Optional on Windows:
- Set `VFOX_LUA_WINDOWS_LUABINARIES=1` to install a prebuilt LuaBinaries package instead of compiling from source
- Supported LuaBinaries versions: `5.5.0`, `5.4.8`, `5.3.6`, `5.2.4`

## Usage

### Install with vfox
Expand All @@ -38,6 +42,15 @@ vfox install lua@5.4.7
vfox use -g lua@5.4.7
```

On Windows, you can opt into prebuilt LuaBinaries packages instead of the default MSYS2 source build:

```powershell
$env:VFOX_LUA_WINDOWS_LUABINARIES=1
vfox install lua@5.5.0
vfox use -g lua@5.5.0
lua -v
```

### Install with mise

The vfox-lua plugin can also be used through [mise](https://mise.jdx.dev/), which supports vfox plugins.
Expand Down Expand Up @@ -92,6 +105,8 @@ luarocks install luacheck

3. On Windows, use `PowerShell` to install Lua.

4. `VFOX_LUA_WINDOWS_LUABINARIES=1` is a Windows-only opt-in. If the requested version is not published by LuaBinaries, the install will fail and you should use the default source-build flow instead. The archive is downloaded from SourceForge's mirror autoselect over HTTPS; checksum verification is currently skipped because the redirected mirrors don't yield a stable hash. Prefer the default source-build flow if you require an integrity check.

## Known Issues

- Lua versions 5.0 and earlier cannot be installed on Linux.
Expand Down
17 changes: 16 additions & 1 deletion hooks/env_keys.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
function PLUGIN:EnvKeys(ctx)
local sdkInfo = ctx.sdkInfo["lua"]
local version = sdkInfo.version
local installDir = sdkInfo.path
local installDir = ctx.path

local shortVersion = string.match(version, "^(%d+%.%d+)")

Expand All @@ -16,6 +16,21 @@ function PLUGIN:EnvKeys(ctx)
},
}

-- LuaBinaries installs place lua.exe in the install root next to the DLL; MSYS2 source
-- builds only populate bin/. Detect the LuaBinaries layout by probing the file so PATH
-- stays correct on `vfox use` even when VFOX_LUA_WINDOWS_LUABINARIES (an install-time
-- opt-in) is no longer exported in the activation shell.
if RUNTIME.osType == "windows" then
local rootLua = io.open(installDir .. "/lua.exe", "r")
if rootLua ~= nil then
rootLua:close()
table.insert(envs, 1, {
key = "PATH",
value = installDir,
})
end
end

local luarocksBin = installDir .. "/luarocks/bin"
local f = io.open(luarocksBin, "r")
if f ~= nil then
Expand Down
70 changes: 70 additions & 0 deletions hooks/post_install.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
local Utils = require("utils")

--- Extension point, called after PreInstall, can perform additional operations,
--- such as file operations for the SDK installation directory or compile source code
function CheckBuildTools(osType)
Expand All @@ -22,6 +24,69 @@ Make sure make.exe and gcc.exe are in the System $env:PATH in PowerShell.
end
end

local function copy_file(src, dst)
local input = io.open(src, "rb")
if input == nil then
return false
end
local content = input:read("*a")
input:close()

local output = io.open(dst, "wb")
if output == nil then
return false
end
output:write(content)
output:close()
return true
end

local function file_exists(path)
local f = io.open(path, "rb")
if f == nil then
return false
end
f:close()
return true
end

local function InstallWindowsLuaBinaries(path, lua_version)
local pkg_meta = Utils.get_windows_luabinaries_package(lua_version)
if pkg_meta == nil then
error("LuaBinaries package metadata missing for version " .. lua_version)
end

-- LuaBinaries archives expand executables (lua54.exe, luac54.exe, ...) into the install
-- root next to the DLL. We add aliases (lua.exe, luac.exe, wlua.exe) in the same folder
-- so users can invoke them by their canonical names. env_keys.lua already prepends the
-- install root to PATH, so a separate bin/ directory isn't needed.
local lua_exe = path .. "\\" .. pkg_meta.executable_prefix .. ".exe"
if not file_exists(lua_exe) then
error("LuaBinaries executable not found at " .. lua_exe)
end

local copies = {
{ src = lua_exe, dst = path .. "\\lua.exe" },
}

local luac_prefix = "luac" .. string.sub(pkg_meta.executable_prefix, 4)
local luac_exe = path .. "\\" .. luac_prefix .. ".exe"
if file_exists(luac_exe) then
table.insert(copies, { src = luac_exe, dst = path .. "\\luac.exe" })
end

local wlua_exe = path .. "\\" .. pkg_meta.wlua_prefix .. ".exe"
if file_exists(wlua_exe) then
table.insert(copies, { src = wlua_exe, dst = path .. "\\wlua.exe" })
end

for _, item in ipairs(copies) do
if not copy_file(item.src, item.dst) then
error("failed to copy " .. item.src .. " to " .. item.dst)
end
end
end


function PLUGIN:PostInstall(ctx)
--- ctx.rootPath SDK installation directory
Expand All @@ -32,6 +97,11 @@ function PLUGIN:PostInstall(ctx)
local lua_version = sdkInfo.version
print(string.format("os type: %s, lua installed path: %s", RUNTIME.osType, path))

if RUNTIME.osType == "windows" and Utils.use_windows_luabinaries() then
InstallWindowsLuaBinaries(path, lua_version)
return
end

CheckBuildTools(RUNTIME.osType)
-- TODO: support install luajit
local status
Expand Down
22 changes: 21 additions & 1 deletion hooks/pre_install.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@ function PLUGIN:PreInstall(ctx)
local lua_version = ctx.version
local download_url

if RUNTIME.osType == "windows" and Utils.use_windows_luabinaries() then
local pkg_meta = Utils.get_windows_luabinaries_package(lua_version)
if pkg_meta == nil then
error("LuaBinaries does not provide a Windows binary for version " ..
lua_version .. ". Disable VFOX_LUA_WINDOWS_LUABINARIES or choose one of: " ..
Utils.get_windows_luabinaries_versions_text() .. ".")
end

print("lua download url: " .. pkg_meta.url)
-- LuaBinaries is distributed via SourceForge's mirror autoselect, which redirects to
-- a rotating set of mirrors. vfox computed checksums sometimes hashed the redirect HTML
-- instead of the archive bytes, so the integrity check was unreliable. Until upstream
-- publishes signed checksums we can pin, the opt-in install relies on HTTPS only —
-- documented as a trade-off in the README.
return {
version = lua_version,
url = pkg_meta.url,
}
end

local v, checksum = Utils.get_version_info(lua_version)
if not v then
error("Version " .. lua_version .. " not found in https://www.lua.org/ftp/.")
Expand All @@ -27,4 +47,4 @@ function PLUGIN:PreInstall(ctx)
url = download_url,
sha256 = checksum
}
end
end
74 changes: 74 additions & 0 deletions lib/utils.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
local http = require("http")

local lua_utils = {}
local windows_luabinaries_packages = {
["5.5.0"] = {
archive_name = "lua-5.5.0_Win64_bin.zip",
relative_path = "5.5.0/Tools%20Executables/lua-5.5.0_Win64_bin.zip",
executable_prefix = "lua55",
wlua_prefix = "wlua55",
dll_name = "lua55.dll",
},
["5.4.8"] = {
archive_name = "lua-5.4.8_Win64_bin.zip",
relative_path = "5.4.8/Tools%20Executables/lua-5.4.8_Win64_bin.zip",
executable_prefix = "lua54",
wlua_prefix = "wlua54",
dll_name = "lua54.dll",
},
["5.3.6"] = {
archive_name = "lua-5.3.6_Win64_bin.zip",
relative_path = "5.3.6/Tools%20Executables/lua-5.3.6_Win64_bin.zip",
executable_prefix = "lua53",
wlua_prefix = "wlua53",
dll_name = "lua53.dll",
},
["5.2.4"] = {
archive_name = "lua-5.2.4_Win64_bin.zip",
relative_path = "5.2.4/Tools%20Executables/lua-5.2.4_Win64_bin.zip",
executable_prefix = "lua52",
wlua_prefix = "wlua52",
dll_name = "lua52.dll",
},
}

local function parse_version_line(line)
return string.match(line, "([^,]+),([^,]+)")
Expand Down Expand Up @@ -42,6 +72,50 @@ function lua_utils.get_version_info(lua_version)
return nil, nil
end

function lua_utils.use_windows_luabinaries()
local flag = os.getenv("VFOX_LUA_WINDOWS_LUABINARIES")
return flag ~= nil and flag ~= "" and flag ~= "0" and flag ~= "false"
end

function lua_utils.get_windows_luabinaries_versions()
local versions = {}
for version, _ in pairs(windows_luabinaries_packages) do
table.insert(versions, version)
end
table.sort(versions, function(a, b)
return a > b
end)
return versions
end

function lua_utils.get_windows_luabinaries_versions_text()
return table.concat(lua_utils.get_windows_luabinaries_versions(), ", ")
end

function lua_utils.get_windows_luabinaries_package(lua_version)
if RUNTIME.osType ~= "windows" then
return nil
end

local pkg_meta = windows_luabinaries_packages[lua_version]
if pkg_meta == nil then
return nil
end

return {
archive_name = pkg_meta.archive_name,
executable_prefix = pkg_meta.executable_prefix,
wlua_prefix = pkg_meta.wlua_prefix,
dll_name = pkg_meta.dll_name,
url = "https://sourceforge.net/projects/luabinaries/files/" ..
pkg_meta.relative_path .. "/download?use_mirror=autoselect",
}
end

function lua_utils.is_success_status(status)
return status == true or status == 0
end

function lua_utils.is_dir(path)
local status = os.execute("[ -d " .. path .. " ]")
return status == 0
Expand Down
Loading