Fix partial updates on Windows

This commit is contained in:
Fedor Indutny 2022-01-19 15:42:55 -08:00 committed by GitHub
parent 3eddd06e5c
commit a802188f33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 296 additions and 0 deletions

View File

@ -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"