From 2216a28ce3c4c7a3e264187a7fccfc6471f99992 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Sat, 8 Aug 2026 23:16:03 +0100 Subject: [PATCH] Refactor Windows installer update process to improve file handling and cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Updated the `swapUpdateStaging` macro to streamline the update process by swapping the old and new versions of Farm Control more efficiently. - Introduced a cleanup step to remove leftover `.old` directories from previous updates, enhancing the installer’s reliability. - Improved logging for better visibility during the update and removal processes, ensuring users are informed of actions taken. --- packaging/windows/installer.nsh | 115 ++++++++++++-------------------- 1 file changed, 42 insertions(+), 73 deletions(-) diff --git a/packaging/windows/installer.nsh b/packaging/windows/installer.nsh index 5dc1415..ddd97de 100644 --- a/packaging/windows/installer.nsh +++ b/packaging/windows/installer.nsh @@ -121,103 +121,72 @@ Var FinalInstDir ${EndIf} !macroend -; Returns 0 in $R9 when $R8 can be renamed (file unlocked / path free). -; _ID must be unique per insert so labels do not collide. -!macro tryRenameProbe _ID - StrCpy $R9 1 - ${IfNot} ${FileExists} "$R8" - StrCpy $R9 0 - Goto try_rename_probe_done_${_ID} - ${EndIf} - - ClearErrors - Rename "$R8" "$R8.updating" - ${If} ${Errors} - Goto try_rename_probe_done_${_ID} - ${EndIf} - - ; Leave the .updating name — the whole tree is about to be deleted. - StrCpy $R9 0 - try_rename_probe_done_${_ID}: -!macroend - -; Wait until the live install directory is released by the quitting app. -!macro waitForInstallDirWritable - !insertmacro progressStatus "Waiting for Farm Control to release install files..." - DetailPrint "Waiting for install directory to become writable..." - - StrCpy $R7 0 - wait_install_writable: - ; Probe the main binaries — rename fails while the process still holds them. - StrCpy $R8 "$FinalInstDir\bin\FarmControl.exe" - !insertmacro tryRenameProbe farmcontrol - ${If} $R9 != 0 - Goto wait_install_writable_retry - ${EndIf} - - StrCpy $R8 "$FinalInstDir\bin\launcher.exe" - !insertmacro tryRenameProbe launcher - ${If} $R9 != 0 - Goto wait_install_writable_retry - ${EndIf} - - ; Also probe creating a temp file in the install root. - ClearErrors - FileOpen $R8 "$FinalInstDir\.farmcontrol-write-probe" w - ${If} $R8 == "" - Goto wait_install_writable_retry - ${EndIf} - FileClose $R8 - Delete "$FinalInstDir\.farmcontrol-write-probe" - Goto wait_install_writable_done - - wait_install_writable_retry: - IntOp $R7 $R7 + 1 - ${If} $R7 < 60 - Sleep 500 - Goto wait_install_writable - ${EndIf} - !insertmacro progressFailure "Could not access the previous Farm Control installation." - Abort - - wait_install_writable_done: -!macroend - +; Swap order: Farm Control -> .old, Farm Control.new -> Farm Control, delete .old. !macro swapUpdateStaging !insertmacro progressPhase "Applying update" + !insertmacro progressStatus "Replacing Farm Control with the new version..." + DetailPrint "Replacing Farm Control with staged update..." + + ; Clear a leftover .old from a previous interrupted update. + ${If} ${FileExists} "$FinalInstDir.old" + DetailPrint "Removing leftover Farm Control.old..." + RMDir /r "$FinalInstDir.old" + ${EndIf} ${If} ${FileExists} "$FinalInstDir" - !insertmacro waitForInstallDirWritable - - !insertmacro progressStatus "Replacing Farm Control with the new version..." - DetailPrint "Replacing Farm Control with staged update..." + !insertmacro progressStatus "Waiting for Farm Control to release install files..." + DetailPrint "Waiting to rename install directory to Farm Control.old..." StrCpy $R7 0 - swap_delete_retry: - RMDir /r "$FinalInstDir" - ${If} ${FileExists} "$FinalInstDir" + swap_rename_old_retry: + ClearErrors + Rename "$FinalInstDir" "$FinalInstDir.old" + ${If} ${Errors} IntOp $R7 $R7 + 1 - ${If} $R7 < 20 + ${If} $R7 < 60 Sleep 500 - Goto swap_delete_retry + Goto swap_rename_old_retry ${EndIf} - !insertmacro progressFailure "Could not remove the previous Farm Control installation." + !insertmacro progressFailure "Could not move the previous Farm Control installation aside." Abort ${EndIf} ${EndIf} !insertmacro progressStatus "Activating new Farm Control installation..." - DetailPrint "Activating staged update..." + DetailPrint "Renaming Farm Control.new to Farm Control..." ClearErrors Rename "$INSTDIR" "$FinalInstDir" ${If} ${Errors} + ; Best-effort rollback so the previous install is usable again. + ${If} ${FileExists} "$FinalInstDir.old" + Rename "$FinalInstDir.old" "$FinalInstDir" + ${EndIf} !insertmacro progressFailure "Could not activate the new Farm Control installation." Abort ${EndIf} StrCpy $INSTDIR $FinalInstDir !insertmacro progressLog "installer:STATUS:Update files activated" + + ${If} ${FileExists} "$FinalInstDir.old" + !insertmacro progressStatus "Removing previous Farm Control installation..." + DetailPrint "Removing Farm Control.old..." + + StrCpy $R7 0 + swap_delete_old_retry: + RMDir /r "$FinalInstDir.old" + ${If} ${FileExists} "$FinalInstDir.old" + IntOp $R7 $R7 + 1 + ${If} $R7 < 20 + Sleep 500 + Goto swap_delete_old_retry + ${EndIf} + ; New version is already active; leftover .old is non-fatal. + DetailPrint "Warning: could not fully remove Farm Control.old" + !insertmacro progressLog "installer:STATUS:Warning: could not fully remove previous installation" + ${EndIf} + ${EndIf} !macroend !macro uninstallPreviousFarmControl