diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..ab5abac --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,117 @@ +# Building & Releasing Series 3 Watcher + +## Prerequisites (Win7 VM — do this once) + +- Python 3.7.2 (or 3.8.10 if SP1 is installed) +- Inno Setup 6 — installed at `C:\Program Files (x86)\Inno Setup 6\` +- PyInstaller, pystray, Pillow — installed automatically by `build.bat` + +The Win7 VM is the build machine. All builds must happen there to ensure +compatibility with the production DL2 computer. + +--- + +## First-Time Install on a New Machine + +Do this when setting up a brand new machine that has never had the watcher before. + +**Step 1 — Build the .exe (on the Win7 VM)** + +1. Copy the `series3-watcher/` folder to the VM (shared folder, USB, etc.) +2. Double-click `build.bat` +3. Wait for it to finish — output: `dist\series3-watcher.exe` + +**Step 2 — Build the installer (on the Win7 VM)** + +1. Open `installer.iss` in Inno Setup Compiler +2. Click **Build → Compile** +3. Output: `Output\series3-watcher-setup.exe` + +**Step 3 — Create a Gitea release** + +1. On your main machine, go to `https://gitea.serversdown.net/serversdown/series3-watcher` +2. Click **Releases → New Release** +3. Set the tag to match the version in `series3_watcher.py` (e.g. `v1.4.1`) +4. Upload **both** files as release assets: + - `dist\series3-watcher.exe` — used by the auto-updater on existing installs + - `Output\series3-watcher-setup.exe` — used for fresh installs + +**Step 4 — Install on the target machine** + +1. Download `series3-watcher-setup.exe` from the Gitea release +2. Run it on the target machine — installs to `C:\Program Files\Series3Watcher\` +3. The watcher launches automatically after install (or on next login) +4. The Setup Wizard appears on first run — fill in the Terra-View URL and Blastware path + +--- + +## Releasing an Update (existing machines auto-update) + +Do this for any code change — bug fix, new feature, etc. + +**Step 1 — Bump the version** + +In `series3_watcher.py`, update the `VERSION` string: +```python +VERSION = "1.4.2" # increment appropriately +``` +Also update `installer.iss`: +``` +AppVersion=1.4.2 +``` + +**Step 2 — Build the .exe (on the Win7 VM)** + +1. Pull the latest code to the VM +2. Double-click `build.bat` +3. Output: `dist\series3-watcher.exe` + +> For hotfixes you can skip Inno Setup — existing machines only need the `.exe`. +> Only rebuild the installer if you need a fresh install package for a new machine. + +**Step 3 — Create a Gitea release** + +1. Go to `https://gitea.serversdown.net/serversdown/series3-watcher` +2. Click **Releases → New Release** +3. Tag must match the new version exactly (e.g. `v1.4.2`) — the auto-updater + compares this tag against its own version to decide whether to update +4. Upload `dist\series3-watcher.exe` as a release asset +5. Optionally upload `Output\series3-watcher-setup.exe` if you rebuilt the installer + +**Step 4 — Done** + +Existing installs check Gitea every ~5 minutes. When they see the new tag they +will download `series3-watcher.exe`, swap it in place, and relaunch silently. +No user action required on the target machine. + +--- + +## Version Numbering + +Follows Semantic Versioning: `MAJOR.MINOR.PATCH` + +| Change type | Example | +|-------------|---------| +| Bug fix / text change | `1.4.1 → 1.4.2` | +| New feature | `1.4.x → 1.5.0` | +| Breaking change | `1.x.x → 2.0.0` | + +--- + +## Files That Go in the Gitea Release + +| File | Required for | Notes | +|------|-------------|-------| +| `dist\series3-watcher.exe` | Auto-updates on existing machines | Always upload this | +| `Output\series3-watcher-setup.exe` | Fresh installs on new machines | Only needed for new deployments | + +--- + +## Files That Are NOT Committed to Git + +- `dist/` — PyInstaller output +- `Output/` — Inno Setup output +- `build/` — PyInstaller temp files +- `*.spec` — PyInstaller spec file +- `config.ini` — machine-specific, never commit +- `agent_logs/` — log files diff --git a/config-template.ini b/config-template.ini index 3d69ae6..5c5376c 100644 --- a/config-template.ini +++ b/config-template.ini @@ -19,7 +19,7 @@ MISSING_HOURS = 24 # Logging ENABLE_LOGGING = True -LOG_FILE = C:\Program Files\Series3Watcher\agent_logs\series3_watcher.log +LOG_FILE = C:\Users\%USERNAME%\AppData\Local\Series3Watcher\agent_logs\series3_watcher.log LOG_RETENTION_DAYS = 30 # Console colors - (Doesn't work on windows 7) diff --git a/series3_tray.py b/series3_tray.py index 454e498..1dea283 100644 --- a/series3_tray.py +++ b/series3_tray.py @@ -126,13 +126,21 @@ def apply_update(download_url): # --------------- Paths --------------- -# When frozen by PyInstaller, __file__ points to a temp extraction dir. -# sys.executable is always the real .exe location — use that instead. +# Executable location — used for bundled assets (icon.ico etc.) if getattr(sys, "frozen", False): HERE = os.path.dirname(os.path.abspath(sys.executable)) else: HERE = os.path.dirname(os.path.abspath(__file__)) -CONFIG_PATH = os.path.join(HERE, "config.ini") + +# config.ini lives in AppData so normal users can write it without UAC issues. +# Fall back to the exe directory when running from source (dev mode). +if getattr(sys, "frozen", False): + _appdata = os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA") or HERE + CONFIG_DIR = os.path.join(_appdata, "Series3Watcher") + os.makedirs(CONFIG_DIR, exist_ok=True) +else: + CONFIG_DIR = HERE +CONFIG_PATH = os.path.join(CONFIG_DIR, "config.ini") # --------------- Icon drawing --------------- diff --git a/series3_watcher.py b/series3_watcher.py index 7ab22ad..d3772c5 100644 --- a/series3_watcher.py +++ b/series3_watcher.py @@ -63,7 +63,10 @@ def load_config(path: str) -> Dict[str, Any]: "OK_HOURS": float(get_int("OK_HOURS", 12)), "MISSING_HOURS": float(get_int("MISSING_HOURS", 24)), "ENABLE_LOGGING": get_bool("ENABLE_LOGGING", True), - "LOG_FILE": get_str("LOG_FILE", r"C:\Program Files\Series3Watcher\agent_logs\series3_watcher.log"), + "LOG_FILE": get_str("LOG_FILE", os.path.join( + os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA") or "C:\\", + "Series3Watcher", "agent_logs", "series3_watcher.log" + )), "LOG_RETENTION_DAYS": get_int("LOG_RETENTION_DAYS", 30), "COLORIZE": get_bool("COLORIZE", False), # Win7 default off "MLG_HEADER_BYTES": max(256, min(get_int("MLG_HEADER_BYTES", 2048), 65536)), diff --git a/settings_dialog.py b/settings_dialog.py index 2013a00..a5414d4 100644 --- a/settings_dialog.py +++ b/settings_dialog.py @@ -34,7 +34,10 @@ DEFAULTS = { "MISSING_HOURS": "24", "MLG_HEADER_BYTES": "2048", "ENABLE_LOGGING": "true", - "LOG_FILE": r"C:\Program Files\Series3Watcher\agent_logs\series3_watcher.log", + "LOG_FILE": os.path.join( + os.environ.get("LOCALAPPDATA") or os.environ.get("APPDATA") or "C:\\", + "Series3Watcher", "agent_logs", "series3_watcher.log" + ), "LOG_RETENTION_DAYS": "30", "COLORIZE": "false", }