FEnigma/packaging/windows/oem/install.bat
Dominik Roth 23615a8c92 Fix id-namespace regression, add StrikeRequest type, kill full-panel
rerender on assign/alive/shell, add Windows build tooling

- Board.add_target/add_ally's id auto-assignment used a bare
  next(c for c in string.ascii_uppercase if c not in used), which
  raises StopIteration once 26 entities of a group exist -- a real
  crash confirmed via a live traceback, and a direct regression from
  moving that sequence from per-type to per-group. This was the actual
  cause of "Accept as"/"Accept all" silently doing nothing. Fixed with
  _next_free_id(), which rolls over to two-letter ids instead of
  raising.
- New TargetType.STRIKE_REQUEST: the bearing/distance-offset "taking
  fire" fire-support request (see the earlier two-entity split) now
  creates this instead of reusing STRIKE, so a radioed-in request is
  never confused with a strike the player placed themselves. Same
  crosshair icon, excluded from type pickers/dedupe like STRIKE.
- The "Accept as..." popover on a detected map marker now uses the
  same icon grid the entity-edit "Change type" popover does (was a
  plain unfiltered text list of every TargetType, which also wrongly
  offered STRIKE/STRIKE_REQUEST as pickable).
- Firing panel: _cycle_assignment/_toggle_alive/_pick_shell no longer
  route through app.py's full solver+dedupe+canvas+panel refresh --
  none of the three can affect the solver or dedupe, and none change
  which cards exist or their order (except _toggle_alive in
  hide/sort_later mode). New FiringPanel._rebuild_one() rebuilds just
  the one changed card; on_visual_change is a new, lighter callback
  (just a map redraw) for the two of these three that actually affect
  it. This was a real, confirmed lag source with many units on the
  board: every click on any of these was previously rebuilding every
  card of every target.
- Map right-click entity menu: added "Mark destroyed"/"Mark alive",
  reusing the same cheap-refresh path (new
  FiringPanel.refresh_after_alive_change).
- packaging/windows/: a from-scratch (untested against a real boot)
  MSYS2 + WiX .msi build pipeline for Windows, driven from Linux via
  dockur/windows (KVM-in-container), no Windows machine or GitHub
  required. See its own README for status/caveats.
- New/updated tests: id-namespace sharing + the 26-entity overflow
  regression (tests/test_models.py), StrikeRequest split
  (tests/test_ocr.py), warp_to_map's img_scale param
  (tests/test_map_vision_warp.py). 44/44 passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 20:48:57 +02:00

82 lines
4.2 KiB
Batchfile

@echo off
REM One-time provisioning, auto-run by dockur/windows during the final step
REM of Windows's own unattended setup (see its README's /oem mechanism).
REM Everything here happens exactly once and lands on the VM's persistent
REM disk -- later builds just boot this already-provisioned VM and run
REM build.bat, no re-provisioning.
REM
REM UNTESTED end to end: written from MSYS2's documented CI bootstrap
REM sequence (the same one msys2/setup-msys2 uses) and WiX's own docs, not
REM verified against a live dockur/windows boot. Expect to debug this on
REM the actual first run -- watch it happen at http://localhost:8006.
REM
REM Every step also echoes to Z:\install_progress.log (best-effort, only
REM if the Z:\ shared drive happens to be up already at this point in
REM setup) purely so build_windows.sh on the host has SOMETHING to show
REM besides silence during the one-time provisioning run.
setlocal enabledelayedexpansion
call :log "starting FEnigma build-VM provisioning"
REM -- MSYS2: the "base" self-extracting archive, not the GUI installer --
REM (the GUI installer has no reliable non-interactive/silent flag across
REM versions; the base sfx archive is what CI pipelines actually use).
REM Discover the current filename by scraping the repo listing, since it's
REM datestamped and there's no stable "latest" URL.
call :log "finding current MSYS2 base archive..."
powershell -NoProfile -Command ^
"$ProgressPreference='SilentlyContinue';" ^
"$html = Invoke-WebRequest -Uri 'https://repo.msys2.org/distrib/x86_64/' -UseBasicParsing;" ^
"$name = ($html.Links | Where-Object { $_.href -match '^msys2-base-x86_64-.*\.sfx\.exe$' } | Select-Object -Last 1).href;" ^
"Invoke-WebRequest -Uri ('https://repo.msys2.org/distrib/x86_64/' + $name) -OutFile 'C:\msys2-base.sfx.exe' -UseBasicParsing"
if not exist C:\msys2-base.sfx.exe (
call :log "FAILED: could not download MSYS2 base archive"
exit /b 1
)
call :log "extracting MSYS2 to C:\msys64 ..."
C:\msys2-base.sfx.exe -y -oC:\ >> C:\OEM\install.log 2>&1
del C:\msys2-base.sfx.exe
REM First bash launch finalizes the base install and kills itself off
REM mid-update (documented MSYS2 behavior) -- run it, ignore its exit
REM code, then run the real update.
call :log "bootstrapping MSYS2 (pacman -Syuu, twice) ..."
C:\msys64\usr\bin\bash.exe -lc "exit 0" >> C:\OEM\install.log 2>&1
C:\msys64\usr\bin\bash.exe -lc "pacman -Syuu --noconfirm" >> C:\OEM\install.log 2>&1
C:\msys64\usr\bin\bash.exe -lc "pacman -Syuu --noconfirm" >> C:\OEM\install.log 2>&1
call :log "installing GTK4/libadwaita/PyGObject/build deps ..."
C:\msys64\usr\bin\bash.exe -lc "pacman -S --noconfirm --needed mingw-w64-x86_64-python mingw-w64-x86_64-python-pip mingw-w64-x86_64-python-gobject mingw-w64-x86_64-gtk4 mingw-w64-x86_64-libadwaita mingw-w64-x86_64-python-numpy mingw-w64-x86_64-python-pillow mingw-w64-x86_64-opencv mingw-w64-x86_64-tesseract-ocr" >> C:\OEM\install.log 2>&1
call :log "pip install pytesseract (pure python, no wheel needed) ..."
C:\msys64\mingw64\bin\python3.exe -m pip install pytesseract >> C:\OEM\install.log 2>&1
REM -- WiX v3 toolset (candle/light/heat), a plain zip of standalone exes,
REM no installer needed. Fixed versioned URL, no scraping required.
call :log "fetching WiX v3.11 ..."
powershell -NoProfile -Command ^
"$ProgressPreference='SilentlyContinue';" ^
"Invoke-WebRequest -Uri 'https://github.com/wixtoolset/wix3/releases/download/wix3111rtm/wix311-binaries.zip' -OutFile 'C:\wix311-binaries.zip' -UseBasicParsing;" ^
"Expand-Archive -Path 'C:\wix311-binaries.zip' -DestinationPath 'C:\wix' -Force"
del C:\wix311-binaries.zip
REM -- Register the build watcher to run at every boot from here on, plus
REM kick it off right now too (ONSTART won't retroactively fire for this
REM already-in-progress boot). Runs as SYSTEM so it works with no user
REM logged in.
call :log "registering build watcher ..."
schtasks /create /tn "FenigmaBuildWatcher" /sc onstart /ru SYSTEM /rl HIGHEST /tr "C:\OEM\watch_build.bat" /f >> C:\OEM\install.log 2>&1
start "" cmd /c C:\OEM\watch_build.bat
call :log "provisioning done"
echo DONE > C:\OEM\provisioned.marker
if exist Z:\ echo DONE > Z:\PROVISIONED
endlocal
exit /b 0
:log
echo [install.bat] %~1 >> C:\OEM\install.log
if exist Z:\ echo [install.bat] %~1 >> Z:\install_progress.log
exit /b 0