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:
@@ -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.
|
||||
Reference in New Issue
Block a user