From a802188f33b270bf78eaa6e8a176fc067eb860e2 Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Wed, 19 Jan 2022 15:42:55 -0800 Subject: [PATCH] Fix partial updates on Windows --- patches/app-builder-lib+22.14.5.patch | 296 ++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) diff --git a/patches/app-builder-lib+22.14.5.patch b/patches/app-builder-lib+22.14.5.patch index 9df980603..2e9021f1b 100644 --- a/patches/app-builder-lib+22.14.5.patch +++ b/patches/app-builder-lib+22.14.5.patch @@ -24,3 +24,299 @@ index 1536059..555f8f5 100644 - update-mime-database /usr/share/mime || true update-desktop-database /usr/share/applications || true +diff --git a/node_modules/app-builder-lib/templates/nsis/include/extractAppPackage.nsh b/node_modules/app-builder-lib/templates/nsis/include/extractAppPackage.nsh +index 367aaae..d96a655 100644 +--- a/node_modules/app-builder-lib/templates/nsis/include/extractAppPackage.nsh ++++ b/node_modules/app-builder-lib/templates/nsis/include/extractAppPackage.nsh +@@ -90,5 +90,41 @@ + !macroend + + !macro extractUsing7za FILE ++ Push $OUTDIR ++ CreateDirectory "$PLUGINSDIR\7z-out" ++ ClearErrors ++ SetOutPath "$PLUGINSDIR\7z-out" ++ Nsis7z::Extract "${FILE}" ++ Pop $R0 ++ SetOutPath $R0 ++ ++ # Retry counter ++ StrCpy $R1 0 ++ ++ LoopExtract7za: ++ IntOp $R1 $R1 + 1 ++ ++ # Attempt to copy files in atomic way ++ CopyFiles /SILENT "$PLUGINSDIR\7z-out\*" $OUTDIR ++ IfErrors 0 DoneExtract7za ++ ++ DetailPrint `Can't modify "${PRODUCT_NAME}"'s files.` ++ ${if} $R1 < 5 ++ # Try copying a few times before asking for a user action. ++ Goto RetryExtract7za ++ ${else} ++ MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "$(appCannotBeClosed)" /SD IDCANCEL IDRETRY RetryExtract7za ++ ${endIf} ++ ++ # As an absolutely last resort after a few automatic attempts and user ++ # intervention - we will just overwrite everything with `Nsis7z::Extract` ++ # even though it is not atomic and will ignore errors. + Nsis7z::Extract "${FILE}" ++ Quit ++ ++ RetryExtract7za: ++ Sleep 1000 ++ Goto LoopExtract7za ++ ++ DoneExtract7za: + !macroend +diff --git a/node_modules/app-builder-lib/templates/nsis/include/installUtil.nsh b/node_modules/app-builder-lib/templates/nsis/include/installUtil.nsh +index 0d6f293..4736774 100644 +--- a/node_modules/app-builder-lib/templates/nsis/include/installUtil.nsh ++++ b/node_modules/app-builder-lib/templates/nsis/include/installUtil.nsh +@@ -126,7 +126,10 @@ Function handleUninstallResult + Return + + ${if} $R0 != 0 ++ MessageBox MB_OK|MB_ICONEXCLAMATION "$(uninstallFailed): $R0" + DetailPrint `Uninstall was not successful. Uninstaller error code: $R0.` ++ SetErrorLevel 2 ++ Quit + ${endif} + FunctionEnd + +@@ -156,7 +159,7 @@ Function uninstallOldVersion + !endif + ${if} $uninstallString == "" + ClearErrors +- Goto Done ++ Return + ${endif} + ${endif} + +@@ -175,7 +178,7 @@ Function uninstallOldVersion + ${if} $installationDir == "" + ${andIf} $uninstallerFileName == "" + ClearErrors +- Goto Done ++ Return + ${endif} + + ${if} $installMode == "CurrentUser" +@@ -206,12 +209,37 @@ Function uninstallOldVersion + StrCpy $uninstallerFileNameTemp "$PLUGINSDIR\old-uninstaller.exe" + !insertmacro copyFile "$uninstallerFileName" "$uninstallerFileNameTemp" + +- ExecWait '"$uninstallerFileNameTemp" /S /KEEP_APP_DATA $0 _?=$installationDir' $R0 +- ifErrors 0 Done +- # the execution failed - might have been caused by some group policy restrictions +- # we try to execute the uninstaller in place +- ExecWait '"$uninstallerFileName" /S /KEEP_APP_DATA $0 _?=$installationDir' $R0 +- Done: ++ # Retry counter ++ StrCpy $R5 0 ++ ++ UninstallLoop: ++ IntOp $R5 $R5 + 1 ++ ++ ${if} $R5 > 5 ++ MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "$(appCannotBeClosed)" /SD IDCANCEL IDRETRY OneMoreAttempt ++ Return ++ ${endIf} ++ ++ OneMoreAttempt: ++ ExecWait '"$uninstallerFileNameTemp" /S /KEEP_APP_DATA $0 _?=$installationDir' $R0 ++ ifErrors TryInPlace CheckResult ++ ++ TryInPlace: ++ # the execution failed - might have been caused by some group policy restrictions ++ # we try to execute the uninstaller in place ++ ExecWait '"$uninstallerFileName" /S /KEEP_APP_DATA $0 _?=$installationDir' $R0 ++ ifErrors DoesNotExist ++ ++ CheckResult: ++ ${if} $R0 == 0 ++ Return ++ ${endIf} ++ ++ Sleep 1000 ++ Goto UninstallLoop ++ ++ DoesNotExist: ++ SetErrors + FunctionEnd + + !macro uninstallOldVersion ROOT_KEY +diff --git a/node_modules/app-builder-lib/templates/nsis/messages.yml b/node_modules/app-builder-lib/templates/nsis/messages.yml +index ce95e3f..6527c99 100644 +--- a/node_modules/app-builder-lib/templates/nsis/messages.yml ++++ b/node_modules/app-builder-lib/templates/nsis/messages.yml +@@ -144,3 +144,5 @@ areYouSureToUninstall: + da: Er du sikker på, at du vil afinstallere ${PRODUCT_NAME}? + decompressionFailed: + en: Failed to decompress files. Please try running the installer again. ++uninstallFailed: ++ en: Failed to uninstall old application files. Please try running the installer again. +diff --git a/node_modules/app-builder-lib/templates/nsis/uninstaller.nsh b/node_modules/app-builder-lib/templates/nsis/uninstaller.nsh +index 8db1f9a..d400ec4 100644 +--- a/node_modules/app-builder-lib/templates/nsis/uninstaller.nsh ++++ b/node_modules/app-builder-lib/templates/nsis/uninstaller.nsh +@@ -28,6 +28,109 @@ Function un.onInit + !endif + FunctionEnd + ++Function un.atomicRMDir ++ Exch $R0 ++ Push $R1 ++ Push $R2 ++ Push $R3 ++ ++ StrCpy $R3 "$INSTDIR$R0\*.*" ++ FindFirst $R1 $R2 $R3 ++ ++ loop: ++ StrCmp $R2 "" break ++ ++ StrCmp $R2 "." continue ++ StrCmp $R2 ".." continue ++ ++ IfFileExists "$INSTDIR$R0\$R2\*.*" isDir isNotDir ++ ++ isDir: ++ CreateDirectory "$PLUGINSDIR\old-install$R0\$R2" ++ ++ Push "$R0\$R2" ++ Call un.atomicRMDir ++ Pop $R3 ++ ++ ${if} $R3 != 0 ++ Goto done ++ ${endIf} ++ ++ Goto continue ++ ++ isNotDir: ++ ClearErrors ++ Rename "$INSTDIR$R0\$R2" "$PLUGINSDIR\old-install$R0\$R2" ++ ++ # Ignore errors when renaming ourselves. ++ StrCmp "$R0\$R2" "${UNINSTALL_FILENAME}" 0 +2 ++ ClearErrors ++ ++ IfErrors 0 +3 ++ StrCpy $R3 "$INSTDIR$R0\$R2" ++ Goto done ++ ++ continue: ++ FindNext $R1 $R2 ++ Goto loop ++ ++ break: ++ StrCpy $R3 0 ++ ++ done: ++ FindClose $R1 ++ ++ StrCpy $R0 $R3 ++ ++ Pop $R3 ++ Pop $R2 ++ Pop $R1 ++ Exch $R0 ++FunctionEnd ++ ++Function un.restoreFiles ++ Exch $R0 ++ Push $R1 ++ Push $R2 ++ Push $R3 ++ ++ StrCpy $R3 "$PLUGINSDIR\old-install$R0\*.*" ++ FindFirst $R1 $R2 $R3 ++ ++ loop: ++ StrCmp $R2 "" break ++ ++ StrCmp $R2 "." continue ++ StrCmp $R2 ".." continue ++ ++ IfFileExists "$INSTDIR$R0\$R2\*.*" isDir isNotDir ++ ++ isDir: ++ CreateDirectory "$INSTDIR$R0\$R2" ++ ++ Push "$R0\$R2" ++ Call un.restoreFiles ++ Pop $R3 ++ ++ Goto continue ++ ++ isNotDir: ++ Rename $PLUGINSDIR\old-install$R0\$R2" "$INSTDIR$R0\$R2" ++ ++ continue: ++ FindNext $R1 $R2 ++ Goto loop ++ ++ break: ++ StrCpy $R0 0 ++ FindClose $R1 ++ ++ Pop $R3 ++ Pop $R2 ++ Pop $R1 ++ Exch $R0 ++FunctionEnd ++ + Section "un.install" + # for assisted installer we check it here to show progress + !ifndef ONE_CLICK +@@ -38,6 +141,34 @@ Section "un.install" + + !insertmacro setLinkVars + ++ # delete the installed files ++ !ifmacrodef customRemoveFiles ++ !insertmacro customRemoveFiles ++ !else ++ ${if} ${isUpdated} ++ CreateDirectory "$PLUGINSDIR\old-install" ++ ++ Push "" ++ Call un.atomicRMDir ++ Pop $R0 ++ ++ ${if} $R0 != 0 ++ DetailPrint "File is busy, aborting: $R0" ++ ++ # Attempt to restore previous directory ++ Push "" ++ Call un.restoreFiles ++ Pop $R0 ++ ++ Abort `Can't rename "$INSTDIR" to "$PLUGINSDIR\old-install".` ++ ${endif} ++ ++ ${endif} ++ ++ # Remove all files (or remaining shallow directories from the block above) ++ RMDir /r $INSTDIR ++ !endif ++ + ${ifNot} ${isKeepShortcuts} + WinShell::UninstAppUserModelId "${APP_ID}" + +@@ -64,13 +195,6 @@ Section "un.install" + !insertmacro unregisterFileAssociations + !endif + +- # delete the installed files +- !ifmacrodef customRemoveFiles +- !insertmacro customRemoveFiles +- !else +- RMDir /r $INSTDIR +- !endif +- + Var /GLOBAL isDeleteAppData + StrCpy $isDeleteAppData "0" +