-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(nsis): use atomic rmdir on update #6551
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"app-builder-lib": patch | ||
--- | ||
|
||
fix(nsis): use revertible rmdir on update |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,109 @@ Function un.onInit | |
!endif | ||
FunctionEnd | ||
|
||
Function un.atomicRMDir | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not entirely proud of this, but it implements |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The order of operations changed as stated in the commit message. We try to keep as much state as possible in case we will need to restore the files on failure. The users would be really frustrated to see their shortcuts and file associations go if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just went ahead and did it. Makes for a much better user experience! |
||
!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" | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think ideally we should retry running uninstaller (with user's confirmation) in such case instead of failing whole installation immediately. Let me know if you want me to add this to the current patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, and btw.
Abort
doesn't quite work here for some reason (the installer just hangs), so I had to resort toQuit
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indutny-signal This sounds like a great idea. Is it complex to add?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually already pushed it 😉