From 3d86ed73eb7d8cfec4193151b96670f42b45bdea Mon Sep 17 00:00:00 2001 From: maziggy Date: Wed, 10 Jun 2026 13:09:46 +0200 Subject: [PATCH] fix(installer): stop Bambuddy service before file copy on upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upgrading over a running install was failing with permission-denied errors on python.exe / .pyd / nssm.exe — the service held file locks during the [Files] copy phase. Add a PrepareToInstall hook that detects an existing install ({app}\bin\nssm.exe present) and stops the service before the overwrite. FileExists guards a no-op on first-time installs; the post-install [Run] step re-registers and starts the service fresh either way. --- installers/windows/bambuddy.iss | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/installers/windows/bambuddy.iss b/installers/windows/bambuddy.iss index 140d22c2a..40c763222 100644 --- a/installers/windows/bambuddy.iss +++ b/installers/windows/bambuddy.iss @@ -123,6 +123,40 @@ Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""Bamb Type: filesandordirs; Name: "{app}" [Code] + +// Stop the Bambuddy service BEFORE the [Files] section copies anything, +// so file locks on python.exe / .pyd / nssm.exe release in time for the +// overwrite. Without this, upgrading over a running install fails with +// "permission denied" on every file the service has open. +// +// On a fresh install {app}\bin\nssm.exe doesn't exist yet — FileExists +// guards that path so the hook is a no-op for first-time installers. +// The Sleep gives Windows a beat to finalize the python.exe unload +// before the [Files] step starts grabbing exclusive handles. +// +// The install-service.bat in [Run] does `nssm remove ... confirm` plus +// a fresh `nssm install`, so even if we leave the old service entry in +// place here, the post-install step re-registers it cleanly. +function PrepareToInstall(var NeedsRestart: Boolean): String; +var + ResultCode: Integer; + NssmPath: string; +begin + Result := ''; + NeedsRestart := False; + + NssmPath := ExpandConstant('{app}\bin\nssm.exe'); + if FileExists(NssmPath) then + begin + Log('Stopping Bambuddy service before file copy...'); + Exec(NssmPath, 'stop Bambuddy', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + // ResultCode 0 == stopped; non-zero is fine too (already stopped / + // service not registered). The lock we care about is python.exe's, + // and it's released the moment the process exits. + Sleep(1500); + end; +end; + // Pre-install check: refuse to install if port 8000 is already in use by // something other than a previous Bambuddy install. This catches the // "I have something else on 8000" case early instead of after install.