Add build and development instructions for the workspace

Document how to build, package and release the player so the knowledge is not
rediscovered on each machine or session.

New file: .github/instructions/kiwy-build-and-development.instructions.md

Contents:
- Entry points: src/main.py on Linux/Pi, windows/run_win.py on Windows (which
  patches platform differences before running main.py).
- Verified toolchain: Python 3.12.9 x64 in windows\venv, Kivy 2.3.1,
  PyInstaller 6.21.0. Python 3.13+/3.14 is unsupported for the Windows build
  because Kivy 2.3.1 has no wheels for them.
- Build commands (pyinstaller build.spec, build_win.bat) and the real output
  path, including the note that cefpython3 is not installed in this venv, so
  the embedded-CEF engine is inactive and web links use the subprocess adapter.
- build.spec expectations: runtime hook for DPI awareness, console=True,
  excludes, and the rule that lazily/dynamically imported modules must be listed
  in hiddenimports or the packaged exe fails with ModuleNotFoundError.
- Code signing constraint: production hosts enforce Smart App Control, where an
  unsigned (or self-signed) exe is blocked at kernel level, so a public CA cert
  is required.
- Verification: py_compile gate, the need to close the running player before a
  rebuild (output lock / "Access is denied"), the .exe reserved-device-name
  pitfall that makes Test-Path report a false positive without -LiteralPath, and
  the stale duplicate one-file exe at windows\dist\KiwySignagePlayer.exe that
  must not be deployed.
- Release checklist and commit hygiene (do not track dist/build output or the
  player_auth.json credential files).
This commit is contained in:
ske087
2026-09-10 16:52:41 +03:00
parent 7e880421c9
commit eb8e66e427
@@ -0,0 +1,140 @@
---
description: "Use when building, compiling, packaging or releasing the Kiwy Signage Player: PyInstaller build, .exe generation, build.spec, hiddenimports, code signing, Smart App Control, Windows development, Raspberry Pi deployment, or adding new modules under src/. Covers the exact build commands, environment constraints, bundling rules and verification steps."
name: "Kiwy Build & Development"
---
# Kiwy Signage Player — Build & Development
Cross-platform Kivy digital signage player.
- **Raspberry Pi / Linux** — `src/main.py` is the entry point (root `install.sh`, `start.sh`).
- **Windows** — `windows/run_win.py` is the entry point; it sets Windows env vars, imports
`main.py`, then monkey-patches platform differences. Packaged to `.exe` with PyInstaller.
## Ground Rules
- **Keep `src/main.py` cross-platform.** Windows-specific behaviour belongs in
`windows/run_win.py` (see `_patch_main()`), Pi-specific behaviour in `main.py` guarded
by capability checks. Do not add Windows-only imports to `main.py`.
- **Rebuild is mandatory.** The `.exe` bundles `src/`, so Python edits are invisible until
you rebuild. There is no hot reload in the packaged app.
- **`dist/` is a runtime folder, not just build output.** It holds `config/`, `media/`,
`playlists/`, `logs/`, `.kiosk-profile/` and `.player_heartbeat`. Never wipe `dist/`
blindly; a `--clean` rebuild preserves it, but a manual delete destroys player state.
## Environment
| Item | Value |
|------|-------|
| Interpreter | **Python 3.12.9** (64-bit) — project venv at `windows\venv` |
| Kivy | 2.3.1 |
| PyInstaller | 6.21.0 |
| Linux target | Python 3.13 (`repo/python-wheels/`, `repo/system-packages/`) |
- **Python 3.13+/3.14 is NOT supported for the Windows build** — Kivy 2.3.1 has no wheels
for them.
- `cefpython3` is **not installed** in the project venv. The embedded-CEF web-link engine is
therefore unavailable and web links fall back to the Chrome/Edge subprocess adapter.
Installing `cefpython3` (uncomment it in `windows/requirements_win.txt`) restores the
CEF engine.
## Build
From `windows\`:
```
venv\Scripts\python.exe -m PyInstaller build.spec --clean --noconfirm
```
Or the full one-click path (creates venv, installs deps, builds, then signs):
```
build_win.bat
```
Output (folder mode, via `COLLECT`):
```
windows\dist\KiwySignagePlayer\KiwySignagePlayer.exe <- the real build output
```
**Deployment hazard:** `windows\dist\KiwySignagePlayer.exe` (one level up) is a stale
leftover from an older single-file build of the same name. It is not refreshed by the
current spec, so deploying it ships old code. Always take the executable from the
`KiwySignagePlayer\` subfolder, and delete the stray copy if it reappears.
### `build.spec` facts
- Entry point `run_win.py`; `pathex=[BUILD_DIR, SRC_DIR]` so `src/` modules resolve.
- `runtime_hooks=[pyi_runtime_hook.py]` — sets per-monitor DPI awareness **before** SDL/Kivy
initialise. Keep DPI work here; it must run before any window is created.
- `datas += Tree(src)` bundles all of `src/`. `console=True` so startup errors and the Kivy
log remain visible — do not flip this to `False` without a reason.
- `hiddenimports` must list modules that PyInstaller's static analysis **cannot** see:
lazily imported ones (`cef_browser` is imported inside a function) or dynamic imports
(`getattr`, `importlib`). Top-level imports such as `weblink_session` are found
automatically via `pathex`, but listing them is harmless insurance.
**When you add a module under `src/` that is imported lazily or by string, add it to
`hiddenimports` or the packaged exe will fail at runtime with `ModuleNotFoundError`.**
- `excluded_imports` drops Linux-only packages (`evdev`, `gi`, GStreamer) and the
non-matching `cefpython3` `.pyd` variants.
## Code Signing (production constraint)
Production PCs run with **Smart App Control enforced** (`VerifiedAndReputablePolicyState=1`,
UMCI enforced) with **no "Run anyway" bypass** — an unsigned exe is blocked at kernel level.
- A **self-signed certificate does NOT satisfy Smart App Control.** A cert from a reputable
public CA is required. `create_self_signed_cert.ps1` is dev-only.
- Provide a cert as `KIWY_SIGN_PFX` (+ optional `KIWY_SIGN_PFX_PASSWORD`) or drop
`kiwy_signing.pfx` in `windows\`; `build_win.bat` then signs via `sign_exe.ps1`
(signtool with RFC3161 timestamp when available).
- See `documentation/CODE_SIGNING_SMART_APP_CONTROL.md`.
## Verify Before Committing
Fast syntax gate (no build, seconds):
```
python -m py_compile src/main.py src/weblink_session.py windows/run_win.py
```
**Close the running player before rebuilding.** A running
`dist\KiwySignagePlayer\KiwySignagePlayer.exe` locks the output and the build fails with
"Access is denied". Chrome/Edge kiosk processes left over from web-link playback can also
hold locks; if the build fails, check for stray `msedge.exe` / `chrome.exe` before retrying.
Because `.exe` is a **reserved Windows device name** as well as a real file, use
`Test-Path -LiteralPath` when probing for the executable, otherwise the path silently
resolves to the console device.
Development run — **use this on a SAC-locked host**, since the unsigned exe cannot launch:
```
cd windows
venv\Scripts\activate
python run_win.py
```
Diagnose playback transitions via the trace log (`logs\playback_trace.log`), written by
`src/playback_trace.py`.
## Release Checklist
1. Bump `PLAYER_VERSION` in `src/main.py` **and** `filevers`/`prodvers`/`FileVersion`/
`ProductVersion` in `windows\version_info.txt`; keep them in sync.
2. Rebuild (`build_win.bat`).
3. Confirm the exe is signed (`Get-AuthenticodeSignature`); unsigned builds are blocked on
production hosts.
4. Smoke-test a mixed playlist: image → video → weblink → image, verifying durations, audio
(`audio: off` / `muted`), and a clean exit/restart.
## Commit Hygiene
- Never commit `windows\build\` or `windows\dist\` (git-ignored). Tracked build output such
as `windows\archive_list.txt` and `windows\build_last.txt` is the exception, not the rule.
- **Do not commit `player_auth.json` or `src/player_auth.json`** — they contain live
credentials (`auth_code`, `player_id`, `server_url`). These are currently tracked; treat any
future change to them as a deliberate, reviewed decision.
- Do not commit `config\app_config.json` values that are host-specific without checking
whether they belong in the repo default.