[Installer][Client] Fix review findings: throttle backups, NSIS old dir, portable messaging

This commit is contained in:
Lukas Brübach 2026-10-13 08:53:29 +02:00
parent bb5f17b876
commit f4e3d9acba
5 changed files with 255 additions and 49 deletions

View file

@ -15,6 +15,7 @@ Var ReinstallMode
Var AllowForceClose
Var GuardDir
Var OldUninstallString
Var OldInstallDir
Var DataBackupDir
Var StaleFindHandle
Var StaleFindName
@ -129,6 +130,9 @@ StrCpy $InstallLogPath "$TEMP\Cockatrice-installer.log"
; No backup has been taken yet; RestoreUserDataAfterUninstall must be a no-op
; until BackupUserDataBeforeUninstall sets this after actually copying something.
StrCpy $DataBackupDir ""
; No old install location resolved yet; Backup/Restore fall back to $INSTDIR
; when this is empty (the /R path where $INSTDIR already is the old dir).
StrCpy $OldInstallDir ""
; Start each run from a clean file so the log that gets sent back is the last
; run, not every past run glued together.
FileOpen $LogHandle "$InstallLogPath" w
@ -318,11 +322,14 @@ SetShellVarContext all
SetRegView 32
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString"
!insertmacro CockLog "uninstall (32-bit): '$R0 _?=$INSTDIR'"
; On the /R path the updater passes /D=<appDir>, so $INSTDIR already is the old
; install dir. Publish it for the backup/restore pair below.
StrCpy $OldInstallDir $INSTDIR
!insertmacro CockLog "uninstall (32-bit): '$R0 _?=$OldInstallDir'"
StrCmp $R0 "" done32
DetailPrint "Removing previous version (32-bit)..."
Call BackupUserDataBeforeUninstall
ExecWait '$R0 _?=$INSTDIR'
ExecWait '$R0 _?=$OldInstallDir'
Call RestoreUserDataAfterUninstall
done32:
@ -332,11 +339,12 @@ ${If} ${RunningX64}
SetRegView 64
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString"
!insertmacro CockLog "uninstall (64-bit): '$R0 _?=$INSTDIR'"
StrCpy $OldInstallDir $INSTDIR
!insertmacro CockLog "uninstall (64-bit): '$R0 _?=$OldInstallDir'"
StrCmp $R0 "" done64
DetailPrint "Removing previous version (64-bit)..."
Call BackupUserDataBeforeUninstall
ExecWait '$R0 _?=$INSTDIR'
ExecWait '$R0 _?=$OldInstallDir'
Call RestoreUserDataAfterUninstall
done64:
@ -358,59 +366,72 @@ FunctionEnd
; Non-portable data paths beyond loose decks are covered by the client's
; startup safety backup (warnAboutDataPathsInProgramDir).
Function BackupUserDataBeforeUninstall
; Always start from a clean slate: %TEMP% survives across installer runs, and a
; leftover backup must never be mistaken for this run's - a fresh install would
; otherwise resurrect ancient decks via RestoreUserDataAfterUninstall.
RMDir /r "$TEMP\CockatriceDataBackup"
StrCpy $DataBackupDir ""
${If} ${FileExists} "$INSTDIR\portable.dat"
${AndIf} ${FileExists} "$INSTDIR\data"
; $OldInstallDir is the directory being uninstalled: on the /R path it equals
; $INSTDIR (updater passes /D=<appDir>), on the interactive path componentsPagePre
; sets it from the registry InstallLocation via $GuardDir, because $INSTDIR is
; still the default there (directory page comes later).
${If} $OldInstallDir == ""
StrCpy $OldInstallDir $INSTDIR
${EndIf}
; Start from a clean slate only on the first backup of this run: %TEMP% survives
; across installer runs, so a stale backup must never be mistaken for this run's -
; but this function runs twice in sequence (32-bit then 64-bit), and an
; unconditional RMDir here would delete the first call's safety copy before the
; second uninstall runs.
${If} $DataBackupDir == ""
RMDir /r "$TEMP\CockatriceDataBackup"
${EndIf}
${If} ${FileExists} "$OldInstallDir\portable.dat"
${AndIf} ${FileExists} "$OldInstallDir\data"
StrCpy $DataBackupDir "$TEMP\CockatriceDataBackup"
!insertmacro CockLog "pre-uninstall backup: copying $INSTDIR\data (downloaded pics excluded)"
!insertmacro CockLog "pre-uninstall backup: copying $OldInstallDir\data (downloaded pics excluded)"
DetailPrint "Backing up portable user data before removing previous version..."
CreateDirectory "$DataBackupDir\data"
CopyFiles /SILENT "$INSTDIR\data\*.*" "$DataBackupDir\data\"
CopyFiles /SILENT "$OldInstallDir\data\*.*" "$DataBackupDir\data\"
; Downloaded pictures are large and re-downloadable, so drop them from the
; safety backup - but keep user-made custom pics (data\pics\CUSTOM).
RMDir /r "$DataBackupDir\data\pics"
${If} ${FileExists} "$INSTDIR\data\pics\CUSTOM"
${If} ${FileExists} "$OldInstallDir\data\pics\CUSTOM"
CreateDirectory "$DataBackupDir\data\pics\CUSTOM"
CopyFiles /SILENT "$INSTDIR\data\pics\CUSTOM\*.*" "$DataBackupDir\data\pics\CUSTOM\"
CopyFiles /SILENT "$OldInstallDir\data\pics\CUSTOM\*.*" "$DataBackupDir\data\pics\CUSTOM\"
${EndIf}
DetailPrint "Portable user data backup complete."
${EndIf}
${If} ${FileExists} "$INSTDIR\*.cod"
${OrIf} ${FileExists} "$INSTDIR\*.dec"
${If} ${FileExists} "$OldInstallDir\*.cod"
${OrIf} ${FileExists} "$OldInstallDir\*.dec"
${If} $DataBackupDir == ""
StrCpy $DataBackupDir "$TEMP\CockatriceDataBackup"
${EndIf}
!insertmacro CockLog "pre-uninstall backup: copying loose deck files"
DetailPrint "Backing up deck files stored in the install directory..."
CreateDirectory "$DataBackupDir\loose_decks"
CopyFiles /SILENT "$INSTDIR\*.cod" "$DataBackupDir\loose_decks\"
CopyFiles /SILENT "$INSTDIR\*.dec" "$DataBackupDir\loose_decks\"
CopyFiles /SILENT "$OldInstallDir\*.cod" "$DataBackupDir\loose_decks\"
CopyFiles /SILENT "$OldInstallDir\*.dec" "$DataBackupDir\loose_decks\"
${EndIf}
FunctionEnd
Function RestoreUserDataAfterUninstall
StrCmp $DataBackupDir "" done
${If} $OldInstallDir == ""
StrCpy $OldInstallDir $INSTDIR
${EndIf}
${If} ${FileExists} "$DataBackupDir\data"
${If} ${FileExists} "$INSTDIR\data"
${If} ${FileExists} "$OldInstallDir\data"
!insertmacro CockLog "post-uninstall restore: user data survived, backup kept"
DetailPrint "Previous user data survived the uninstall; backup kept at $DataBackupDir\data."
${Else}
!insertmacro CockLog "post-uninstall restore: restoring $INSTDIR\data"
CreateDirectory "$INSTDIR\data"
CopyFiles /SILENT "$DataBackupDir\data\*.*" "$INSTDIR\data\"
!insertmacro CockLog "post-uninstall restore: restoring $OldInstallDir\data"
CreateDirectory "$OldInstallDir\data"
CopyFiles /SILENT "$DataBackupDir\data\*.*" "$OldInstallDir\data\"
DetailPrint "Restored portable user data from pre-uninstall backup."
${EndIf}
${EndIf}
${If} ${FileExists} "$DataBackupDir\loose_decks\*.cod"
${OrIf} ${FileExists} "$DataBackupDir\loose_decks\*.dec"
!insertmacro CockLog "post-uninstall restore: restoring loose deck files"
CreateDirectory "$INSTDIR"
CopyFiles /SILENT "$DataBackupDir\loose_decks\*.cod" "$INSTDIR\"
CopyFiles /SILENT "$DataBackupDir\loose_decks\*.dec" "$INSTDIR\"
CreateDirectory "$OldInstallDir"
CopyFiles /SILENT "$DataBackupDir\loose_decks\*.cod" "$OldInstallDir\"
CopyFiles /SILENT "$DataBackupDir\loose_decks\*.dec" "$OldInstallDir\"
DetailPrint "Restored deck files stored in the install directory."
${IfNot} ${Silent}
MessageBox MB_OK|MB_ICONINFORMATION "Your decks were stored inside the Cockatrice install folder, which the previous version's uninstaller deletes.$\n$\nThey have been restored from a backup. Please move them out of the install folder (Settings -> General -> Paths) so a future uninstall cannot delete them again."
@ -1120,12 +1141,16 @@ ${If} $PortableMode = 0
; instance of the application is still running out of the *old* install
; directory before letting it delete anything. The uninstall string is
; stashed away first, the check works on $R0.
; $INSTDIR is still the default here (directory page comes later), so the
; backup/restore dir comes from the registry InstallLocation via $GuardDir,
; not from $INSTDIR - otherwise a custom-location install is unprotected.
StrCpy $OldUninstallString $R0
!insertmacro CockLog "componentsPagePre: old 32-bit uninstall '$OldUninstallString _?=$INSTDIR'"
Call EnsureOldInstallNotRunning
StrCpy $OldInstallDir $GuardDir
!insertmacro CockLog "componentsPagePre: old 32-bit uninstall '$OldUninstallString _?=$OldInstallDir' (oldDir=$OldInstallDir InstDir=$INSTDIR)"
ClearErrors
Call BackupUserDataBeforeUninstall
ExecWait "$OldUninstallString _?=$INSTDIR"
ExecWait "$OldUninstallString _?=$OldInstallDir"
Call RestoreUserDataAfterUninstall
done32:
@ -1146,11 +1171,12 @@ ${If} $PortableMode = 0
uninst64:
StrCpy $OldUninstallString $R0
!insertmacro CockLog "componentsPagePre: old 64-bit uninstall '$OldUninstallString _?=$INSTDIR'"
Call EnsureOldInstallNotRunning
StrCpy $OldInstallDir $GuardDir
!insertmacro CockLog "componentsPagePre: old 64-bit uninstall '$OldUninstallString _?=$OldInstallDir' (oldDir=$OldInstallDir InstDir=$INSTDIR)"
ClearErrors
Call BackupUserDataBeforeUninstall
ExecWait "$OldUninstallString _?=$INSTDIR"
ExecWait "$OldUninstallString _?=$OldInstallDir"
Call RestoreUserDataAfterUninstall
done64: