docs: expand CI/CD guide with NSIS launch function, VBS fallback, and local build testing
- Replace MUI_FINISHPAGE_RUN_PARAMETERS with RUN_FUNCTION (fixes quoting) - Add embedded Python fallback to VBS hidden launcher - Add .onInit file-lock detection for running instances - Add section 11: local Windows build testing with NSIS - Expand troubleshooting table with common build/install issues
This commit is contained in:
@@ -342,12 +342,36 @@ InstallDir "$LOCALAPPDATA\${APPNAME}"
|
|||||||
RequestExecutionLevel user
|
RequestExecutionLevel user
|
||||||
|
|
||||||
; Optional: launch app after install (checkbox on finish page)
|
; Optional: launch app after install (checkbox on finish page)
|
||||||
; Direct bat approach (shows brief console flash):
|
; IMPORTANT: Do NOT use MUI_FINISHPAGE_RUN with MUI_FINISHPAGE_RUN_PARAMETERS —
|
||||||
; !define MUI_FINISHPAGE_RUN "$INSTDIR\MyApp.bat"
|
; NSIS Exec command chokes on the quoting. Use MUI_FINISHPAGE_RUN_FUNCTION instead:
|
||||||
; Preferred: VBS hidden launcher (no console window at all):
|
!define MUI_FINISHPAGE_RUN ""
|
||||||
!define MUI_FINISHPAGE_RUN "wscript.exe"
|
|
||||||
!define MUI_FINISHPAGE_RUN_PARAMETERS '"$INSTDIR\scripts\start-hidden.vbs"'
|
|
||||||
!define MUI_FINISHPAGE_RUN_TEXT "Launch ${APPNAME}"
|
!define MUI_FINISHPAGE_RUN_TEXT "Launch ${APPNAME}"
|
||||||
|
!define MUI_FINISHPAGE_RUN_FUNCTION LaunchApp
|
||||||
|
|
||||||
|
Function LaunchApp
|
||||||
|
ExecShell "open" "wscript.exe" '"$INSTDIR\scripts\start-hidden.vbs"'
|
||||||
|
Sleep 2000
|
||||||
|
ExecShell "open" "http://localhost:8765/" ; Open Web UI after server starts
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
; Detect running instance before install (file lock check)
|
||||||
|
Function .onInit
|
||||||
|
IfFileExists "$INSTDIR\python\python.exe" 0 done
|
||||||
|
ClearErrors
|
||||||
|
FileOpen $0 "$INSTDIR\python\python.exe" a
|
||||||
|
IfErrors locked
|
||||||
|
FileClose $0
|
||||||
|
Goto done
|
||||||
|
locked:
|
||||||
|
MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \
|
||||||
|
"${APPNAME} is currently running.$\n$\nYes = Stop and continue$\nNo = Continue anyway (may cause errors)$\nCancel = Abort" \
|
||||||
|
IDYES kill IDNO done
|
||||||
|
Abort
|
||||||
|
kill:
|
||||||
|
nsExec::ExecToLog 'wmic process where "ExecutablePath like $\'%AppName%python%$\'" call terminate'
|
||||||
|
Sleep 2000
|
||||||
|
done:
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
; Sections
|
; Sections
|
||||||
Section "!Core (required)" SecCore ; App files + uninstaller
|
Section "!Core (required)" SecCore ; App files + uninstaller
|
||||||
@@ -365,17 +389,27 @@ Bat files briefly flash a console window even with `@echo off`. To avoid this,
|
|||||||
use a VBS wrapper that all shortcuts and the finish page point to:
|
use a VBS wrapper that all shortcuts and the finish page point to:
|
||||||
|
|
||||||
```vbs
|
```vbs
|
||||||
|
Set fso = CreateObject("Scripting.FileSystemObject")
|
||||||
Set WshShell = CreateObject("WScript.Shell")
|
Set WshShell = CreateObject("WScript.Shell")
|
||||||
scriptDir = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
|
scriptDir = fso.GetParentFolderName(WScript.ScriptFullName)
|
||||||
appRoot = CreateObject("Scripting.FileSystemObject").GetParentFolderName(scriptDir)
|
appRoot = fso.GetParentFolderName(scriptDir)
|
||||||
WshShell.CurrentDirectory = appRoot
|
WshShell.CurrentDirectory = appRoot
|
||||||
' Run bat completely hidden (0 = hidden, False = don't wait)
|
' Use embedded Python if present (installed dist), otherwise system Python
|
||||||
WshShell.Run """" & appRoot & "\MyApp.bat""", 0, False
|
embeddedPython = appRoot & "\python\python.exe"
|
||||||
|
If fso.FileExists(embeddedPython) Then
|
||||||
|
WshShell.Run """" & embeddedPython & """ -m your_package.main", 0, False
|
||||||
|
Else
|
||||||
|
WshShell.Run "python -m your_package.main", 0, False
|
||||||
|
End If
|
||||||
```
|
```
|
||||||
|
|
||||||
Place in `scripts/start-hidden.vbs` and bundle it in the build script.
|
Place in `scripts/start-hidden.vbs` and bundle it in the build script.
|
||||||
All NSIS shortcuts use: `"wscript.exe" '"$INSTDIR\scripts\start-hidden.vbs"'`
|
All NSIS shortcuts use: `"wscript.exe" '"$INSTDIR\scripts\start-hidden.vbs"'`
|
||||||
|
|
||||||
|
**Important:** The embedded Python fallback is critical — the installed distribution
|
||||||
|
doesn't have Python on PATH, so `python` alone won't work. The dev environment uses
|
||||||
|
system Python, so the fallback handles both cases.
|
||||||
|
|
||||||
**CI dependencies:** `sudo apt-get install -y nsis msitools zip`
|
**CI dependencies:** `sudo apt-get install -y nsis msitools zip`
|
||||||
|
|
||||||
Build: `makensis -DVERSION="${VERSION}" installer.nsi`
|
Build: `makensis -DVERSION="${VERSION}" installer.nsi`
|
||||||
@@ -486,7 +520,64 @@ git push origin v0.2.0-alpha.1
|
|||||||
- [ ] Configure `pyproject.toml` with `[tool.ruff]` and `[tool.pytest]`
|
- [ ] Configure `pyproject.toml` with `[tool.ruff]` and `[tool.pytest]`
|
||||||
- [ ] Set up `.pre-commit-config.yaml` with ruff + black
|
- [ ] Set up `.pre-commit-config.yaml` with ruff + black
|
||||||
|
|
||||||
## 11. Troubleshooting
|
## 11. Local Build Testing (Windows)
|
||||||
|
|
||||||
|
The CI builds on Linux, but you can build locally on Windows for faster iteration.
|
||||||
|
|
||||||
|
### 11.1. Prerequisites
|
||||||
|
|
||||||
|
Install NSIS (for installer builds):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# If winget is not on PATH, use the full path:
|
||||||
|
& "$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe" install NSIS.NSIS
|
||||||
|
# Installs to: C:\Program Files (x86)\NSIS\makensis.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.2. Build Steps
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Build frontend
|
||||||
|
npm ci && npm run build
|
||||||
|
|
||||||
|
# 2. Build Windows distribution (from Git Bash)
|
||||||
|
bash build-dist-windows.sh v1.0.0
|
||||||
|
|
||||||
|
# 3. Build NSIS installer
|
||||||
|
"/c/Program Files (x86)/NSIS/makensis.exe" -DVERSION="1.0.0" installer.nsi
|
||||||
|
# Output: build/MediaServer-v1.0.0-setup.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.3. Common Issues
|
||||||
|
|
||||||
|
| Issue | Cause | Fix |
|
||||||
|
|-------|-------|-----|
|
||||||
|
| `zip: command not found` | Git Bash doesn't include `zip` | Harmless — only affects the portable ZIP, not the installer. Install `zip` via MSYS2 if needed |
|
||||||
|
| `Exec expects 1 parameters, got 2` | `MUI_FINISHPAGE_RUN_PARAMETERS` quoting breaks NSIS `Exec` | Use `MUI_FINISHPAGE_RUN_FUNCTION` instead (see section 6) |
|
||||||
|
| `Error opening file for writing: ...python\\_asyncio.pyd` | Server is running and has DLLs locked | Stop the server before installing. Add `.onInit` file-lock check (see section 6) |
|
||||||
|
| App doesn't start after install (Launch checkbox) | VBS uses `python` but embedded Python isn't on PATH | Use embedded Python fallback in VBS (see Hidden Launcher section) |
|
||||||
|
| `winget` not recognized | `winget.exe` exists but isn't on shell PATH | Use full path: `$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe` |
|
||||||
|
| NSIS warning: `install function not referenced` | `MUI_FINISHPAGE_RUN` define is missing | `MUI_FINISHPAGE_RUN_FUNCTION` still requires `MUI_FINISHPAGE_RUN` to be defined (controls checkbox visibility). Set it to `""` |
|
||||||
|
| `dist/` has stale files after code changes | `build-dist-windows.sh` copies from source at build time | Re-run the full build script, or manually copy changed files into `dist/` |
|
||||||
|
|
||||||
|
### 11.4. Iterating on Installer Only
|
||||||
|
|
||||||
|
If you only changed `installer.nsi` (not app code), skip the full rebuild:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Just rebuild the installer using existing dist/
|
||||||
|
"/c/Program Files (x86)/NSIS/makensis.exe" -DVERSION="1.0.0" installer.nsi
|
||||||
|
```
|
||||||
|
|
||||||
|
If you changed app code or dependencies, you must re-run `build-dist-windows.sh` first —
|
||||||
|
the `dist/` directory is a snapshot and won't pick up source changes automatically.
|
||||||
|
|
||||||
|
## 12. Troubleshooting
|
||||||
|
|
||||||
|
### Running server blocks installation
|
||||||
|
|
||||||
|
See section 11.3. The `.onInit` function in section 6 shows how to detect a locked
|
||||||
|
`python.exe` and prompt the user before proceeding.
|
||||||
|
|
||||||
### Release already exists for tag
|
### Release already exists for tag
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user