157 lines
8.5 KiB
YAML
157 lines
8.5 KiB
YAML
# Windows on ARM (#61): package the ARM64 release the way release.yml does (cross-compiled on an
|
|
# x64 runner, unsigned here), then install that MSI on a Windows 11 ARM64 runner and run it, and
|
|
# run the test suite natively on ARM64.
|
|
name: Windows ARM64
|
|
|
|
# Nightly on main and on pushes to `release` (dependency and runner-image drift shows up within a
|
|
# day, and always before a release ships), and on PRs that change the Windows packaging itself.
|
|
on:
|
|
schedule:
|
|
- cron: "43 5 * * *"
|
|
push:
|
|
branches: [release]
|
|
pull_request:
|
|
paths:
|
|
- .github/workflows/windows-arm64.yml
|
|
- packaging/windows/**
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: windows-arm64-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
CARGO_INCREMENTAL: 0
|
|
RUST_BACKTRACE: 1
|
|
|
|
jobs:
|
|
package:
|
|
name: package (cross-compiled on x64)
|
|
runs-on: windows-latest
|
|
timeout-minutes: 90
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
targets: aarch64-pc-windows-msvc
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
key: windows-arm64-package
|
|
- name: Install WiX
|
|
shell: pwsh
|
|
run: dotnet tool install --global wix --version 5.0.2
|
|
- name: Build and package (unsigned)
|
|
shell: pwsh
|
|
env:
|
|
DIST: ${{ github.workspace }}\dist\arm64
|
|
run: ./packaging/windows/package.ps1 -Arch arm64
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: pdfcraft-windows-arm64
|
|
path: dist/arm64/*
|
|
if-no-files-found: error
|
|
retention-days: 7
|
|
|
|
install:
|
|
name: install and run on ARM64
|
|
needs: package
|
|
runs-on: windows-11-arm
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: pdfcraft-windows-arm64
|
|
path: dist
|
|
- name: Install the MSI, check it, run it, uninstall it, reinstall without the desktop shortcut
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$msi = (Get-ChildItem dist/*.msi | Select-Object -First 1).FullName
|
|
# A command-line override must not put files in a user profile while registering
|
|
# their handlers machine-wide (#305). This runs on a disposable CI runner.
|
|
$p = Start-Process msiexec.exe -WindowStyle Hidden -ArgumentList '/i', "`"$msi`"", '/qn', 'ALLUSERS=2', 'MSIINSTALLPERUSER=1', '/l*v', 'per-user.log' -Wait -PassThru
|
|
if ($p.ExitCode -ne 1603) { Get-Content per-user.log -Tail 60; throw "per-user install should fail with 1603, got $($p.ExitCode)" }
|
|
if (-not (Select-String -Path per-user.log -SimpleMatch 'PdfCraft must be installed for all users.')) {
|
|
Get-Content per-user.log -Tail 60; throw 'per-user install did not fail on the scope guard'
|
|
}
|
|
$p = Start-Process msiexec.exe -ArgumentList '/i', "`"$msi`"", '/qn', '/l*v', 'install.log' -Wait -PassThru
|
|
if ($p.ExitCode -ne 0) { Get-Content install.log -Tail 60; throw "msiexec /i exited $($p.ExitCode)" }
|
|
$shortcuts = @(
|
|
(Join-Path ([Environment]::GetFolderPath('CommonPrograms')) 'PdfCraft.lnk'),
|
|
(Join-Path ([Environment]::GetFolderPath('CommonDesktopDirectory')) 'PdfCraft.lnk')
|
|
)
|
|
# Plain shortcuts to the program (#143), not advertised ones, so TargetPath is the exe.
|
|
$exePath = Join-Path $env:ProgramFiles 'PdfCraft\pdfcraft.exe'
|
|
$wsh = New-Object -ComObject WScript.Shell
|
|
foreach ($shortcut in $shortcuts) {
|
|
if (-not (Test-Path -LiteralPath $shortcut)) { throw "installer did not create $shortcut" }
|
|
$target = $wsh.CreateShortcut($shortcut).TargetPath
|
|
if ($target -ne $exePath) { throw "$shortcut points to '$target', not $exePath" }
|
|
Write-Output "ok $shortcut -> $target"
|
|
}
|
|
$dir = Join-Path $env:ProgramFiles 'PdfCraft'
|
|
foreach ($exe in 'pdfcraft.exe', 'pdfcraft-cli.exe') {
|
|
$path = Join-Path $dir $exe
|
|
if (-not (Test-Path $path)) { Get-ChildItem -Recurse $env:ProgramFiles -Filter $exe | Select-Object -First 3; throw "$exe not installed in $dir" }
|
|
$bytes = [System.IO.File]::ReadAllBytes($path)
|
|
$machine = [BitConverter]::ToUInt16($bytes, [BitConverter]::ToInt32($bytes, 0x3C) + 4)
|
|
if ($machine -ne 0xAA64) { throw "$exe is for machine 0x$('{0:X}' -f $machine), not ARM64" }
|
|
Write-Output "ok $path (ARM64)"
|
|
}
|
|
# The installed CLI runs natively: open, render and edit a small PDF through the engine.
|
|
$cli = Join-Path $dir 'pdfcraft-cli.exe'
|
|
& $cli tools | Out-Null
|
|
if ($LASTEXITCODE -ne 0) { throw "pdfcraft-cli tools exited $LASTEXITCODE" }
|
|
$body = 'BT /F1 24 Tf 20 150 Td (Hello ARM64) Tj ET'
|
|
$objs = @('<< /Type /Catalog /Pages 2 0 R >>', '<< /Type /Pages /Kids [3 0 R] /Count 1 >>',
|
|
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>',
|
|
"<< /Length $($body.Length) >>`nstream`n$body`nendstream", '<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>')
|
|
$sb = [System.Text.StringBuilder]::new("%PDF-1.7`n"); $offsets = @()
|
|
for ($i = 0; $i -lt $objs.Count; $i++) { $offsets += $sb.Length; [void]$sb.Append("$($i + 1) 0 obj`n$($objs[$i])`nendobj`n") }
|
|
$xref = $sb.Length
|
|
[void]$sb.Append("xref`n0 $($objs.Count + 1)`n0000000000 65535 f `n")
|
|
foreach ($o in $offsets) { [void]$sb.Append(('{0:D10} 00000 n `n' -f $o)) }
|
|
[void]$sb.Append("trailer`n<< /Size $($objs.Count + 1) /Root 1 0 R >>`nstartxref`n$xref`n%%EOF`n")
|
|
New-Item -ItemType Directory -Force smoke | Out-Null
|
|
[System.IO.File]::WriteAllText("$PWD\smoke\hello.pdf", $sb.ToString(), [System.Text.Encoding]::ASCII)
|
|
$steps = '[{"tool":"doc_open","args":{"path":"hello.pdf"}},{"tool":"text_paragraphs","args":{"doc":1,"page":1}},{"tool":"text_edit","args":{"doc":1,"page":1,"paragraph":1,"text":"Edited on ARM64"}},{"tool":"page_render","args":{"doc":1,"page":1,"dpi":72},"out":"page.png"},{"tool":"doc_save","args":{"doc":1,"path":"out.pdf"}}]'
|
|
[System.IO.File]::WriteAllText("$PWD\smoke\steps.json", $steps)
|
|
$out = & $cli run --script smoke\steps.json --root smoke 2>&1 | Out-String
|
|
if ($LASTEXITCODE -ne 0) { Write-Output $out; throw "pdfcraft-cli run exited $LASTEXITCODE" }
|
|
if ($out -notmatch 'Hello ARM64') { Write-Output $out; throw 'text_paragraphs did not read the page' }
|
|
foreach ($f in 'smoke\page.png', 'smoke\out.pdf') { if (-not (Test-Path $f) -or (Get-Item $f).Length -eq 0) { Write-Output $out; throw "$f was not written" } }
|
|
Write-Output 'ok pdfcraft-cli: opened, read, edited, rendered and saved a PDF on ARM64'
|
|
$p = Start-Process msiexec.exe -ArgumentList '/x', "`"$msi`"", '/qn' -Wait -PassThru
|
|
if ($p.ExitCode -ne 0) { throw "msiexec /x exited $($p.ExitCode)" }
|
|
if (Test-Path (Join-Path $dir 'pdfcraft.exe')) { throw 'uninstall left pdfcraft.exe behind' }
|
|
foreach ($shortcut in $shortcuts) {
|
|
if (Test-Path -LiteralPath $shortcut) { throw "uninstall left $shortcut behind" }
|
|
}
|
|
Write-Output 'ok uninstalled'
|
|
# Unattended installs can opt out of the desktop shortcut (#143); the Start Menu one stays.
|
|
$p = Start-Process msiexec.exe -ArgumentList '/i', "`"$msi`"", '/qn', 'INSTALLDESKTOPSHORTCUT=0', '/l*v', 'install-nodesktop.log' -Wait -PassThru
|
|
if ($p.ExitCode -ne 0) { Get-Content install-nodesktop.log -Tail 60; throw "msiexec /i INSTALLDESKTOPSHORTCUT=0 exited $($p.ExitCode)" }
|
|
if (-not (Test-Path -LiteralPath $shortcuts[0])) { throw "INSTALLDESKTOPSHORTCUT=0 also skipped $($shortcuts[0])" }
|
|
if (Test-Path -LiteralPath $shortcuts[1]) { throw "INSTALLDESKTOPSHORTCUT=0 still created $($shortcuts[1])" }
|
|
$p = Start-Process msiexec.exe -ArgumentList '/x', "`"$msi`"", '/qn' -Wait -PassThru
|
|
if ($p.ExitCode -ne 0) { throw "msiexec /x exited $($p.ExitCode)" }
|
|
if (Test-Path -LiteralPath $shortcuts[0]) { throw "uninstall left $($shortcuts[0]) behind" }
|
|
Write-Output 'ok INSTALLDESKTOPSHORTCUT=0: Start Menu shortcut only'
|
|
|
|
test:
|
|
name: test (native ARM64)
|
|
runs-on: windows-11-arm
|
|
timeout-minutes: 120
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
key: windows-arm64-test
|
|
- name: Test
|
|
run: cargo test --workspace --locked
|