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
79 changes: 35 additions & 44 deletions .github/workflows/windows-installer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ jobs:
# reports as `cancelled`, not `failure`, which reads like someone stopped
# it — so it is worth saying plainly here that LTO is what costs the time.
timeout-minutes: 75
# NON-GATING (same rationale as publish-pypi.yml's windows wheel job): the
# installer must first build the ciris-server abi3 wheel on Windows, which
# fails today because the substrate (persist/edge) pulls openssl-src + has
# Unix-only paths that don't build on windows-msvc (CIRISPersist#200 /
# CIRISEdge#90). The installer machinery (PyInstaller spec, Inno Setup, jlink
# JRE) is complete and correct; this job will start producing an artifact the
# moment the upstream Windows wheel goes green. Remove continue-on-error then.
continue-on-error: true
# GATING since 0.5.203 (CIRISServer#562). This job carried
# `continue-on-error: true` from the day the Windows wheel could not build
# (CIRISPersist#200 / CIRISEdge#90); the wheel has published since 0.5.202,
# and under that flag the job failed on `cd client` on every run after the
# client tree was deleted (#471) while the run read `success` — no installer
# for months and nothing that said so. The first green artifact after the
# rebuild is run 34226383277 (CIRIS-Server-Setup-0.5.203-x64.exe, 117 MiB:
# the frozen node, the client package's 66 MB desktop JAR, a 51 MB jlink
# runtime). A failure here is now a failure.
permissions:
contents: read
packages: write # CIRISCache save (GHCR) on main — CIRISServer#99
Expand Down Expand Up @@ -119,10 +120,6 @@ jobs:
distribution: 'liberica'
java-version: '17'

- name: Set up Gradle (distribution + dependency cache)
uses: gradle/actions/setup-gradle@v4
with:
cache-read-only: false

- name: Get version from Cargo.toml
id: version
Expand All @@ -133,32 +130,6 @@ jobs:
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "ciris-server version: $VERSION"

- name: Build CIRIS Desktop UberJar
uses: nick-fields/retry@v4
with:
timeout_minutes: 25
max_attempts: 3
retry_wait_seconds: 60
shell: bash
command: |
cd client
./gradlew :desktopApp:packageUberJarForCurrentOS --no-daemon
ls -lh desktopApp/build/compose/jars/

- name: Stage the desktop JAR into the wheel tree
shell: bash
run: |
mkdir -p python/ciris_server/desktop_app
cp client/desktopApp/build/compose/jars/CIRIS-windows-*.jar \
python/ciris_server/desktop_app/
ls -lh python/ciris_server/desktop_app/

# Build the wheel via maturin-action — IDENTICAL to build-wheels.yml's
# windows leg (target x64, rust 1.97.0, sccache: true), so it shares that
# job's warmed sccache pool (CIRISServer#274). The wheel carries the staged
# JAR (pyproject [tool.maturin] include). `--strip` matches the publish
# wheel's compile flags for pool-identity; `--out dist-wheel` only sets the
# output dir (does not affect the sccache compile keys).
- name: Build the ciris-server wheel (maturin-action, shared sccache)
uses: PyO3/maturin-action@v1
# The desktop installer IS the Google desktop client, so of all the
Expand Down Expand Up @@ -186,6 +157,25 @@ jobs:
echo "installing $WHL"
pip install "$WHL"
python -c "import ciris_server; from ciris_server.cli import main; print('ciris_server import OK')"
# THE DESKTOP JAR COMES FROM THE CLIENT PACKAGE (CIRISServer#471 / #562).
#
# `client/` was deleted in 0.5.189; the wheel depends on `ciris-client`,
# whose win_amd64 wheel carries the Compose uber-jar under
# `ciris_client/_artifacts/` with a manifest, and `ciris_server.desktop_launcher`
# resolves it through `ciris_client.artifact_path("desktop-uber-jar")`. The
# `pip install` above pulled it; this step only asks where it landed, for the
# jlink trim below. The step that stood here used to `cd client && ./gradlew`,
# which failed on every run since 0.5.189 while the job read `success`
# (continue-on-error) — CIRISServer#562.
- name: Locate the desktop JAR in the installed client package
id: jar
shell: bash
run: |
set -euo pipefail
JAR=$(python -c "import ciris_client; print(ciris_client.artifact_path('desktop-uber-jar'))")
test -f "$JAR"
ls -lh "$JAR"
echo "path=$JAR" >> "$GITHUB_OUTPUT"

- name: CIRISCache save (windows-x64 server layer)
if: github.ref == 'refs/heads/main'
Expand All @@ -207,16 +197,17 @@ jobs:
run: |
mkdir -p dist
mv installers/windows/dist/ciris-server dist/
# confirm the desktop JAR rode into the bundle
ls dist/ciris-server/_internal/ciris_server/desktop_app/ || \
echo "WARN: desktop JAR not found in bundle (launcher will fall back to system layout)"
# The bundle must carry the client package's artifact dir — the JAR
# and its manifest — or the frozen launcher finds no desktop to start.
ls -lh dist/ciris-server/_internal/ciris_client/_artifacts/
test -n "$(ls dist/ciris-server/_internal/ciris_client/_artifacts/*.jar)"

- name: Trim JRE via jlink (Liberica)
shell: pwsh
run: |
$jar = Get-ChildItem -Path 'client\desktopApp\build\compose\jars' -Filter 'CIRIS-windows-*.jar' | Select-Object -First 1
if (-not $jar) { Write-Error "No CIRIS-windows-*.jar found"; exit 1 }
.\installers\windows\bundle-jre.ps1 -JarPath $jar.FullName -OutputDir dist\runtime
$jar = "${{ steps.jar.outputs.path }}"
if (-not (Test-Path $jar)) { Write-Error "desktop JAR not found at $jar"; exit 1 }
.\installers\windows\bundle-jre.ps1 -JarPath $jar -OutputDir dist\runtime

# (Removed in 0.5.65: the Universal CRT redist fetch was a Win7 SP1
# prerequisite — Win10+/Server 2016+ ship the UCRT in-box.)
Expand Down
23 changes: 13 additions & 10 deletions installers/windows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ users who'd rather not touch Python.
| Piece | Source | Lands at |
|-------|--------|----------|
| CPython + Rust node + launcher | PyInstaller `--onedir` of `ciris-server.spec` (after `pip install` of the maturin wheel) | `{app}\` |
| Compose desktop JAR | rides inside the wheel (`ciris_server/desktop_app/CIRIS-*.jar`); collected by the spec | `{app}\_internal\ciris_server\desktop_app\` |
| Compose desktop JAR | from the `ciris-client` win_amd64 wheel (`ciris_client/_artifacts/CIRIS-windows-*.jar` + manifest), pulled by `pip install` of the server wheel; collected by the spec | `{app}\_internal\ciris_client\_artifacts\` |
| Trimmed JRE (~30 MB) | `bundle-jre.ps1` (jlink) | `{app}\runtime\` |

`desktop_launcher.find_java()` prefers `{app}\runtime` when frozen, so the
Expand All @@ -29,21 +29,24 @@ bundled JRE is used; `cli._spawn_headless_node()` re-invokes the frozen exe with
## Build (locally, on Windows)

```powershell
# 0. build + install the wheel (needs Rust + maturin), with the JAR staged first
cd client; .\gradlew :desktopApp:packageUberJarForCurrentOS
copy desktopApp\build\compose\jars\CIRIS-windows-*.jar ..\python\ciris_server\desktop_app\
cd ..; maturin build --release -o dist-wheel; pip install (Get-ChildItem dist-wheel\*.whl)
# 0. build + install the wheel (needs Rust + maturin); pip pulls ciris-client,
# whose win_amd64 wheel carries the desktop JAR (no Gradle, no client/ tree)
# (from the repository root)
maturin build --release -o dist-wheel; pip install (Get-ChildItem dist-wheel\*.whl)
# 1. PyInstaller bundle
cd installers\windows; pyinstaller ciris-server.spec --noconfirm; mv dist\ciris-server ..\..\dist\
# 2. trimmed JRE
.\bundle-jre.ps1 -JarPath ..\..\client\desktopApp\build\compose\jars\CIRIS-windows-*.jar -OutputDir ..\..\dist\runtime
$jar = python -c "import ciris_client; print(ciris_client.artifact_path('desktop-uber-jar'))"
.\bundle-jre.ps1 -JarPath $jar -OutputDir ..\..\dist\runtime
# 3. installer
iscc ciris-server-installer.iss /DCirisVersion=0.5.38
iscc ciris-server-installer.iss /DCirisVersion=0.5.203
```

CI does all of this — see `.github/workflows/client-artifacts.yml`
(`windows-installer` job, Win8.1 floor) and `windows7-installer.yml` (the
experimental, dispatch-only Win7 variant with a patched CPython).
CI does all of this — see `.github/workflows/windows-installer.yml`
(`windows-installer` job, Win8.1 floor; runs on main, on tags, and on a PR
under `ci:full`; `workflow_dispatch` runs it on any branch). The Win7 variant
(`windows7-installer.yml`) no longer exists; the `Win7Tier` define in the
Inno script is kept for a future dispatch-only build.

## Windows 7

Expand Down
2 changes: 1 addition & 1 deletion installers/windows/bundle-jre.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# under-trimming are catastrophic.
#
# Usage:
# .\bundle-jre.ps1 -JarPath ..\..\client\desktopApp\build\compose\jars\CIRIS-windows-x64-2.7.6.jar -OutputDir ..\..\dist\runtime
# .\bundle-jre.ps1 -JarPath (python -c "import ciris_client; print(ciris_client.artifact_path('desktop-uber-jar'))") -OutputDir ..\..\dist\runtime
#
# Prereqs:
# JAVA_HOME points to a JDK 17+ install (jlink is part of the JDK).
Expand Down
2 changes: 1 addition & 1 deletion installers/windows/ciris-server-installer.iss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
; Bundles two things into one .exe:
; 1. dist\ciris-server\ — the PyInstaller --onedir bundle: CPython + the
; compiled Rust node (ciris_server._native) + the launcher. The per-platform
; Compose desktop JAR rides INSIDE this bundle (the wheel carries it under
; Compose desktop JAR rides INSIDE this bundle (the CLIENT package carries it under
; ciris_server/desktop_app/, and ciris-server.spec collects it), so no
; separate JAR Files entry is needed.
; 2. dist\runtime\ — a trimmed JRE from bundle-jre.ps1 (~30 MB). find_java()
Expand Down
9 changes: 9 additions & 0 deletions installers/windows/ciris-server.spec
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,16 @@ hiddenimports += ["ciris_server._native"]
# Grab the compiled _native.<abi3>.pyd and the per-platform desktop JAR that the
# wheel bundles under ciris_server/desktop_app/.
binaries = collect_dynamic_libs("ciris_server")
# The desktop JAR is the CLIENT package's (CIRISServer#471): `ciris_client/_artifacts/`
# holds the per-platform uber-jar and the manifest `artifact_path()` reads, and
# `ciris_server.desktop_launcher.find_desktop_jar` resolves it through that
# package. Collect the package's data (and its modules, below) so the frozen
# launcher finds exactly what the installed wheel found. The old in-wheel
# location (`ciris_server/desktop_app/`) is empty since 0.5.189; collecting it
# is harmless and keeps a pre-#471 wheel buildable.
datas = collect_data_files("ciris_server", includes=["desktop_app/CIRIS-*.jar"])
datas += collect_data_files("ciris_client")
hiddenimports += collect_submodules("ciris_client")

a = Analysis(
["ciris-server-entry.py"],
Expand Down
Loading