From 8d512b01584c0d165803a6ce516285c31b88a90b Mon Sep 17 00:00:00 2001 From: exzile Date: Tue, 30 Jun 2026 17:00:00 -0400 Subject: [PATCH] Add standalone Windows installer, uninstaller, and repairer for OVMS Introduce packaging/windows: a per-user Inno Setup installer plus PowerShell control scripts and a tray Manager that make OpenVINO Model Server installable, repairable, and removable on Windows without admin rights. - Installer (OVMSInstaller.iss): per-user install to %LOCALAPPDATA%, modern wizard UI with OpenVINO branding, existing-install detection with a repair/upgrade-vs-uninstall choice page, and caches the pristine package under %LOCALAPPDATA%\OVMS\packages\source for offline repair. - Scripts: configure-ovms, start/stop (process or service), set-path, service install/uninstall, validate-install, repair-package (verify + restore + ovms --version), and uninstall with a 3-way data choice (preserve all / keep models / remove all). - Manager: WinForms tray app (start/stop/status) as an MVP; full GUI to follow. - Bundles the python_on OVMS package (OpenVINO runtime, GenAI, tokenizers, Python) as a single version-matched payload. Co-Authored-By: Claude Opus 4.8 --- .../OVMS_WINDOWS_INSTALLER_MANAGER_PLAN.md | 1277 +++++++++++++++++ packaging/windows/README.md | 43 + packaging/windows/installer/OVMSInstaller.iss | 315 ++++ packaging/windows/installer/README.md | 29 + .../windows/installer/assets/ovms-small.bmp | Bin 0 -> 38566 bytes .../windows/installer/assets/ovms-welcome.bmp | Bin 0 -> 618006 bytes .../windows/installer/build_installer.ps1 | 59 + packaging/windows/manager/.gitignore | 3 + packaging/windows/manager/build_manager.ps1 | 22 + .../src/OVMS.Manager/Assets/ovms-manager.ico | Bin 0 -> 270398 bytes .../src/OVMS.Manager/OVMS.Manager.csproj | 12 + .../manager/src/OVMS.Manager/Program.cs | 212 +++ packaging/windows/scripts/configure-ovms.ps1 | 75 + packaging/windows/scripts/install-service.ps1 | 46 + packaging/windows/scripts/ovms-env.ps1 | 33 + packaging/windows/scripts/repair-package.ps1 | 91 ++ packaging/windows/scripts/set-path.ps1 | 44 + packaging/windows/scripts/start-ovms.ps1 | 86 ++ packaging/windows/scripts/stop-ovms.ps1 | 38 + packaging/windows/scripts/uninstall-ovms.ps1 | 71 + .../windows/scripts/uninstall-service.ps1 | 13 + .../windows/scripts/validate-install.ps1 | 36 + .../windows/settings/settings.template.json | 16 + 23 files changed, 2521 insertions(+) create mode 100644 packaging/windows/OVMS_WINDOWS_INSTALLER_MANAGER_PLAN.md create mode 100644 packaging/windows/README.md create mode 100644 packaging/windows/installer/OVMSInstaller.iss create mode 100644 packaging/windows/installer/README.md create mode 100644 packaging/windows/installer/assets/ovms-small.bmp create mode 100644 packaging/windows/installer/assets/ovms-welcome.bmp create mode 100644 packaging/windows/installer/build_installer.ps1 create mode 100644 packaging/windows/manager/.gitignore create mode 100644 packaging/windows/manager/build_manager.ps1 create mode 100644 packaging/windows/manager/src/OVMS.Manager/Assets/ovms-manager.ico create mode 100644 packaging/windows/manager/src/OVMS.Manager/OVMS.Manager.csproj create mode 100644 packaging/windows/manager/src/OVMS.Manager/Program.cs create mode 100644 packaging/windows/scripts/configure-ovms.ps1 create mode 100644 packaging/windows/scripts/install-service.ps1 create mode 100644 packaging/windows/scripts/ovms-env.ps1 create mode 100644 packaging/windows/scripts/repair-package.ps1 create mode 100644 packaging/windows/scripts/set-path.ps1 create mode 100644 packaging/windows/scripts/start-ovms.ps1 create mode 100644 packaging/windows/scripts/stop-ovms.ps1 create mode 100644 packaging/windows/scripts/uninstall-ovms.ps1 create mode 100644 packaging/windows/scripts/uninstall-service.ps1 create mode 100644 packaging/windows/scripts/validate-install.ps1 create mode 100644 packaging/windows/settings/settings.template.json diff --git a/packaging/windows/OVMS_WINDOWS_INSTALLER_MANAGER_PLAN.md b/packaging/windows/OVMS_WINDOWS_INSTALLER_MANAGER_PLAN.md new file mode 100644 index 0000000000..8a0980cd10 --- /dev/null +++ b/packaging/windows/OVMS_WINDOWS_INSTALLER_MANAGER_PLAN.md @@ -0,0 +1,1277 @@ +# OVMS Windows Installer and Manager Plan + +## Goal + +Create a Windows installer and GUI manager that make OpenVINO Model Server +simple to install, configure, run, and maintain on Windows. + +The user-facing experience should feel closer to a local AI desktop server app: + +- Install OVMS with the required OpenVINO runtime dependencies. +- Include GenAI/tokenizer support for LLM use cases when selected. +- Optionally include Python-enabled OVMS support. +- Configure server settings during installation. +- Provide a GUI and taskbar tray icon for later management. +- Support start-at-login and Windows Service modes. +- Allow repair, upgrade, and optional feature installation later. + +The first implementation should live in the `model_server` repository because +the primary product being installed and managed is `ovms.exe`. OpenVINO Runtime +and OpenVINO GenAI are dependencies consumed through the OVMS Windows package. + +## Non-Goals + +- Do not turn `ovms.exe` itself into a GUI application. +- Do not install unrelated OpenVINO SDK/toolkit components unless they are + required by the OVMS package. +- Do not mix arbitrary OpenVINO, GenAI, and OVMS versions. The installer and + manager should keep the installed stack version-matched. +- Do not replace the portable `ovms.zip` package. The installer should exist + alongside it. + +## Recommended Repository Layout + +```text +model_server/ + packaging/ + windows/ + OVMS_WINDOWS_INSTALLER_MANAGER_PLAN.md + README.md + installer/ + README.md + build_installer.ps1 + OVMSInstaller.iss + assets/ + uninstall/ + manager/ + README.md + build_manager.ps1 + OVMS.Manager.sln + src/ + OVMS.Manager/ + OVMS.Manager.Core/ + assets/ + scripts/ + configure-ovms.ps1 + install-service.ps1 + uninstall-service.ps1 + uninstall-ovms.ps1 + repair-package.ps1 + validate-install.ps1 + schemas/ + ovms-manager-settings.schema.json + install-options.schema.json +``` + +Existing root-level packaging scripts should remain in place: + +```text +windows_build.bat +windows_create_package.bat +install_ovms_service.bat +setupvars.bat +setupvars.ps1 +``` + +The Windows installer should consume the existing package output: + +```text +dist/windows/ovms/ +dist/windows/ovms.zip +``` + +Final release artifacts should include: + +```text +dist/windows/ovms.zip +dist/windows/OVMS-Setup.exe +``` + +## Product Architecture + +Keep the server headless and add a Windows UX layer around it. + +```text +OVMS-Setup.exe + installs files + writes first-time config + optionally registers the Windows Service + installs OVMS Manager + +OVMS Manager.exe + owns the GUI and tray icon + controls server startup/shutdown + manages settings, logs, models, and feature repair + +ovms.exe + remains the model server process +``` + +## Installer Technology + +Start with Inno Setup. + +Reasons: + +- Fast path to a polished single-file installer. +- Supports component selection, custom wizard pages, Start Menu shortcuts, + uninstall hooks, and scripted service commands. +- Easier to iterate than WiX/MSI for the first product version. + +WiX/MSI can be considered later if enterprise/GPO deployment becomes a firm +requirement. + +Inno Setup is a build-time dependency only. The generated installer must be a +normal Windows installer that does not require users to install Inno Setup, +Python, .NET, OpenVINO, GenAI, or other runtime packages separately. + +Runtime dependency policy: + +- OVMS, OpenVINO runtime DLLs, OpenVINO GenAI DLLs, tokenizers, and bundled + Python come from the packaged `dist/windows/ovms` payload. +- The tray app must be published self-contained and included in the installer + payload. +- The installer must not download required runtime dependencies during install. +- PowerShell may be used for install-time configuration because it is part of + supported Windows installations, but it must not fetch external packages. + +## Install Locations + +Program files: + +```text +C:\Program Files\OVMS\ +``` + +Persistent data: + +```text +C:\ProgramData\OVMS\ + settings.json + models\ + config.json + logs\ + ovms_server.log + packages\ + downloads\ +``` + +Per-user startup, when using login mode: + +```text +HKCU\Software\Microsoft\Windows\CurrentVersion\Run +``` + +Service configuration, when using service mode: + +```text +HKLM\SYSTEM\CurrentControlSet\Services\ovms +``` + +## Privilege Model + +The installer and Manager must support a clear privilege boundary. + +### Machine-Wide Install + +Default for the first release: + +```text +C:\Program Files\OVMS +C:\ProgramData\OVMS +HKLM service registration +Machine PATH, if selected +``` + +Machine-wide install requires elevation during setup. + +Admin-only actions: + +- Installing to `C:\Program Files\OVMS`. +- Writing machine-wide PATH entries. +- Registering or deleting the `ovms` Windows Service. +- Changing service start type. +- Writing service command-line configuration. +- Opening firewall rules, if added later. + +### Per-User Actions + +These should not require elevation: + +- Starting Manager at user login through HKCU Run. +- Starting or stopping a Manager-owned `ovms.exe` process. +- Editing user-writable settings where permissions allow it. +- Opening logs, model folders, and diagnostics. + +### Manager Elevation Behavior + +Manager should run unelevated by default. When the user performs an admin-only +action, Manager should prompt for elevation for that action only. + +Manager should not require elevation just to show the tray icon, read status, or +start a user-owned OVMS process. + +### Future Per-User Install + +A per-user install may be added later: + +```text +%LOCALAPPDATA%\Programs\OVMS +%LOCALAPPDATA%\OVMS +HKCU startup only +No Windows Service support unless elevated later +``` + +This should be treated as a separate install mode, not an accidental fallback. + +## Installer Wizard + +### Component Selection + +Suggested defaults: + +```text +[x] OpenVINO Model Server +[x] GenAI / LLM support +[x] Python support +[x] OVMS Manager app +[x] Tray icon +[ ] Windows Service +[ ] Start at boot +[x] Add OVMS to PATH +``` + +The UI should present OpenVINO and GenAI as required runtime capabilities of +the selected OVMS package, not as unrelated SDK installs. + +### Existing Install Detection + +Before showing the normal install flow, the installer must check whether OVMS is +already installed. + +Detection sources: + +- Apps & Features uninstall registry entry for OpenVINO Model Server. +- Existing install marker under `C:\Program Files\OVMS`. +- Existing Manager settings at `C:\ProgramData\OVMS\settings.json`. +- Existing `ovms` Windows Service registration. +- Existing PATH entries pointing to an OVMS install directory. +- Running `OVMS Manager.exe` process. +- Running `ovms.exe` process from a known OVMS install directory. + +Install marker: + +```text +C:\ProgramData\OVMS\install.json +``` + +Suggested content: + +```json +{ + "productName": "OpenVINO Model Server", + "installDir": "C:\\Program Files\\OVMS", + "dataDir": "C:\\ProgramData\\OVMS", + "version": "2026.2.1", + "packageVariant": "python_on", + "installedAtUtc": "2026-06-30T15:00:00Z", + "installerVersion": "1.0.0" +} +``` + +If an existing install is detected, the installer should offer: + +```text +Repair existing install +Upgrade existing install +Modify installed features +Uninstall +Cancel +``` + +Rules: + +- Do not silently install over an existing OVMS directory. +- Stop Manager and OVMS before repair, upgrade, modify, or uninstall. +- Preserve `C:\ProgramData\OVMS` by default. +- If multiple possible installs are detected, show the paths and require the user + to choose or cancel. +- If only a running `ovms.exe` is found outside the managed install directory, + warn about the conflict but do not treat it as the managed install. + +### Server Configuration + +Collect: + +```text +REST port: 8000 +gRPC port: 9000 +Bind address: 127.0.0.1 +Model repository: C:\ProgramData\OVMS\models +Log level: INFO +Log path: C:\ProgramData\OVMS\logs\ovms_server.log +``` + +### Runtime Mode + +Offer: + +```text +Run when I sign in with tray icon +Run as Windows Service +Manual only +``` + +Recommended default: + +```text +Run when I sign in with tray icon +``` + +Advanced option: + +```text +Run as Windows Service and optionally start at boot +``` + +### Optional Initial Model + +Offer: + +```text +None +Add local model +Pull model after install +``` + +The MVP can start with `None` only and add model workflows in a later phase. + +### Finish Page + +Offer: + +```text +[x] Launch OVMS Manager +[ ] Start server now +``` + +## Manager Application + +Use .NET WPF or WinUI 3. WPF is the recommended first choice because it is +pragmatic, native-feeling, and works well with tray icons, Windows services, +process control, and file-based settings. + +Suggested projects: + +```text +OVMS.Manager + WPF UI and tray integration + +OVMS.Manager.Core + service/process/config/log/package logic +``` + +### Dashboard + +Show: + +- Server running/stopped state. +- Runtime mode: process, service, or manual. +- Active REST and gRPC ports. +- Bind address. +- Installed package variant. +- Served model count. +- Latest health check result. + +Health check: + +```text +GET http://127.0.0.1:/v3/models +``` + +### Server Controls + +Support: + +- Start server. +- Stop server. +- Restart server. +- Reload status. +- Open logs. +- Open model repository. + +In user-login mode, Manager starts and stops `ovms.exe` directly. + +In service mode, Manager controls the `ovms` Windows Service. + +### Settings + +Support editing: + +- REST port. +- gRPC port. +- Bind address. +- Log level. +- Log path. +- Model repository path. +- Config path. +- Target device defaults, if added later. +- Startup mode. +- Show tray icon. + +Settings changes that affect the process command line should prompt for or +perform a restart. + +### Startup + +Support: + +- Start Manager at user login. +- Show tray icon. +- Start OVMS when Manager starts. +- Register as Windows Service. +- Configure service start type: manual or automatic. + +### Models + +Support: + +- List configured models from `config.json`. +- Add local model. +- Remove model from config. +- Open model folder. +- Refresh/reload config. +- Pull supported model, in a later phase. + +### Features + +Detect: + +- `ovms.exe` exists. +- `openvino_genai.dll` exists. +- `openvino_tokenizers.dll` exists. +- `python\python.exe` exists, for Python-enabled package. +- `ovms.exe --version` succeeds. + +Show: + +```text +GenAI support: Installed / Missing +Python support: Installed / Missing +Package variant: python_on / python_off +``` + +If GenAI or Python support is missing, offer repair or upgrade to a matching +package variant rather than mixing arbitrary DLL versions. + +### Updates + +Support: + +- Check for updates manually from Manager. +- Optionally check for updates periodically. +- Show installed version, latest available version, package variant, and release + notes link. +- Download updates only after user confirmation. +- Reuse the staged upgrade and rollback flow. + +The first release should not silently auto-install updates. + +### Logs + +Support: + +- Tail `ovms_server.log`. +- Open log folder. +- Copy diagnostics summary. +- Show recent service events, if practical. + +### Advanced + +Support: + +- View effective server command line. +- Validate PATH and environment variables. +- Reset config. +- Repair package. +- Check for updates. +- Export diagnostics bundle. + +## Tray Icon + +The tray icon belongs to `OVMS Manager.exe`, not `ovms.exe`. + +Left-click behavior: + +- Open or focus the OVMS Manager window. +- If the Manager window is minimized or hidden, restore it. +- If the Manager window is already open, bring it to the foreground. + +Context menu: + +```text +Open OVMS Manager +Start Server +Stop Server +``` + +Keep the first version intentionally small. Additional items such as restart, +logs, diagnostics, model folder, settings, and quit can be added later from the +Manager UI if needed. + +Notifications: + +- Server started. +- Server stopped. +- Server failed to start. +- Port already in use. +- Model config changed. + +## Configuration Files + +Manager settings: + +```text +C:\ProgramData\OVMS\settings.json +``` + +Initial content: + +```json +{ + "installDir": "C:\\Program Files\\OVMS", + "dataDir": "C:\\ProgramData\\OVMS", + "modelRepositoryPath": "C:\\ProgramData\\OVMS\\models", + "configPath": "C:\\ProgramData\\OVMS\\models\\config.json", + "logPath": "C:\\ProgramData\\OVMS\\logs\\ovms_server.log", + "restPort": 8000, + "grpcPort": 9000, + "bindAddress": "127.0.0.1", + "logLevel": "INFO", + "runMode": "user-login", + "startAtLogin": true, + "showTrayIcon": true, + "serviceAutoStart": false, + "packageVariant": "python_on" +} +``` + +OVMS config: + +```text +C:\ProgramData\OVMS\models\config.json +``` + +Initial content: + +```json +{ + "model_config_list": [] +} +``` + +## Startup Modes + +### User-Login Mode + +Behavior: + +- Manager starts at user login. +- Manager owns the tray icon. +- Manager starts `ovms.exe` hidden. +- Server runs only after user login. + +This is the best Ollama-like default. + +### Service Mode + +Behavior: + +- `ovms` Windows Service owns the server process. +- Service can start before user login. +- Manager controls service state. +- Tray icon is still provided by Manager after login. + +This is best for machine/server reliability. + +### Manual Mode + +Behavior: + +- Nothing starts automatically. +- User launches Manager and starts OVMS manually. + +This is best for development and low-impact installs. + +## Runtime Ownership + +Exactly one runtime owner should control OVMS at a time. + +Runtime owners: + +```text +manager-process +windows-service +manual +none +``` + +Manager must avoid starting a duplicate server when: + +- The `ovms` Windows Service is running. +- A Manager-owned `ovms.exe` process is already running. +- Another process is already listening on the configured REST or gRPC port. +- A lock file indicates another Manager instance is controlling the server. + +State file: + +```text +C:\ProgramData\OVMS\runtime.json +``` + +Suggested content: + +```json +{ + "owner": "manager-process", + "pid": 12345, + "serviceName": "ovms", + "restPort": 8000, + "grpcPort": 9000, + "startedAtUtc": "2026-06-30T15:00:00Z" +} +``` + +Lock file: + +```text +C:\ProgramData\OVMS\ovms-manager.lock +``` + +Ownership rules: + +- User-login mode may start only a Manager-owned process. +- Service mode may start only the `ovms` Windows Service. +- Manual mode never auto-starts OVMS. +- Switching from process mode to service mode must stop the process first. +- Switching from service mode to process mode must stop the service first. +- Manager should show the current owner and block conflicting start actions with + a clear explanation. + +Port preflight: + +- Before starting OVMS, Manager must check configured REST and gRPC ports. +- If a port is occupied by another process, Manager should show the process id + and executable name when available. +- Manager should not blindly kill unrelated processes. + +## Feature and Package Strategy + +Use the OVMS Windows package as the unit of installation. + +Recommended variants: + +```text +Minimal install: OVMS python_off package +LLM/GenAI install: OVMS python_on package +``` + +Do not independently install unmatched OpenVINO Runtime, GenAI, and tokenizer +DLLs. The Manager should install, repair, or upgrade a matching OVMS package +variant. + +This avoids version mismatch issues between: + +- `ovms.exe` +- OpenVINO runtime DLLs +- OpenVINO GenAI DLLs +- OpenVINO tokenizers DLLs +- Python support files + +## Upgrade and Repair Strategy + +Upgrade and repair must be staged and recoverable. + +Package source: + +- Installer builds from local `dist/windows/ovms`. +- Manager repair/upgrade uses a matching OVMS release package or an installer + cache under `C:\ProgramData\OVMS\packages`. + +Verification before use: + +- Validate package version metadata. +- Validate expected files are present. +- Validate checksums or signatures when packages are downloaded. +- Run `ovms.exe --version` from the staged package before swapping. + +Staging path: + +```text +C:\ProgramData\OVMS\packages\staging\\ +``` + +Backup path: + +```text +C:\ProgramData\OVMS\packages\backup\\ +``` + +Upgrade steps: + +1. Stop Manager-owned OVMS process or `ovms` service. +2. Download or locate the matching package. +3. Verify checksum/signature and required files. +4. Extract to staging. +5. Run staged `ovms.exe --version`. +6. Backup current install files. +7. Swap staged files into `C:\Program Files\OVMS`. +8. Preserve `C:\ProgramData\OVMS` settings, models, and logs. +9. Restart OVMS if it was running before upgrade. +10. Run health check. +11. Roll back from backup if version or health validation fails. + +Repair steps: + +- Re-verify installed files. +- Restore missing files from package cache when possible. +- Re-run `ovms.exe --version`. +- Re-register service only if the selected runtime mode requires it. + +The Manager should never mix individual DLLs from unrelated package versions. + +## Update Checking + +Update checking should be explicit, version-aware, and safe. + +Default behavior: + +- Manual update checks are supported. +- Periodic update checks are opt-in. +- Updates are downloaded and installed only after user confirmation. + +Update source: + +- Official OVMS release metadata. +- For development builds, an explicitly configured package feed may be used. + +The Manager should compare: + +- Installed OVMS version. +- Installed package variant, such as `python_on` or `python_off`. +- Installed Manager version. +- Latest compatible OVMS package. +- Latest compatible Manager package. + +Update states: + +```text +Up to date +Update available +Update downloaded +Update failed +Update requires restart +Cannot check for updates +``` + +Update flow: + +1. User clicks "Check for updates". +2. Manager fetches release metadata. +3. Manager shows latest compatible version and release notes link. +4. User confirms download. +5. Manager downloads package to `C:\ProgramData\OVMS\packages`. +6. Manager verifies checksum/signature. +7. Manager stages package. +8. Manager stops OVMS if needed. +9. Manager applies upgrade using the staged upgrade flow. +10. Manager restarts OVMS if it was running before update. +11. Manager reports success or rollback result. + +The update checker must never install a package whose version or variant cannot +be matched to the installed stack. + +## Configuration Safety + +All configuration writes must be validated and recoverable. + +Files controlled by Manager: + +```text +C:\ProgramData\OVMS\settings.json +C:\ProgramData\OVMS\models\config.json +C:\ProgramData\OVMS\runtime.json +``` + +Rules: + +- Validate JSON before saving. +- Validate against schema where a schema exists. +- Write to a temporary file first. +- Atomically replace the destination file. +- Keep a `.bak` copy of the previous valid version. +- Preserve comments only if a comment-preserving parser is adopted; otherwise + treat files as strict JSON. +- If config is malformed on startup, show the error and offer restore from + backup. + +Suggested backup names: + +```text +settings.json.bak +config.json.bak +runtime.json.bak +``` + +Restart behavior: + +- Settings that alter the OVMS command line require restart. +- Settings that only affect Manager UI should apply immediately. +- Manager must validate config before restarting OVMS. + +## Security and Network Exposure + +Default bind address must be local-only: + +```text +127.0.0.1 +``` + +Binding to these addresses is security-sensitive: + +```text +0.0.0.0 +:: +LAN adapter IPs +``` + +If the user selects a non-local bind address, Manager should: + +- Show an explicit warning that the model server may be reachable from other + devices. +- Require confirmation. +- Show the active URLs after restart. +- Avoid adding firewall rules unless the user explicitly opts in. + +If firewall rule management is added later, it must be treated as an admin-only +operation and must be removed during uninstall if created by the installer or +Manager. + +## Model Download and Trust + +Model download can be added after the MVP, but the plan must account for trust +and storage rules. + +Model download requirements: + +- Show source, model id, license link, and estimated size before download. +- Support cancellation. +- Support resume when practical. +- Check free disk space before download. +- Use a cache under `C:\ProgramData\OVMS\downloads` by default. +- Support Hugging Face authentication for gated models if needed. +- Do not auto-accept model licenses on behalf of the user. +- Record downloaded model metadata. + +Metadata path: + +```text +C:\ProgramData\OVMS\models\model-metadata.json +``` + +Suggested metadata: + +```json +{ + "models": [ + { + "name": "OpenVINO/Qwen3-8B-int4-ov", + "source": "huggingface", + "path": "C:\\ProgramData\\OVMS\\models\\OpenVINO\\Qwen3-8B-int4-ov", + "downloadedAtUtc": "2026-06-30T15:00:00Z", + "licenseAccepted": false + } + ] +} +``` + +## Installer Responsibilities + +Install: + +- Copy `dist/windows/ovms` to install directory. +- Copy `OVMS Manager.exe` and supporting files. +- Create `C:\ProgramData\OVMS`. +- Create `install.json`. +- Create default `settings.json`. +- Create default `models\config.json`. +- Add PATH entries if selected. +- Register service if selected. +- Add login startup entry if selected. +- Create Start Menu shortcuts. +- Launch Manager if selected. + +Uninstall: + +- Stop Manager-controlled process if running. +- Stop service if installed. +- Delete service if installed. +- Remove login startup entry. +- Remove PATH entries created by installer. +- Remove program files. +- Ask whether to preserve models, logs, and settings under `C:\ProgramData\OVMS`. + +## Manager Responsibilities + +- Read and write `settings.json`. +- Read `install.json` and report installed version/variant. +- Read and update OVMS `config.json`. +- Build the effective `ovms.exe` command line. +- Start and stop `ovms.exe` in user-login/manual modes. +- Start and stop the `ovms` Windows Service in service mode. +- Update service command line when settings change. +- Run health checks. +- Show logs. +- Detect package capabilities. +- Repair or upgrade the installed package. +- Check for updates. +- Manage startup mode. +- Enforce runtime ownership rules. +- Validate ports before starting OVMS. +- Validate and atomically write configuration. +- Export diagnostics bundles. + +## Build Pipeline + +Initial local pipeline: + +```powershell +.\windows_build.bat --with_python +.\windows_create_package.bat opt --with_python +.\packaging\windows\manager\build_manager.ps1 +.\packaging\windows\installer\build_installer.ps1 +``` + +Expected outputs: + +```text +dist/windows/ovms.zip +dist/windows/OVMS-Setup.exe +``` + +The installer build should fail clearly if `dist/windows/ovms/ovms.exe` is +missing. + +## Uninstaller + +Uninstall support is a first-class deliverable. The Windows installer must +register a standard uninstaller in Windows Apps & Features and provide clean +scripted cleanup for files, service state, startup entries, and environment +changes. + +Uninstaller entry: + +```text +Settings > Apps > Installed apps > OpenVINO Model Server +``` + +Uninstaller responsibilities: + +- Stop `OVMS Manager.exe` if it is running. +- Stop any Manager-launched `ovms.exe` process. +- Stop the `ovms` Windows Service if installed. +- Delete the `ovms` Windows Service if installed. +- Remove login startup registry entries created by the installer. +- Remove PATH entries created by the installer. +- Remove Start Menu and desktop shortcuts. +- Remove installed program files under `C:\Program Files\OVMS`. +- Ask whether to preserve user data under `C:\ProgramData\OVMS`. +- Preserve models, logs, and settings by default unless the user selects full + removal. + +User data removal options: + +```text +Preserve models, logs, and settings +Remove logs and settings but keep models +Remove everything, including models +``` + +The uninstaller should avoid deleting arbitrary user-selected directories unless +they are inside `C:\ProgramData\OVMS` or were explicitly created by the +installer. If the user configured an external model repository, uninstall should +preserve it by default and show the path before offering deletion. + +## Diagnostics + +Diagnostics should be available before release hardening. The Manager should +include a "Copy diagnostics" or "Export diagnostics bundle" action. + +Diagnostics bundle contents: + +- Manager version. +- OVMS version from `ovms.exe --version`. +- Installed package variant. +- Install directory. +- Data directory. +- Effective command line with secrets redacted. +- `settings.json`. +- OVMS `config.json`. +- `runtime.json`. +- Service state from `sc query ovms`, when available. +- Service configuration from `sc qc ovms`, when available. +- Port ownership for configured REST and gRPC ports. +- Last 500 lines of `ovms_server.log`, if present. +- Recent Manager log entries. +- Latest health check result. + +Diagnostics should be written to: + +```text +C:\ProgramData\OVMS\diagnostics\ovms-diagnostics-.zip +``` + +Sensitive values, tokens, and credentials must be redacted. + +## Test Matrix + +The Windows installer and Manager should have explicit install-time and +runtime smoke tests. + +Installer tests: + +- Detect existing install and show repair/upgrade/modify/uninstall choices. +- Clean machine-wide install. +- Install with PATH enabled. +- Install without PATH. +- Install with Manager startup enabled. +- Install with service mode enabled. +- Install to a path containing spaces. +- Install when `C:\ProgramData\OVMS` already exists. +- Install over a previous version. +- Detect existing unmanaged `ovms.exe` and warn without modifying it. + +Manager tests: + +- Start/stop/restart in user-login mode. +- Start/stop/restart in service mode. +- Switch from process mode to service mode. +- Switch from service mode to process mode. +- Block duplicate start when port is occupied. +- Report owner when another OVMS process is running. +- Persist settings changes. +- Restore malformed config from backup. +- Export diagnostics bundle. + +Uninstaller tests: + +- Uninstall after process-mode install. +- Uninstall after service-mode install. +- Preserve models/logs/settings. +- Remove logs/settings but keep models. +- Full removal. +- External model repository is preserved by default. +- PATH and startup entries are removed. +- Service is stopped and deleted. + +Upgrade/repair tests: + +- Repair missing DLL. +- Repair missing Manager file. +- Upgrade python_off to python_on. +- Failed upgrade rolls back. +- Upgrade preserves settings and model repository. +- Update checker reports up-to-date state. +- Update checker reports update-available state. +- Update checker handles offline/network failure. + +Security tests: + +- Default bind is `127.0.0.1`. +- Non-local bind shows warning. +- Firewall changes require explicit opt-in if implemented. + +## Implementation Phases + +### Phase 1: Foundation + +- Add folder layout. +- Add README files. +- Add settings schema. +- Add install-options schema. +- Add install marker schema. +- Add runtime state schema. +- Add validation script. +- Document service/process/startup behavior. +- Document privilege model. +- Document runtime ownership rules. +- Document config safety rules. + +Acceptance criteria: + +- `packaging/windows` documents the intended architecture. +- `validate-install.ps1` can inspect an unpacked OVMS folder and report missing + required files. +- The plan defines admin-only actions and non-admin Manager actions. +- The plan defines duplicate-start prevention. + +### Phase 2: Installer MVP + +- Add Inno Setup script. +- Add existing-install detection. +- Install existing `dist/windows/ovms` package. +- Write `settings.json`. +- Write empty OVMS `config.json`. +- Create Start Menu shortcuts. +- Support Add to PATH. +- Support optional service registration. +- Register a standard Apps & Features uninstaller. +- Support clean uninstall with preserve/remove data options. +- Implement elevated machine-wide install. +- Fail clearly when required elevation is unavailable. + +Acceptance criteria: + +- Fresh install succeeds on Windows. +- Existing install shows repair/upgrade/modify/uninstall choices. +- `ovms.exe --version` works after install. +- User can start OVMS manually from installed files. +- Uninstall removes program files, service registration, startup entries, PATH + changes, and shortcuts. +- Uninstall preserves or removes data according to user choice. +- Installer-created PATH and startup entries are tracked for cleanup. + +### Phase 3: Manager MVP + +- Add WPF Manager shell. +- Add tray icon. +- Add dashboard. +- Add start/stop/restart controls. +- Add settings page. +- Add logs page. +- Add start-at-login toggle. +- Add runtime ownership detection. +- Add port preflight. +- Add minimal diagnostics export. + +Acceptance criteria: + +- Manager starts from Start Menu. +- Tray menu works. +- Manager can start and stop `ovms.exe`. +- Health check reflects the running server state. +- Settings changes persist. +- Manager blocks duplicate starts and reports port conflicts. +- Diagnostics bundle can be exported. + +### Phase 4: Service Mode + +- Manager can register/unregister service. +- Manager can start/stop/restart service. +- Manager can set service start type. +- Installer and Manager use compatible service configuration. +- Switching runtime modes stops the previous owner first. + +Acceptance criteria: + +- `sc query ovms` reflects selected state. +- Service mode starts OVMS with configured port, bind address, config path, and + log path. +- Manager reports service errors clearly. +- Manager does not allow process mode and service mode to run OVMS + simultaneously. + +### Phase 5: Model Management + +- List configured models. +- Add local model to `config.json`. +- Remove model from `config.json`. +- Open model repository. +- Refresh health/model list. +- Validate config before writing. +- Backup config before writing. + +Acceptance criteria: + +- Adding a local model updates `config.json`. +- Removing a model updates `config.json`. +- Manager shows served models when OVMS is running. +- Malformed config can be restored from backup. + +### Phase 6: Feature Management + +- Detect GenAI support. +- Detect Python support. +- Detect package variant. +- Offer repair install. +- Offer upgrade from python_off to python_on using a matching package. +- Add manual update checking. +- Stage package upgrades. +- Verify package before swap. +- Roll back failed upgrades. + +Acceptance criteria: + +- Manager reports installed capabilities accurately. +- Repair verifies required files after completion. +- Upgrade preserves settings and model repository. +- Failed upgrade restores the previous working package. +- Update checker reports current state accurately. + +### Phase 7: Release Hardening + +- Add code signing path. +- Add installer versioning. +- Add upgrade behavior. +- Add modify/repair behavior for existing installs. +- Add update checking and package-feed compatibility rules. +- Add diagnostics bundle export. +- Add CI packaging job. +- Add documentation for support and troubleshooting. +- Add automated installer, Manager, service, uninstall, and upgrade smoke tests. + +Acceptance criteria: + +- Signed installer builds reproducibly. +- Installing over a previous version upgrades cleanly. +- Diagnostics bundle contains settings, logs, version, service state, and health + check output. +- Test matrix runs successfully on a clean Windows worker. + +## Open Questions + +- Should the default REST port be 8000, or should it preserve the current local + AgentTools convention when used there? +- Should the installer default to user-login mode or service mode for non-admin + installs? +- Should the first version support model download during install, or should that + be Manager-only after install? +- Should we ship both python_on and python_off installers, or one installer that + can download the other package variant? +- Should Manager require admin elevation only for service/PATH changes, or run + elevated at startup? +- Should the first release support per-user install, or only elevated + machine-wide install? +- What package signature/hash source should Manager trust for repair and + upgrade downloads? +- Should periodic update checks be opt-in during install or only configurable + later in Manager? +- What registry keys should be authoritative for installed-version detection? +- Should non-local bind addresses be allowed in the installer, or only in + Manager advanced settings? +- How should Manager store Hugging Face tokens if gated model downloads are + supported? + +## First Concrete Tasks + +1. Add `packaging/windows/README.md` summarizing the installer and manager + ownership. +2. Add schemas for `settings.json`, install options, and install marker. +3. Add existing-install detection rules. +4. Add runtime state schema and duplicate-start ownership rules. +5. Add `validate-install.ps1` for unpacked `dist/windows/ovms`. +6. Add an Inno Setup MVP that installs the existing package. +7. Add explicit uninstaller scripts and Apps & Features registration. +8. Add a minimal WPF Manager with tray icon and start/stop controls. +9. Add diagnostics export and port preflight. +10. Add manual update checker design and package metadata contract. diff --git a/packaging/windows/README.md b/packaging/windows/README.md new file mode 100644 index 0000000000..059ea019ad --- /dev/null +++ b/packaging/windows/README.md @@ -0,0 +1,43 @@ +# OVMS Windows Packaging + +This folder contains the Windows installer, uninstaller, server-control scripts, +and lightweight tray app for OpenVINO Model Server. + +The first implementation intentionally keeps the full configuration UI out of +scope. It provides: + +- An Inno Setup installer that consumes `dist/windows/ovms`. +- A standard Windows uninstaller. +- First-run settings and install markers under `C:\ProgramData\OVMS`. +- A minimal tray app with: + - Open OVMS Manager + - Start Server + - Stop Server + +The installed application should behave like a regular Windows application. It +must not require the user to install Python, .NET, OpenVINO, GenAI, or other +runtime dependencies separately. Those files are bundled in the installer +payload: + +- OpenVINO and GenAI DLLs come from `dist/windows/ovms`. +- Bundled Python support comes from the `python_on` OVMS package. +- The tray app is published self-contained so it does not require a separate + .NET Desktop Runtime install. +- Inno Setup is a build-time tool only; users do not need it installed. + +The full Manager UI is planned as a later phase. + +## Build Order + +```powershell +.\windows_build.bat --with_python +.\windows_create_package.bat opt --with_python +.\packaging\windows\manager\build_manager.ps1 +.\packaging\windows\installer\build_installer.ps1 +``` + +Expected output: + +```text +dist/windows/OVMS-Setup.exe +``` diff --git a/packaging/windows/installer/OVMSInstaller.iss b/packaging/windows/installer/OVMSInstaller.iss new file mode 100644 index 0000000000..97c1d88346 --- /dev/null +++ b/packaging/windows/installer/OVMSInstaller.iss @@ -0,0 +1,315 @@ +#define AppName "OpenVINO Model Server" +#define AppPublisher "OpenVINO" +#define AppExeName "OVMS.Manager.exe" +#ifndef SourceRoot +#define SourceRoot "..\..\.." +#endif +#ifndef OvmsSourceDir +#define OvmsSourceDir SourceRoot + "\dist\windows\ovms" +#endif +#ifndef ManagerPublishDir +#define ManagerPublishDir SourceRoot + "\packaging\windows\manager\artifacts\publish" +#endif +#ifndef OutputDir +#define OutputDir SourceRoot + "\dist\windows" +#endif + +[Setup] +AppId={{9F35B167-C72A-4E1D-93E9-448CE4AE5270} +AppName={#AppName} +AppVersion=1.0.0 +AppPublisher={#AppPublisher} +DefaultDirName={localappdata}\Programs\OVMS +DefaultGroupName=OpenVINO Model Server +DisableProgramGroupPage=yes +OutputDir={#OutputDir} +OutputBaseFilename=OVMS-Setup +Compression=lzma +SolidCompression=yes +ArchitecturesAllowed=x64compatible +ArchitecturesInstallIn64BitMode=x64compatible +PrivilegesRequired=lowest +UninstallDisplayName={#AppName} +UninstallDisplayIcon={app}\OVMS.Manager.exe +CloseApplications=yes +RestartApplications=no +WizardStyle=modern +WizardSizePercent=120 +WizardImageFile=assets\ovms-welcome.bmp +WizardSmallImageFile=assets\ovms-small.bmp +WizardImageStretch=yes +DisableWelcomePage=no +ShowLanguageDialog=no +DisableReadyPage=no + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "path"; Description: "Add OVMS to PATH"; GroupDescription: "Optional configuration:"; Flags: checkedonce +Name: "startup"; Description: "Start tray app when I sign in"; GroupDescription: "Optional configuration:"; Flags: checkedonce + +[Files] +Source: "{#OvmsSourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "{#ManagerPublishDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "{#SourceRoot}\packaging\windows\scripts\*.ps1"; DestDir: "{app}\scripts"; Flags: ignoreversion +Source: "{#SourceRoot}\packaging\windows\settings\settings.template.json"; DestDir: "{app}\templates"; Flags: ignoreversion +Source: "{#OvmsSourceDir}\*"; DestDir: "{localappdata}\OVMS\packages\source"; Flags: ignoreversion recursesubdirs createallsubdirs + +[Icons] +Name: "{group}\Open OVMS Manager"; Filename: "{app}\OVMS.Manager.exe" +Name: "{group}\Start OVMS Server"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\start-ovms.ps1"" -DataDir ""{localappdata}\OVMS""" +Name: "{group}\Stop OVMS Server"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\stop-ovms.ps1"" -DataDir ""{localappdata}\OVMS""" +Name: "{group}\Repair OVMS Server"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\repair-package.ps1"" -InstallDir ""{app}"" -DataDir ""{localappdata}\OVMS""" +Name: "{group}\Uninstall OpenVINO Model Server"; Filename: "{uninstallexe}" + +[Registry] +Root: HKCU; Subkey: "Software\OpenVINO\OVMS"; ValueType: string; ValueName: "InstallDir"; ValueData: "{app}"; Flags: uninsdeletekey +Root: HKCU; Subkey: "Software\OpenVINO\OVMS"; ValueType: string; ValueName: "DataDir"; ValueData: "{localappdata}\OVMS"; Flags: uninsdeletekey +Root: HKCU; Subkey: "Software\OpenVINO\OVMS"; ValueType: string; ValueName: "Version"; ValueData: "1.0.0"; Flags: uninsdeletekey +Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "OVMS Manager"; ValueData: """{app}\OVMS.Manager.exe"""; Tasks: startup; Flags: uninsdeletevalue + +[Run] +Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\configure-ovms.ps1"" -InstallDir ""{app}"" -DataDir ""{localappdata}\OVMS"" -PackageVariant ""python_on"""; Flags: runhidden waituntilterminated +Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\set-path.ps1"" -InstallDir ""{app}"" -Action Add"; Tasks: path; Flags: runhidden waituntilterminated +Filename: "{app}\OVMS.Manager.exe"; Description: "Launch OVMS Manager"; Flags: nowait postinstall skipifsilent + +[UninstallRun] +Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\uninstall-ovms.ps1"" -InstallDir ""{app}"" -DataDir ""{localappdata}\OVMS"" -DataMode ""{code:GetDataMode}"""; Flags: runhidden waituntilterminated; RunOnceId: "OVMSCleanup" + +[Code] +var + DataModeChoice: String; + // Existing-install detection state, populated in InitializeSetup and + // consumed by InitializeWizard/NextButtonClick to drive the custom page. + ExistingInstallDetected: Boolean; + ExistingInstallDir: String; + ExistingUninstallString: String; + ExistingInstallPage: TWizardPage; + RbRepair: TNewRadioButton; + RbUninstall: TNewRadioButton; + // When True, the "Exit Setup?" confirmation is suppressed so Setup can + // close cleanly after handing off to the existing uninstaller. + SuppressCancelConfirm: Boolean; + +function GetDataMode(Param: String): String; +begin + Result := DataModeChoice; +end; +function QueryExistingManagedInstall(var ExistingDir: String; var UninstallString: String): Boolean; +begin + Result := False; + ExistingDir := ''; + UninstallString := ''; + + if RegQueryStringValue(HKCU, 'Software\OpenVINO\OVMS', 'InstallDir', ExistingDir) then + begin + RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{9F35B167-C72A-4E1D-93E9-448CE4AE5270}_is1', 'UninstallString', UninstallString); + Result := True; + exit; + end; + + if RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{9F35B167-C72A-4E1D-93E9-448CE4AE5270}_is1', 'InstallLocation', ExistingDir) then + begin + RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{9F35B167-C72A-4E1D-93E9-448CE4AE5270}_is1', 'UninstallString', UninstallString); + Result := True; + exit; + end; + + if DirExists(ExpandConstant('{localappdata}\Programs\OVMS')) then + begin + ExistingDir := ExpandConstant('{localappdata}\Programs\OVMS'); + RegQueryStringValue(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{9F35B167-C72A-4E1D-93E9-448CE4AE5270}_is1', 'UninstallString', UninstallString); + Result := True; + end; +end; + +function HasRunningOvmsProcess(): Boolean; +var + ResultCode: Integer; + MarkerPath: String; +begin + MarkerPath := ExpandConstant('{tmp}\ovms-running.txt'); + DeleteFile(MarkerPath); + Exec('powershell.exe', + '-NoProfile -ExecutionPolicy Bypass -Command "if (Get-Process ovms -ErrorAction SilentlyContinue) { ''''running'''' | Set-Content -Path ''''' + MarkerPath + ''''' }"', + '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + Result := FileExists(MarkerPath); + DeleteFile(MarkerPath); +end; + +function RunExistingUninstaller(UninstallString: String): Boolean; +var + ResultCode: Integer; +begin + Result := False; + if UninstallString = '' then + begin + MsgBox('An existing OpenVINO Model Server install was detected, but its uninstaller could not be found.', mbError, MB_OK); + exit; + end; + + Exec('cmd.exe', '/C ' + UninstallString, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode); + Result := ResultCode = 0; +end; + +procedure StopRunningManager(); +var + ResultCode: Integer; +begin + Exec('taskkill.exe', '/IM OVMS.Manager.exe /F', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); +end; + +function InitializeSetup(): Boolean; +begin + Result := True; + StopRunningManager(); + + // Existing-install detection: just stash the result in globals. The actual + // repair-vs-uninstall choice is now presented as a custom wizard page + // (see InitializeWizard/NextButtonClick below) instead of a MsgBox here. + // For silent installs there is no UI at all, so default to repair/upgrade + // (i.e. just proceed) -- ExistingInstallDetected is still set, but since + // the custom page is never shown/navigated in silent mode, RbRepair's + // default behavior (proceed) is effectively what happens. + ExistingInstallDetected := QueryExistingManagedInstall(ExistingInstallDir, ExistingUninstallString); + + if HasRunningOvmsProcess() then + begin + if WizardSilent() then + begin + Result := True; + exit; + end; + + if MsgBox( + 'A running ovms.exe process was detected, but it does not appear to be managed by this installer.' + #13#10#13#10 + + 'Setup will not repair or uninstall unmanaged portable OVMS processes. Stop the running server before installing if it uses the same ports.' + #13#10#13#10 + + 'Continue setup?', + mbConfirmation, MB_YESNO) = IDNO then + begin + Result := False; + end; + end; +end; + +procedure InitializeWizard(); +var + Lbl: TNewStaticText; +begin + if not ExistingInstallDetected then + exit; + + ExistingInstallPage := CreateCustomPage(wpWelcome, + 'Existing Installation Found', + 'OpenVINO Model Server is already installed on this computer.'); + + Lbl := TNewStaticText.Create(ExistingInstallPage); + Lbl.Parent := ExistingInstallPage.Surface; + Lbl.Left := 0; + Lbl.Top := 0; + Lbl.Width := ExistingInstallPage.SurfaceWidth; + Lbl.AutoSize := False; + Lbl.WordWrap := True; + Lbl.Caption := + 'An existing install was found at:' + #13#10 + + ExistingInstallDir + #13#10#13#10 + + 'Choose how to continue:'; + Lbl.Height := ScaleY(60); + + RbRepair := TNewRadioButton.Create(ExistingInstallPage); + RbRepair.Parent := ExistingInstallPage.Surface; + RbRepair.Left := 0; + RbRepair.Top := Lbl.Top + Lbl.Height + ScaleY(8); + RbRepair.Width := ExistingInstallPage.SurfaceWidth; + RbRepair.Height := ScaleY(17); + RbRepair.Caption := 'Repair or upgrade the existing installation (recommended)'; + RbRepair.Checked := True; + + RbUninstall := TNewRadioButton.Create(ExistingInstallPage); + RbUninstall.Parent := ExistingInstallPage.Surface; + RbUninstall.Left := 0; + RbUninstall.Top := RbRepair.Top + RbRepair.Height + ScaleY(8); + RbUninstall.Width := ExistingInstallPage.SurfaceWidth; + RbUninstall.Height := ScaleY(17); + RbUninstall.Caption := 'Uninstall the existing installation, then exit'; +end; + +function NextButtonClick(CurPageID: Integer): Boolean; +begin + Result := True; + + if (ExistingInstallPage <> nil) and (CurPageID = ExistingInstallPage.ID) then + begin + if RbUninstall.Checked then + begin + RunExistingUninstaller(ExistingUninstallString); + // Hand-off to the existing uninstaller is done; close Setup cleanly. + // SuppressCancelConfirm tells CancelButtonClick to skip the normal + // "Setup is not complete. Exit Setup?" confirmation, so the user is + // not nagged after deliberately choosing to uninstall and exit. + MsgBox('The existing OpenVINO Model Server installation has been removed.' + #13#10#13#10 + + 'Setup will now close. Run it again to install a fresh copy.', + mbInformation, MB_OK); + SuppressCancelConfirm := True; + WizardForm.Close; + Result := False; + exit; + end; + + // RbRepair.Checked (default): proceed with repair/upgrade as normal. + Result := True; + end; +end; + +procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean); +begin + // After the "Uninstall existing, then exit" path triggers WizardForm.Close, + // skip the "Setup is not complete" confirmation prompt. + if SuppressCancelConfirm then + Confirm := False; +end; + +function InitializeUninstall(): Boolean; +var + DataDir: String; + KeepEverything: Integer; + RemoveModelsToo: Integer; +begin + Result := True; + DataDir := ExpandConstant('{localappdata}\OVMS'); + DataModeChoice := 'PreserveAll'; + + if UninstallSilent() then + begin + exit; + end; + + KeepEverything := MsgBox( + 'Keep your downloaded models and data under:' + #13#10 + + DataDir + #13#10#13#10 + + 'Yes = keep everything (models, settings, and logs)' + #13#10 + + 'No = choose what to remove', + mbConfirmation, MB_YESNO); + + if KeepEverything = IDYES then + begin + DataModeChoice := 'PreserveAll'; + exit; + end; + + RemoveModelsToo := MsgBox( + 'Also delete your downloaded MODELS?' + #13#10#13#10 + + 'Yes = remove everything, including models' + #13#10 + + 'No = keep models, but remove settings and logs', + mbConfirmation, MB_YESNO); + + if RemoveModelsToo = IDYES then + begin + DataModeChoice := 'RemoveAll'; + end + else + begin + DataModeChoice := 'RemoveSettingsKeepModels'; + end; +end; diff --git a/packaging/windows/installer/README.md b/packaging/windows/installer/README.md new file mode 100644 index 0000000000..8caadaa96f --- /dev/null +++ b/packaging/windows/installer/README.md @@ -0,0 +1,29 @@ +# OVMS Windows Installer + +The installer is built with Inno Setup from `OVMSInstaller.iss`. + +It expects the OVMS portable package to already exist at: + +```text +dist/windows/ovms +``` + +The installer adds: + +- OVMS files under `C:\Program Files\OVMS`. +- Data folders under `C:\ProgramData\OVMS`. +- Default settings and install marker files. +- Start Menu shortcuts. +- Optional PATH entry. +- Optional start-at-login entry for the tray app. +- Optional Windows Service registration. +- A standard Apps & Features uninstaller. + +The installer must be fully offline once built. It should not download Python, +.NET, OpenVINO, GenAI, or model-server dependencies during installation. The +OVMS package and self-contained tray app must already be present in the +installer payload. + +The uninstaller stops managed OVMS processes, removes optional service/startup +configuration, removes installer-created PATH entries, and removes installed +program files. Data under `C:\ProgramData\OVMS` is preserved by default. diff --git a/packaging/windows/installer/assets/ovms-small.bmp b/packaging/windows/installer/assets/ovms-small.bmp new file mode 100644 index 0000000000000000000000000000000000000000..134821c273cd2563f8ef42f098f793da90c3560b GIT binary patch literal 38566 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 literal 0 HcmV?d00001 diff --git a/packaging/windows/installer/assets/ovms-welcome.bmp b/packaging/windows/installer/assets/ovms-welcome.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b32e7c5dd10f75a513875429849532754311d602 GIT binary patch literal 618006 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�~C@bnhdr|W&r>n*uau3oYTW?u+ZVpnMtyj)&X1DyE2>W(nW`#eo<;@{m9J5+z zA-qgH*=DSw9P>>z822uHJF$#g*$L5-V=J6td5UsDT?K6y!L%vM zolpy8pe?ACI2XS&*rb`8pqSDuioJQj*`mDrZ4*t`oh{Pm2X8PC(N=0fcfvBpZLR6L zLzfx+f_iPPYuv&en?*4WuJ|+`G#uadCx_=;mK*sL39F6)poNXPg@S*_Aj7@cDsbm zi^P?4W#9TghWck5jJX+45hv-mP;UeHz(I*QrCd{KR`ZYiu>n6YzDVSW-1pre%|Ir? zBvEplK_9?zdxo=qepDQ0Y!%3jar!+Wo@f)R*Fu{;_+ud@%IIFqD`nl z_e49iTU;yS_ImPI!D7|sGb7nN1@<$g+thA~HGFslyC>h0?pZURXd{l2+WH%bh4xXq z$7=JO9qan}rGkU;6mbUDZuQb5k-otmS9?2lLOs@~S8Ui-X%FPVBdJHb5_;ba*oTY~ zz#kWvCGAt*R#Z&Pg%+n=0eJ zn(}sSE#*7rzAX*$Kq#*+{s*8vO|}-DQXk;+{^;fpCvCGpV{$Q zAUTc$EXSqG-bIj0qr+^6!3NGEH`MuvGiR&<>O>nXvIM7yO&ryNUr~Qa4ppa z*M;^_?LqgFamV^JmDIE*%?r!@%*dSMCfau9u;py3tvTcFxv*s1vtYBIi&&;PcWn** zntHRUR&8eAk%MzhOJ?8s^NE}RkELs&;PtDV8APuL6L7Q|RA6_VM4#XcX06c)Z&+(1tjhM=09l)Bz8pjo zVM+Glu_w`?&aQ7)i5o1toe^#09W2MB6);B;j37&?RS@F{+t6jiHxLbVMm0=r<+PXu z%hgWMK2va`U4U1xD0r345$N7xu7CCzTt9(cSCeE@zFW0Px0CLe0z*n3>rNx%&L_ei z)H5UCnoSw^Cy{Qmq(;?d1JOMf7E9EafYXr2bQr~23f{}hJLz6)=4KquoNLwigQx_Y zjJJXl@FUs*xYBJE)<8OQa9oO3@Kwigp)y;1T2VcO8z8HZnrfgAaWUv|Z(hZcPQQdC z&X>>gRIFo~S=P0j0;^J8@1lDSKdP}^;GH1juBC4+NFB%DLE}5o#(A)8a+xf1&@P(3 zD5crKQU@zhj+&TRR@Uq!8mTeYhE?v2e{{sv&m>wPL!D0qnjidPspQ?Ir{V$Kd z0ItFB_wGF|uIb6|tHG0JJ=f3EEpNU1hp^uVG^S zUmkz{r;q;_6o2>LV>F>1fGgd0(%r(1JHVN6zZ__H-VG~W!j0I%4Yaq^J5{^T&Wu~d z^Sx%SA1!bBern!b**A%nb|>cH&u>(4qn&``3Y1r$YTl|uwAqUBD@`}=MS5)>5j!$& zcyZ*vP_;p;dfVe9m*WE2XRg!MX1%p{C9vi+q?z}kaM5!-pzd$2V?u}}!DAO?I^nIQ zfHi{PQ*Hv8K71PNEl#c>%AAaL%1nW_(`N7n#QH2#W=(9i)M&bHi!yqa!l=~HWdx

_H9SvTnxbc1j0Mw}uJG!%ofLNAD` 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 literal 0 HcmV?d00001 diff --git a/packaging/windows/installer/build_installer.ps1 b/packaging/windows/installer/build_installer.ps1 new file mode 100644 index 0000000000..868738a173 --- /dev/null +++ b/packaging/windows/installer/build_installer.ps1 @@ -0,0 +1,59 @@ +param( + [string]$Configuration = "Release", + [string]$SourceRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..")).Path, + [string]$OvmsSourceDir = "", + [string]$OutputDir = "", + [string]$InnoSetupPath = "" +) + +$ErrorActionPreference = "Stop" + +$ovmsDir = if ($OvmsSourceDir) { (Resolve-Path -LiteralPath $OvmsSourceDir).Path } else { Join-Path $SourceRoot "dist\windows\ovms" } +$managerPublishDir = Join-Path $SourceRoot "packaging\windows\manager\artifacts\publish" +$installerScript = Join-Path $PSScriptRoot "OVMSInstaller.iss" +$outputDir = if ($OutputDir) { $OutputDir } else { Join-Path $SourceRoot "dist\windows" } + +if (-not (Test-Path (Join-Path $ovmsDir "ovms.exe"))) { + throw "Missing OVMS package at $ovmsDir. Run windows_create_package.bat first." +} + +if (-not (Test-Path (Join-Path $managerPublishDir "OVMS.Manager.exe"))) { + & (Join-Path $SourceRoot "packaging\windows\manager\build_manager.ps1") -Configuration $Configuration +} + +if (-not $InnoSetupPath) { + $cmd = Get-Command ISCC.exe -ErrorAction SilentlyContinue + if ($cmd) { + $InnoSetupPath = $cmd.Source + } else { + $candidates = @( + "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe", + "$env:ProgramFiles\Inno Setup 6\ISCC.exe" + ) + foreach ($candidate in $candidates) { + if (Test-Path $candidate) { + $InnoSetupPath = $candidate + break + } + } + } +} + +if (-not $InnoSetupPath -or -not (Test-Path $InnoSetupPath)) { + throw "Inno Setup compiler ISCC.exe was not found. Install Inno Setup 6 or pass -InnoSetupPath." +} + +New-Item -ItemType Directory -Force -Path $outputDir | Out-Null + +& $InnoSetupPath ` + "/DSourceRoot=$SourceRoot" ` + "/DOvmsSourceDir=$ovmsDir" ` + "/DManagerPublishDir=$managerPublishDir" ` + "/DOutputDir=$outputDir" ` + $installerScript + +if ($LASTEXITCODE -ne 0) { + throw "Inno Setup failed with exit code $LASTEXITCODE." +} + +Write-Host "[INFO] Installer created at $(Join-Path $outputDir 'OVMS-Setup.exe')" diff --git a/packaging/windows/manager/.gitignore b/packaging/windows/manager/.gitignore new file mode 100644 index 0000000000..b8c89995ae --- /dev/null +++ b/packaging/windows/manager/.gitignore @@ -0,0 +1,3 @@ +artifacts/ +src/**/bin/ +src/**/obj/ diff --git a/packaging/windows/manager/build_manager.ps1 b/packaging/windows/manager/build_manager.ps1 new file mode 100644 index 0000000000..2b145d5351 --- /dev/null +++ b/packaging/windows/manager/build_manager.ps1 @@ -0,0 +1,22 @@ +param( + [string]$Configuration = "Release" +) + +$ErrorActionPreference = "Stop" + +$project = Join-Path $PSScriptRoot "src\OVMS.Manager\OVMS.Manager.csproj" +$output = Join-Path $PSScriptRoot "artifacts\publish" + +dotnet publish $project ` + -c $Configuration ` + -r win-x64 ` + --self-contained true ` + -p:PublishSingleFile=true ` + -p:IncludeNativeLibrariesForSelfExtract=true ` + -p:EnableCompressionInSingleFile=true ` + -o $output +if ($LASTEXITCODE -ne 0) { + throw "dotnet publish failed." +} + +Write-Host "[INFO] Manager published to $output" diff --git a/packaging/windows/manager/src/OVMS.Manager/Assets/ovms-manager.ico b/packaging/windows/manager/src/OVMS.Manager/Assets/ovms-manager.ico new file mode 100644 index 0000000000000000000000000000000000000000..c31506f868644a68c74e6e33dc185f84dd2b5868 GIT binary patch literal 270398 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 + + WinExe + net8.0-windows + true + enable + enable + OVMS.Manager + OVMS.Manager + Assets\ovms-manager.ico + + diff --git a/packaging/windows/manager/src/OVMS.Manager/Program.cs b/packaging/windows/manager/src/OVMS.Manager/Program.cs new file mode 100644 index 0000000000..e650726200 --- /dev/null +++ b/packaging/windows/manager/src/OVMS.Manager/Program.cs @@ -0,0 +1,212 @@ +using System.Diagnostics; +using System.Drawing; +using System.Text.Json; +using System.Windows.Forms; + +namespace OVMS.Manager; + +internal static class Program +{ + [STAThread] + private static void Main() + { + ApplicationConfiguration.Initialize(); + using var app = new TrayApplicationContext(); + Application.Run(app); + } +} + +internal sealed class TrayApplicationContext : ApplicationContext +{ + private readonly NotifyIcon notifyIcon; + private readonly ToolStripMenuItem startItem; + private readonly ToolStripMenuItem stopItem; + private readonly OvmsController controller; + + public TrayApplicationContext() + { + controller = new OvmsController(); + + startItem = new ToolStripMenuItem("Start Server", null, (_, _) => RunAction("Start Server", controller.Start)); + stopItem = new ToolStripMenuItem("Stop Server", null, (_, _) => RunAction("Stop Server", controller.Stop)); + + var openItem = new ToolStripMenuItem("Open OVMS Manager", null, (_, _) => OpenManager()); + var menu = new ContextMenuStrip(); + menu.Items.Add(openItem); + menu.Items.Add(startItem); + menu.Items.Add(stopItem); + + notifyIcon = new NotifyIcon + { + Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath) ?? SystemIcons.Application, + Text = "OpenVINO Model Server", + ContextMenuStrip = menu, + Visible = true + }; + notifyIcon.MouseClick += (_, args) => + { + if (args.Button == MouseButtons.Left) + { + OpenManager(); + } + }; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + notifyIcon.Visible = false; + notifyIcon.Dispose(); + controller.Dispose(); + } + base.Dispose(disposing); + } + + private void OpenManager() + { + var status = controller.GetStatus(); + MessageBox.Show(status, "OpenVINO Model Server", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void RunAction(string title, Action action) + { + try + { + startItem.Enabled = false; + stopItem.Enabled = false; + action(); + notifyIcon.ShowBalloonTip(3000, "OpenVINO Model Server", $"{title} completed.", ToolTipIcon.Info); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, title, MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + startItem.Enabled = true; + stopItem.Enabled = true; + } + } +} + +internal sealed class OvmsController : IDisposable +{ + private readonly string dataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "OVMS"); + private readonly string appDir = AppContext.BaseDirectory; + + public string GetStatus() + { + var settings = LoadSettings(); + var runtimePath = Path.Combine(dataDir, "runtime.json"); + var status = "Stopped"; + + if (File.Exists(runtimePath)) + { + try + { + using var doc = JsonDocument.Parse(File.ReadAllText(runtimePath)); + if (doc.RootElement.TryGetProperty("pid", out var pidElement) && pidElement.TryGetInt32(out var pid)) + { + var process = Process.GetProcessById(pid); + if (string.Equals(process.ProcessName, "ovms", StringComparison.OrdinalIgnoreCase)) + { + status = $"Running, pid {pid}"; + } + } + } + catch + { + status = "Runtime state is stale or unreadable"; + } + } + + return string.Join(Environment.NewLine, new[] + { + $"Status: {status}", + $"REST: http://{settings.BindAddress}:{settings.RestPort}", + $"Install: {settings.InstallDir}", + $"Config: {settings.ConfigPath}", + $"Logs: {settings.LogPath}" + }); + } + + public void Start() + { + RunPowerShell("start-ovms.ps1"); + } + + public void Stop() + { + RunPowerShell("stop-ovms.ps1"); + } + + public void Dispose() + { + } + + private OvmsSettings LoadSettings() + { + var settingsPath = Path.Combine(dataDir, "settings.json"); + if (!File.Exists(settingsPath)) + { + return new OvmsSettings + { + InstallDir = appDir.TrimEnd(Path.DirectorySeparatorChar), + DataDir = dataDir, + ConfigPath = Path.Combine(dataDir, "models", "config.json"), + LogPath = Path.Combine(dataDir, "logs", "ovms_server.log"), + BindAddress = "127.0.0.1", + RestPort = 8000, + GrpcPort = 0 + }; + } + + var settings = JsonSerializer.Deserialize(File.ReadAllText(settingsPath), new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }); + + return settings ?? throw new InvalidOperationException($"Could not parse settings: {settingsPath}"); + } + + private void RunPowerShell(string scriptName) + { + var scriptPath = Path.Combine(appDir, "scripts", scriptName); + if (!File.Exists(scriptPath)) + { + throw new FileNotFoundException("Missing control script.", scriptPath); + } + + var startInfo = new ProcessStartInfo + { + FileName = "powershell.exe", + Arguments = $"-NoProfile -ExecutionPolicy Bypass -File \"{scriptPath}\" -DataDir \"{dataDir}\"", + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true + }; + + using var process = Process.Start(startInfo) ?? throw new InvalidOperationException("Failed to start PowerShell."); + var stdout = process.StandardOutput.ReadToEnd(); + var stderr = process.StandardError.ReadToEnd(); + process.WaitForExit(); + + if (process.ExitCode != 0) + { + throw new InvalidOperationException(string.IsNullOrWhiteSpace(stderr) ? stdout : stderr); + } + } +} + +internal sealed class OvmsSettings +{ + public string InstallDir { get; set; } = ""; + public string DataDir { get; set; } = ""; + public string ConfigPath { get; set; } = ""; + public string LogPath { get; set; } = ""; + public string BindAddress { get; set; } = "127.0.0.1"; + public int RestPort { get; set; } = 8000; + public int GrpcPort { get; set; } = 9000; +} diff --git a/packaging/windows/scripts/configure-ovms.ps1 b/packaging/windows/scripts/configure-ovms.ps1 new file mode 100644 index 0000000000..b12f7305d6 --- /dev/null +++ b/packaging/windows/scripts/configure-ovms.ps1 @@ -0,0 +1,75 @@ +param( + [Parameter(Mandatory = $true)][string]$InstallDir, + [Parameter(Mandatory = $true)][string]$DataDir, + [string]$PackageVariant = "python_on", + [int]$RestPort = 8000, + [int]$GrpcPort = 0, + [string]$BindAddress = "127.0.0.1", + [string]$LogLevel = "INFO" +) + +$ErrorActionPreference = "Stop" + +$modelsDir = Join-Path $DataDir "models" +$logsDir = Join-Path $DataDir "logs" +$configPath = Join-Path $modelsDir "config.json" +$settingsPath = Join-Path $DataDir "settings.json" +$installMarkerPath = Join-Path $DataDir "install.json" +$logPath = Join-Path $logsDir "ovms_server.log" +$utf8NoBom = New-Object System.Text.UTF8Encoding($false) + +New-Item -ItemType Directory -Force -Path $DataDir, $modelsDir, $logsDir, (Join-Path $DataDir "packages"), (Join-Path $DataDir "downloads"), (Join-Path $DataDir "diagnostics") | Out-Null + +if (-not (Test-Path $configPath)) { + [System.IO.File]::WriteAllText($configPath, '{"model_config_list":[]}', $utf8NoBom) +} + +$settings = [ordered]@{ + installDir = $InstallDir + dataDir = $DataDir + modelRepositoryPath = $modelsDir + configPath = $configPath + logPath = $logPath + restPort = $RestPort + grpcPort = $GrpcPort + bindAddress = $BindAddress + logLevel = $LogLevel + runMode = "user-login" + startAtLogin = $true + showTrayIcon = $true + serviceAutoStart = $false + packageVariant = $PackageVariant +} + +$tmpSettings = "$settingsPath.tmp" +[System.IO.File]::WriteAllText($tmpSettings, ($settings | ConvertTo-Json -Depth 10), $utf8NoBom) +Move-Item -Force -Path $tmpSettings -Destination $settingsPath + +$version = "unknown" +$ovmsExe = Join-Path $InstallDir "ovms.exe" +if (Test-Path $ovmsExe) { + try { + $versionOutput = & $ovmsExe --version 2>$null + if ($versionOutput) { + $version = ($versionOutput | Select-Object -First 1).ToString() + } + } catch { + $version = "unknown" + } +} + +$installMarker = [ordered]@{ + productName = "OpenVINO Model Server" + installDir = $InstallDir + dataDir = $DataDir + version = $version + packageVariant = $PackageVariant + installedAtUtc = (Get-Date).ToUniversalTime().ToString("o") + installerVersion = "1.0.0" +} + +$tmpInstall = "$installMarkerPath.tmp" +[System.IO.File]::WriteAllText($tmpInstall, ($installMarker | ConvertTo-Json -Depth 10), $utf8NoBom) +Move-Item -Force -Path $tmpInstall -Destination $installMarkerPath + +Write-Host "[INFO] OVMS configured at $DataDir" diff --git a/packaging/windows/scripts/install-service.ps1 b/packaging/windows/scripts/install-service.ps1 new file mode 100644 index 0000000000..74985ac9d4 --- /dev/null +++ b/packaging/windows/scripts/install-service.ps1 @@ -0,0 +1,46 @@ +param( + [Parameter(Mandatory = $true)][string]$InstallDir, + [Parameter(Mandatory = $true)][string]$DataDir +) + +$ErrorActionPreference = "Stop" + +$settingsPath = Join-Path $DataDir "settings.json" +if (-not (Test-Path $settingsPath)) { + throw "Settings file not found: $settingsPath" +} + +$settings = Get-Content $settingsPath -Raw | ConvertFrom-Json +$ovmsExe = Join-Path $InstallDir "ovms.exe" +if (-not (Test-Path $ovmsExe)) { + throw "ovms.exe not found: $ovmsExe" +} + +. (Join-Path $PSScriptRoot "ovms-env.ps1") -InstallDir $InstallDir -PersistMachine + +$binPath = "`"$ovmsExe`" --rest_port $($settings.restPort) --rest_bind_address `"$($settings.bindAddress)`" --config_path `"$($settings.configPath)`" --log_level $($settings.logLevel) --log_path `"$($settings.logPath)`"" +if ($settings.grpcPort -and [int]$settings.grpcPort -gt 0) { + $binPath += " --port $($settings.grpcPort)" +} + +$existing = Get-Service ovms -ErrorAction SilentlyContinue +if ($existing) { + & sc.exe config ovms binPath= $binPath DisplayName= "OpenVINO Model Server" | Out-Host +} else { + & sc.exe create ovms binPath= $binPath DisplayName= "OpenVINO Model Server" start= demand | Out-Host +} +if ($LASTEXITCODE -ne 0) { + throw "Failed to create or update ovms service." +} + +try { + & $ovmsExe install | Out-Host +} catch { + Write-Warning "ovms.exe install returned an error: $_" +} + +$settings.runMode = "service" +$utf8NoBom = New-Object System.Text.UTF8Encoding($false) +[System.IO.File]::WriteAllText($settingsPath, ($settings | ConvertTo-Json -Depth 10), $utf8NoBom) + +Write-Host "[INFO] OVMS service installed." diff --git a/packaging/windows/scripts/ovms-env.ps1 b/packaging/windows/scripts/ovms-env.ps1 new file mode 100644 index 0000000000..561f547cc6 --- /dev/null +++ b/packaging/windows/scripts/ovms-env.ps1 @@ -0,0 +1,33 @@ +param( + [Parameter(Mandatory = $true)][string]$InstallDir, + [switch]$PersistMachine +) + +$ErrorActionPreference = "Stop" + +$installDirFull = (Resolve-Path -LiteralPath $InstallDir).Path.TrimEnd("\") +$pythonHome = Join-Path $installDirFull "python" +$pythonScripts = Join-Path $pythonHome "Scripts" +$espeakData = Join-Path $installDirFull "espeak-ng-data" + +$env:OVMS_DIR = $installDirFull +if (Test-Path -LiteralPath $pythonHome) { + $env:PYTHONHOME = $pythonHome + $env:PATH = (($installDirFull, $pythonHome, $pythonScripts, $env:PATH) -join ";") +} else { + $env:PATH = (($installDirFull, $env:PATH) -join ";") +} + +if (Test-Path -LiteralPath $espeakData) { + $env:ESPEAK_DATA_PATH = $espeakData +} + +if ($PersistMachine) { + [Environment]::SetEnvironmentVariable("OVMS_DIR", $installDirFull, "Machine") + if (Test-Path -LiteralPath $pythonHome) { + [Environment]::SetEnvironmentVariable("PYTHONHOME", $pythonHome, "Machine") + } + if (Test-Path -LiteralPath $espeakData) { + [Environment]::SetEnvironmentVariable("ESPEAK_DATA_PATH", $espeakData, "Machine") + } +} diff --git a/packaging/windows/scripts/repair-package.ps1 b/packaging/windows/scripts/repair-package.ps1 new file mode 100644 index 0000000000..66a36f13ad --- /dev/null +++ b/packaging/windows/scripts/repair-package.ps1 @@ -0,0 +1,91 @@ +param( + [Parameter(Mandatory = $true)][string]$InstallDir, + [Parameter(Mandatory = $true)][string]$DataDir, + [string]$PackageSource = "" +) + +$ErrorActionPreference = "Stop" + +$packageCacheDir = Join-Path $DataDir "packages\source" + +$resolvedSource = "" +if ($PackageSource -and (Test-Path (Join-Path $PackageSource "ovms.exe"))) { + $resolvedSource = $PackageSource +} elseif (Test-Path (Join-Path $packageCacheDir "ovms.exe")) { + $resolvedSource = $packageCacheDir +} + +if (-not $resolvedSource) { + Write-Warning "No package source available to restore missing files from. Falling back to self-verify only." + Write-Warning "Repair cannot restore missing files without a valid package source (checked: '$PackageSource', '$packageCacheDir')." +} + +$required = @( + "ovms.exe", + "setupvars.bat", + "setupvars.ps1", + "install_ovms_service.bat" +) + +$repairedFiles = @() +foreach ($file in $required) { + $destPath = Join-Path $InstallDir $file + if (-not (Test-Path $destPath)) { + if ($resolvedSource) { + $srcPath = Join-Path $resolvedSource $file + if (Test-Path $srcPath) { + $destDir = Split-Path -Parent $destPath + if (-not (Test-Path $destDir)) { + New-Item -ItemType Directory -Force -Path $destDir | Out-Null + } + Copy-Item -Path $srcPath -Destination $destPath -Force + $repairedFiles += $file + Write-Host "[INFO] Restored missing file: $file" + } else { + Write-Warning "Missing file '$file' could not be restored: not found in package source." + } + } else { + Write-Warning "Missing file '$file' could not be restored: no package source available." + } + } +} + +$genAiInstalled = (Test-Path (Join-Path $InstallDir "openvino_genai.dll")) -and (Test-Path (Join-Path $InstallDir "openvino_tokenizers.dll")) +$pythonInstalled = Test-Path (Join-Path $InstallDir "python\python.exe") + +Write-Host "[INFO] GenAI support: $(if ($genAiInstalled) { 'Installed' } else { 'Missing' })" +Write-Host "[INFO] Python support: $(if ($pythonInstalled) { 'Installed' } else { 'Missing' })" + +$ovmsExe = Join-Path $InstallDir "ovms.exe" +if (-not (Test-Path $ovmsExe)) { + throw "ovms.exe is missing from $InstallDir and could not be restored. Repair cannot continue." +} + +. (Join-Path $PSScriptRoot "ovms-env.ps1") -InstallDir $InstallDir + +try { + $versionOutput = & $ovmsExe --version 2>$null + if ($LASTEXITCODE -ne 0) { + throw "ovms.exe --version exited with code $LASTEXITCODE." + } +} catch { + throw "ovms.exe --version failed during repair: $_" +} + +$settingsPath = Join-Path $DataDir "settings.json" +$configPath = Join-Path $DataDir "models\config.json" + +if ((-not (Test-Path $settingsPath)) -or (-not (Test-Path $configPath))) { + Write-Host "[INFO] Regenerating missing configuration via configure-ovms.ps1." + & (Join-Path $PSScriptRoot "configure-ovms.ps1") -InstallDir $InstallDir -DataDir $DataDir +} + +Write-Host "" +if ($repairedFiles.Count -gt 0) { + Write-Host "[INFO] Repair restored $($repairedFiles.Count) file(s): $($repairedFiles -join ', ')" +} else { + Write-Host "[INFO] No required files were missing; no file repair was needed." +} +Write-Host "[INFO] GenAI support: $(if ($genAiInstalled) { 'Installed' } else { 'Missing' })" +Write-Host "[INFO] Python support: $(if ($pythonInstalled) { 'Installed' } else { 'Missing' })" +Write-Host "[INFO] Repair complete." diff --git a/packaging/windows/scripts/set-path.ps1 b/packaging/windows/scripts/set-path.ps1 new file mode 100644 index 0000000000..eae7760340 --- /dev/null +++ b/packaging/windows/scripts/set-path.ps1 @@ -0,0 +1,44 @@ +param( + [Parameter(Mandatory = $true)][string]$InstallDir, + [ValidateSet("Add", "Remove")][string]$Action +) + +$ErrorActionPreference = "Stop" + +$installDirFull = (Resolve-Path -LiteralPath $InstallDir).Path.TrimEnd("\") +$pythonHome = Join-Path $installDirFull "python" +$pythonScripts = Join-Path $pythonHome "Scripts" +$required = @($installDirFull) +if (Test-Path -LiteralPath $pythonHome) { + $required += $pythonHome + $required += $pythonScripts +} + +$target = "User" +$current = [Environment]::GetEnvironmentVariable("Path", $target) +$parts = @() +if (-not [string]::IsNullOrWhiteSpace($current)) { + $parts = @($current -split ";" | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) +} + +if ($Action -eq "Add") { + foreach ($req in $required) { + $exists = $false + foreach ($part in $parts) { + if ($part.TrimEnd("\") -ieq $req.TrimEnd("\")) { + $exists = $true + break + } + } + if (-not $exists) { + $parts = @($req) + $parts + } + } +} else { + $parts = @($parts | Where-Object { + $candidate = $_.TrimEnd("\") + -not ($required | Where-Object { $_.TrimEnd("\") -ieq $candidate }) + }) +} + +[Environment]::SetEnvironmentVariable("Path", ($parts -join ";"), $target) diff --git a/packaging/windows/scripts/start-ovms.ps1 b/packaging/windows/scripts/start-ovms.ps1 new file mode 100644 index 0000000000..9a8df6770e --- /dev/null +++ b/packaging/windows/scripts/start-ovms.ps1 @@ -0,0 +1,86 @@ +param( + [string]$DataDir = "$env:LOCALAPPDATA\OVMS" +) + +$ErrorActionPreference = "Stop" + +$settingsPath = Join-Path $DataDir "settings.json" +if (-not (Test-Path $settingsPath)) { + throw "Settings file not found: $settingsPath" +} + +$settings = Get-Content $settingsPath -Raw | ConvertFrom-Json +$runtimePath = Join-Path $DataDir "runtime.json" +$utf8NoBom = New-Object System.Text.UTF8Encoding($false) + +$service = Get-Service ovms -ErrorAction SilentlyContinue +if ($service -and $settings.runMode -eq "service") { + if ($service.Status -ne "Running") { + Start-Service ovms + } + Write-Host "[INFO] OVMS service is running." + exit 0 +} + +$restPort = [int]$settings.restPort +$grpcPort = [int]$settings.grpcPort +$ports = @($restPort, $grpcPort) | Where-Object { $_ -gt 0 } | Select-Object -Unique +foreach ($port in $ports) { + $listeners = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue + foreach ($listener in $listeners) { + if ($listener.OwningProcess -ne $PID) { + throw "Port $port is already in use by process id $($listener.OwningProcess)." + } + } +} + +if (Test-Path $runtimePath) { + try { + $runtime = Get-Content $runtimePath -Raw | ConvertFrom-Json + if ($runtime.pid) { + $existing = Get-Process -Id ([int]$runtime.pid) -ErrorAction SilentlyContinue + if ($existing -and $existing.ProcessName -ieq "ovms") { + Write-Host "[INFO] OVMS is already running with pid $($runtime.pid)." + exit 0 + } + } + } catch { + Write-Warning "Ignoring invalid runtime state: $runtimePath" + } +} + +$ovmsExe = Join-Path $settings.installDir "ovms.exe" +if (-not (Test-Path $ovmsExe)) { + throw "ovms.exe not found: $ovmsExe" +} + +. (Join-Path $PSScriptRoot "ovms-env.ps1") -InstallDir $settings.installDir + +$args = @( + "--rest_port", $settings.restPort, + "--rest_bind_address", $settings.bindAddress, + "--config_path", $settings.configPath, + "--log_level", $settings.logLevel, + "--log_path", $settings.logPath +) + +if ($settings.grpcPort -and [int]$settings.grpcPort -gt 0) { + $args += @("--port", $settings.grpcPort) +} + +$process = Start-Process -FilePath $ovmsExe -ArgumentList $args -WindowStyle Hidden -PassThru + +$runtimeState = [ordered]@{ + owner = "manager-process" + pid = $process.Id + serviceName = "ovms" + restPort = [int]$settings.restPort + grpcPort = [int]$settings.grpcPort + startedAtUtc = (Get-Date).ToUniversalTime().ToString("o") +} + +$tmpRuntime = "$runtimePath.tmp" +[System.IO.File]::WriteAllText($tmpRuntime, ($runtimeState | ConvertTo-Json -Depth 10), $utf8NoBom) +Move-Item -Force -Path $tmpRuntime -Destination $runtimePath + +Write-Host "[INFO] Started OVMS with pid $($process.Id)." diff --git a/packaging/windows/scripts/stop-ovms.ps1 b/packaging/windows/scripts/stop-ovms.ps1 new file mode 100644 index 0000000000..061fa9940b --- /dev/null +++ b/packaging/windows/scripts/stop-ovms.ps1 @@ -0,0 +1,38 @@ +param( + [string]$DataDir = "$env:LOCALAPPDATA\OVMS" +) + +$ErrorActionPreference = "Stop" + +$settingsPath = Join-Path $DataDir "settings.json" +$runtimePath = Join-Path $DataDir "runtime.json" + +if (Test-Path $settingsPath) { + $settings = Get-Content $settingsPath -Raw | ConvertFrom-Json + if ($settings.runMode -eq "service") { + $service = Get-Service ovms -ErrorAction SilentlyContinue + if ($service -and $service.Status -ne "Stopped") { + Stop-Service ovms -ErrorAction Stop + Write-Host "[INFO] Stopped OVMS service." + exit 0 + } + } +} + +if (Test-Path $runtimePath) { + try { + $runtime = Get-Content $runtimePath -Raw | ConvertFrom-Json + if ($runtime.pid) { + $process = Get-Process -Id ([int]$runtime.pid) -ErrorAction SilentlyContinue + if ($process -and $process.ProcessName -ieq "ovms") { + Stop-Process -Id $process.Id -Force + Write-Host "[INFO] Stopped OVMS process $($process.Id)." + } + } + } finally { + Remove-Item -Force -Path $runtimePath -ErrorAction SilentlyContinue + } +} else { + Write-Host "[INFO] No OVMS runtime state found." +} + diff --git a/packaging/windows/scripts/uninstall-ovms.ps1 b/packaging/windows/scripts/uninstall-ovms.ps1 new file mode 100644 index 0000000000..b051b0c2d4 --- /dev/null +++ b/packaging/windows/scripts/uninstall-ovms.ps1 @@ -0,0 +1,71 @@ +param( + [Parameter(Mandatory = $true)][string]$InstallDir, + [Parameter(Mandatory = $true)][string]$DataDir, + [ValidateSet("PreserveAll", "RemoveSettingsKeepModels", "RemoveAll")][string]$DataMode = "PreserveAll" +) + +$ErrorActionPreference = "Stop" + +Get-Process -Name "OVMS.Manager" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue + +$runtimePath = Join-Path $DataDir "runtime.json" +if (Test-Path $runtimePath) { + try { + $runtime = Get-Content $runtimePath -Raw | ConvertFrom-Json + if ($runtime.pid) { + $process = Get-Process -Id ([int]$runtime.pid) -ErrorAction SilentlyContinue + if ($process -and $process.ProcessName -ieq "ovms") { + Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue + } + } + } catch { + Write-Warning "Could not read runtime state: $_" + } + Remove-Item -Force -Path $runtimePath -ErrorAction SilentlyContinue +} + +& (Join-Path $PSScriptRoot "uninstall-service.ps1") +& (Join-Path $PSScriptRoot "set-path.ps1") -InstallDir $InstallDir -Action Remove +[Environment]::SetEnvironmentVariable("OVMS_DIR", $null, "User") +[Environment]::SetEnvironmentVariable("PYTHONHOME", $null, "User") +[Environment]::SetEnvironmentVariable("ESPEAK_DATA_PATH", $null, "User") + +Remove-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "OVMS Manager" -ErrorAction SilentlyContinue + +switch ($DataMode) { + "PreserveAll" { + # Keep everything under $DataDir. + } + "RemoveSettingsKeepModels" { + Remove-Item -Force -Path (Join-Path $DataDir "settings.json") -ErrorAction SilentlyContinue + Remove-Item -Force -Path (Join-Path $DataDir "install.json") -ErrorAction SilentlyContinue + Remove-Item -Force -Path (Join-Path $DataDir "runtime.json") -ErrorAction SilentlyContinue + + $logsDir = Join-Path $DataDir "logs" + if (Test-Path $logsDir) { + Remove-Item -LiteralPath $logsDir -Recurse -Force -ErrorAction SilentlyContinue + } + + $packagesDir = Join-Path $DataDir "packages" + if (Test-Path $packagesDir) { + Remove-Item -LiteralPath $packagesDir -Recurse -Force -ErrorAction SilentlyContinue + } + + $downloadsDir = Join-Path $DataDir "downloads" + if (Test-Path $downloadsDir) { + Remove-Item -LiteralPath $downloadsDir -Recurse -Force -ErrorAction SilentlyContinue + } + + $diagnosticsDir = Join-Path $DataDir "diagnostics" + if (Test-Path $diagnosticsDir) { + Remove-Item -LiteralPath $diagnosticsDir -Recurse -Force -ErrorAction SilentlyContinue + } + } + "RemoveAll" { + if (Test-Path $DataDir) { + Remove-Item -LiteralPath $DataDir -Recurse -Force + } + } +} + +Write-Host "[INFO] OVMS uninstall cleanup complete." diff --git a/packaging/windows/scripts/uninstall-service.ps1 b/packaging/windows/scripts/uninstall-service.ps1 new file mode 100644 index 0000000000..ed6f0b8c61 --- /dev/null +++ b/packaging/windows/scripts/uninstall-service.ps1 @@ -0,0 +1,13 @@ +$ErrorActionPreference = "Stop" + +$service = Get-Service ovms -ErrorAction SilentlyContinue +if ($service) { + if ($service.Status -ne "Stopped") { + Stop-Service ovms -ErrorAction SilentlyContinue + } + & sc.exe delete ovms | Out-Host + if ($LASTEXITCODE -ne 0) { + throw "Failed to delete ovms service." + } +} + diff --git a/packaging/windows/scripts/validate-install.ps1 b/packaging/windows/scripts/validate-install.ps1 new file mode 100644 index 0000000000..2e472905b9 --- /dev/null +++ b/packaging/windows/scripts/validate-install.ps1 @@ -0,0 +1,36 @@ +param( + [string]$InstallDir +) + +$ErrorActionPreference = "Stop" + +if (-not $InstallDir) { + $sourceRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..")).Path + $InstallDir = Join-Path $sourceRoot "dist\windows\ovms" +} + +$required = @( + "ovms.exe", + "setupvars.bat", + "setupvars.ps1", + "install_ovms_service.bat" +) + +$missing = @() +foreach ($file in $required) { + $path = Join-Path $InstallDir $file + if (-not (Test-Path $path)) { + $missing += $file + } +} + +if ($missing.Count -gt 0) { + throw "Missing required files in ${InstallDir}: $($missing -join ', ')" +} + +& (Join-Path $InstallDir "ovms.exe") --version +if ($LASTEXITCODE -ne 0) { + throw "ovms.exe --version failed." +} + +Write-Host "[INFO] Install folder validation passed: $InstallDir" diff --git a/packaging/windows/settings/settings.template.json b/packaging/windows/settings/settings.template.json new file mode 100644 index 0000000000..3f5734aa38 --- /dev/null +++ b/packaging/windows/settings/settings.template.json @@ -0,0 +1,16 @@ +{ + "installDir": "", + "dataDir": "", + "modelRepositoryPath": "", + "configPath": "", + "logPath": "", + "restPort": 8000, + "grpcPort": 0, + "bindAddress": "127.0.0.1", + "logLevel": "INFO", + "runMode": "user-login", + "startAtLogin": true, + "showTrayIcon": true, + "serviceAutoStart": false, + "packageVariant": "python_on" +}