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
21 changes: 18 additions & 3 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,24 @@ jobs:

e2e-windows:
if: github.repository == 'version-fox/vfox-flutter'
name: Windows container (amd64)
runs-on: windows-latest
timeout-minutes: 90
name: Windows container (${{ matrix.runs-on }})
strategy:
fail-fast: false
matrix:
runs-on: [windows-latest, windows-11-arm]
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 60
steps:
- uses: actions/checkout@v7
# TODO See https://github.com/actions/runner-images/issues/13729
- if: matrix.runs-on == 'windows-latest'
run: |
for ($i = 1; $i -le 18; $i++) {
docker info *> $null
if ($LASTEXITCODE -eq 0) { exit 0 }
Start-Sleep -Seconds 10
}
throw 'FAIL the docker daemon never became ready'
- if: matrix.runs-on == 'windows-11-arm'
run: pwsh -NoProfile -File tests/e2e/windows/install-docker.ps1
- run: pwsh -NoProfile -File tests/e2e/windows/e2e.ps1
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ See [docs/ohos.md](docs/ohos.md) for details.

See [docs/install-from-source.md](docs/install-from-source.md) for details.

## Testing
### Testing

See [docs/e2e.md](docs/e2e.md) for details.

Expand Down
25 changes: 15 additions & 10 deletions docs/arm64.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,36 @@ their existing version names. Channels also accept a suffix, such as
first, followed by other architectures, with each group ordered by version.
This keeps `@latest` on the default architecture.

Only architectures provided by Flutter for the current operating system are
listed. On Apple Silicon, running an x64 build requires Rosetta.
Only architectures provided by Flutter for the current operating system are listed.

## MacOS ARM64

On Apple Silicon, running an x64 build requires Rosetta.

## Linux ARM64

On Linux ARM64 the plugin installs the official `flutter/flutter` git tag
instead of a prebuilt bundle. The Flutter tool bootstraps the matching native
`dart-sdk-linux-arm64` itself on first run, so the result is a native SDK.
This follows the same pattern as the OpenHarmony builds (`lib/ohos.lua`):
`Available` advertises one `-arm64` entry per `x64` release whose `url` is the
clone URL, and `PreInstall` materializes the tag into a local directory under
`~/.vfox/tmp` that vfox consumes. `PostInstall` removes that throwaway
checkout.

Explicit `-x64` requests still resolve to the upstream archive, which cannot
run on Linux ARM64.

## Windows ARM64

Not supported: upstream publishes no `windows-arm64` archives, so no `-arm64`
entries are listed and installs fail instead of handing out an unusable `x64`
bundle.
On Windows ARM64 the plugin installs the official `flutter/flutter` git tag
instead of a prebuilt bundle, for the same reason as Linux ARM64: upstream
publishes no `windows-arm64` archives. The Flutter tool bootstraps the matching
native `dart-sdk-windows-arm64` itself on first run, so the result is a native
SDK.

Explicit `-x64` requests still resolve to the upstream archive, which cannot
run on Windows ARM64.

# Limits

## Linux ARM64 and Windows ARM64

- **`git` is required.** The checkout runs `git init` / `fetch` / `checkout`
against `https://github.com/flutter/flutter.git`.
- **The first `flutter` run is slow.** It downloads the native Dart SDK and
Expand Down
32 changes: 28 additions & 4 deletions docs/e2e.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# E2E

The offline Lua hook tests (`tests/hooks_test.lua`) run in the **Test Plugin** workflow.
The end-to-end suite runs in containers against real vfox (`latest` and `main`) on Linux
and Windows; each of the four `vfox` x `flavor` combinations gets its own throwaway
container.
The end-to-end suite runs in containers against real vfox on Linux and Windows;
each `vfox` x `flavor` x `mirror` combination gets its own throwaway container.

## Ubuntu 26.04.1

Expand Down Expand Up @@ -32,7 +31,15 @@ docker run --privileged --rm tonistiigi/binfmt --install all
ARCH=arm64 bash tests/e2e/linux/e2e.sh
```

## Running on Windows 11 Pro
## Windows 11 Pro

Windows containers cannot be emulated across architectures, so the ARM64 suite
needs an ARM64 host (a Copilot+ PC or the `windows-11-arm` CI runner).

The `windows-11-arm` runner has no Windows Hypervisor Platform feature,
so Hyper-V isolation is unavailable; process isolation needs only the Containers feature.

### x64

1. Execute in Windows PowerShell 5.1,

Expand Down Expand Up @@ -63,3 +70,20 @@ git clone git@github.com:version-fox/vfox-flutter.git
cd ./vfox-flutter/
pwsh -NoProfile -File .\tests\e2e\windows\e2e.ps1
```

### arm64

1. Execute in Windows PowerShell 5.1,

```powershell
winget install --id Microsoft.PowerShell --source winget --exact
```

2. Execute in PowerShell 7,

```powershell
git clone git@github.com:version-fox/vfox-flutter.git
cd ./vfox-flutter/
pwsh -NoProfile -File .\tests\e2e\windows\install-docker.ps1
pwsh -NoProfile -File .\tests\e2e\windows\e2e.ps1
```
4 changes: 2 additions & 2 deletions docs/ohos.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ vfox search flutter
- **Install by exact version.** OpenHarmony versions sort after the official releases,
so `@latest` and the `stable`/`beta`/`dev` channels never select one.
- **No architecture variants.** `flutter@3.41.10-ohos-1.0.0-x64` is not supported.
- **`linux-arm64`.** Upstream publishes only x64 Dart SDKs, so the first
- **`linux-arm64` and `windows-arm64`.** Upstream publishes only x64 Dart SDKs, so the first
`flutter` run fails there (`It appears that the downloaded file is corrupt`).
The Linux ARM64 e2e runs the official flavor only.
The ARM64 e2e runs the official flavor only.
- **A Windows home containing a space** (`C:\Users\John Doe\.vfox`) is not supported;
point vfox at a path without spaces with `$env:VFOX_HOME = 'D:\vfox'`.
- **The first `flutter` command is slow.** It builds the tool and downloads the Dart SDK
Expand Down
25 changes: 18 additions & 7 deletions hooks/available.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,27 @@ local json = require("json")
local ohos = require("ohos")
local source = require("source")

local MAX_ATTEMPTS = 3
local RETRY_DELAY = 5

require("util")
local function releases(type)
local resp, err
for attempt = 1, MAX_ATTEMPTS do
resp, err = http.get({ url = BASE_URL:format(type.osType) })
if resp ~= nil and resp.status_code == 200 then
return json.decode(resp.body)
end
if attempt < MAX_ATTEMPTS then
sleep(RETRY_DELAY)
end
end
error("get version failed: " .. tostring(err) .. " (status " .. tostring(resp and resp.status_code) .. ")")
end

function PLUGIN:Available(ctx)
local type = getOsTypeAndArch()
local resp, err = http.get({
url = BASE_URL:format(type.osType)
})
if err ~= nil or resp.status_code ~= 200 then
error("get version failed: " .. tostring(err) .. " (status " .. tostring(resp and resp.status_code) .. ")")
end
local body = json.decode(resp.body)
local body = releases(type)
local result = {}
for _, info in ipairs(body.releases) do
local version = info.version
Expand Down
115 changes: 115 additions & 0 deletions lib/git.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
local HOME_ENV = "VFOX_HOME"
local FALLBACK_HOME_ENV = { "HOME", "USERPROFILE" }
local VFOX_DIR = ".vfox"
local TMP_DIR = "tmp"
local ENGINE_PIN = "bin/internal/engine.version"
local FETCH_ATTEMPTS = 3

local M = {}

local function quote(value)
if RUNTIME.osType == "windows" then
return value
end
return "'" .. value:gsub("'", "'\\''") .. "'"
end

local function exec(command)
local result = os.execute(command)
return result == 0 or result == true
end

local function git(root, args)
return exec("git -C " .. quote(root) .. " " .. args)
end

local function sep()
if RUNTIME.osType == "windows" then
return "\\"
end
return "/"
end

local function localPath(path)
return path:gsub("/", sep())
end

function M.removeDir(path)
if RUNTIME.osType == "windows" then
exec('if exist "' .. path .. '" rmdir /s /q "' .. path .. '"')
else
exec("rm -rf " .. quote(path))
end
end

local function vfoxHome()
local home = os.getenv(HOME_ENV)
if home == nil or home == "" then
for _, name in ipairs(FALLBACK_HOME_ENV) do
home = os.getenv(name)
if home ~= nil and home ~= "" then
break
end
end
end
if home == nil or home == "" then
return nil
end
return localPath(home .. "/" .. VFOX_DIR)
end

function M.workDir(version)
local home = vfoxHome()
if home == nil then
return nil
end
return localPath(home .. "/" .. TMP_DIR .. "/" .. version)
end

local function parentDir(dir)
return dir:match("^(.+)[" .. sep() .. "][^" .. sep() .. "]+$")
end

local function makeParentDir(dir)
if RUNTIME.osType == "windows" then
return
end
local parent = parentDir(dir)
if parent == nil then
return
end
exec("mkdir -p " .. quote(parent))
end

function M.resetDir(dir)
M.removeDir(dir)
makeParentDir(dir)
end

function M.init(root)
return exec("git init -q " .. quote(root))
end

function M.fetch(root, remote, ref)
for _ = 1, FETCH_ATTEMPTS do
if git(root, "fetch -q --depth 1 " .. remote .. " " .. ref) then
return true
end
end
return false
end

function M.checkoutHead(root)
return git(root, "checkout -q FETCH_HEAD")
end

function M.hasEnginePin(root)
local pin = io.open(localPath(root .. "/" .. ENGINE_PIN), "r")
if pin == nil then
return false
end
pin:close()
return true
end

return M
Loading
Loading