1
0
Fork 0

Improve windows installer (#6045)

This commit is contained in:
Wilfried Goesgens 2018-08-17 12:37:47 +02:00 committed by Jan
parent aa68414207
commit e5843d32f8
14 changed files with 165 additions and 98 deletions

View File

@ -1,4 +1,5 @@
!include "StrStr.nsh"
Var PathToAdd
;--------------------------------
; path functions

View File

@ -1,78 +1,91 @@
!include "LogicLib.nsh"
!macro printExitCode exitCode Message
!define ARANGO_EXIT_SUCCESS 0
!define ARANGO_EXIT_FAILED 1
!define ARANGO_EXIT_CODE_RESOLVING_FAILED 2
!define ARANGO_EXIT_BINARY_NOT_FOUND 5
!define ARANGO_EXIT_CONFIG_NOT_FOUND 6
!define ARANGO_EXIT_UPGRADE_FAILED 10
!define ARANGO_EXIT_UPGRADE_REQUIRED 11
!define ARANGO_EXIT_DOWNGRADE_REQUIRED 12
!define ARANGO_EXIT_VERSION_CHECK_FAILED 13
!define ARANGO_EXIT_ALREADY_RUNNING 20
!define ARANGO_EXIT_COULD_NOT_BIND_PORT 21
!define ARANGO_EXIT_COULD_NOT_LOCK 22
!define ARANGO_EXIT_RECOVERY 23
!define ARANGO_EXIT_DB_NOT_EMPTY 24
!macro printExitCode exitCode Message DetailMessage
Push "${exitCode}"
Push "${Message}"
Push "${DetailMessage}"
Call printExitCode
!macroend
Function printExitCode
pop $1
pop $3
pop $2
${Switch} $0
pop $1
${Switch} $1
${Case} 0 # EXIT_SUCCESS
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nsuccess'
; No error has occurred.
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> success <<$\r$\n"No error has occurred."$\r$\n$3'
${Break}
${Case} 1 # EXIT_FAILED
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nexit with error'
; Will be returned when a general error occurred.
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> exit with error <<$\r$\n"Will be returned when a general error occurred."$\r$\n$3'
${Break}
${Case} 2 # EXIT_CODE_RESOLVING_FAILED
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nexit code resolving failed'
; fill me
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> exit code resolving failed <<$\r$\n"unspecified exit code"$\r$\n$3'
${Break}
${Case} 5 # EXIT_BINARY_NOT_FOUND
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nbinary not found'
; fill me
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> binary not found <<$\r$\n"Will be returned if a referenced binary was not found"$\r$\n$3'
${Break}
${Case} 6 # EXIT_CONFIG_NOT_FOUND
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nconfig not found'
; fill me
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> config not found <<$\r$\n"Will be returned if no valid configuration was found"$\r$\n$3'
${Break}
${Case} 10 # EXIT_UPGRADE_FAILED
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nupgrade failed'
; Will be returned when the database upgrade failed
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> upgrade failed <<$\r$\n"Will be returned when the database upgrade failed"$\r$\n$3'
${Break}
${Case} 11 # EXIT_UPGRADE_REQUIRED
MessageBox MB_ICONEXCLAMATION '$1:$\r$\ndb upgrade required'
; Will be returned when a database upgrade is required
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> db upgrade required <<$\r$\n"Will be returned when a database upgrade is required"$\r$\n$3'
${Break}
${Case} 12 # EXIT_DOWNGRADE_REQUIRED
MessageBox MB_ICONEXCLAMATION '$1:$\r$\ndb downgrade required'
; Will be returned when a database upgrade is required
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> db downgrade required <<$\r$\n"Will be returned when a database upgrade is required"$\r$\n$3'
${Break}
${Case} 13 # EXIT_VERSION_CHECK_FAILED
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nversion check failed'
; Will be returned when there is a version mismatch
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> version check failed <<$\r$\n"Will be returned when there is a version mismatch"$\r$\n$3'
${Break}
${Case} 20 # EXIT_ALREADY_RUNNING
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nalready running'
; Will be returned when arangod is already running according to PID-file
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> already running <<$\r$\n"Will be returned when arangod is already running according to PID-file"$\r$\n$3'
${Break}
${Case} 21 # EXIT_COULD_NOT_BIND_PORT
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nport blocked'
; Will be returned when endpoint is taken by another process
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> port blocked <<$\r$\n"Will be returned when the configured tcp endpoint is already occupied by another process"$\r$\n$3'
${Break}
${Case} 22 # EXIT_COULD_NOT_LOCK
MessageBox MB_ICONEXCLAMATION '$1:$\r$\ncould not lock - another process could be running'
; fill me
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> could not lock - another process could be running <<$\r$\n"Will be returned if another ArangoDB process is running, or the state can not be cleared"$\r$\n$3'
${Break}
${Case} 23 # EXIT_RECOVERY
MessageBox MB_ICONEXCLAMATION '$1:$\r$\nrecovery failed'
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> recovery failed <<$\r$\n"Will be returned if the automatic database startup recovery fails"$\r$\n$3'
${Break}
${Case} 24 # EXIT_DB_NOT_EMPTY
MessageBox MB_ICONEXCLAMATION '$2:$\r$\n>> database not empty <<$\r$\n"Will be returned when commanding to initialize a non empty directory as database"$\r$\n$3'
${Break}
${Default}
MessageBox MB_ICONEXCLAMATION '$2:$\r$\nUnknown exit code $1!'
; Will be returned if the recovery fails
${Break}

View File

@ -0,0 +1,32 @@
!macro xCopyDir sourceDir DestDir
push ${sourceDir}
push ${DestDir}
call xCopyDir
!macroend
Function xCopyDir
pop $4
pop $3
ReadEnvStr $5 COMSPEC
FindFirst $0 $1 "$3\*"
loop:
StrCmp $1 "" done
StrCmp $1 "." skip
StrCmp $1 ".." skip
IfFileExists "$3\$1\*.*" IsDir 0
DetailPrint "File Source: $3\$1"
DetailPrint "Dest: $4"
ExecWait '$5 /C xcopy /E /C /H /K /O /Y "$3\$1" "$4\" '
goto skip
IsDir:
DetailPrint "Dir Source: $3\$1"
DetailPrint "Dest: $4"
ExecWait '$5 /C xcopy /E /C /H /K /O /Y "$3\$1" "$4\$1\" '
skip:
FindNext $0 $1
Goto loop
done:
FindClose $0
FunctionEnd

View File

@ -14,6 +14,7 @@
!include "WinMessages.nsh"
!include "MUI2.nsh"
!include "StripSlashes.nsh"
!include "xcopy.nsh"
; !include "GetTime.nsh"
;--------------------------------
; get commandline parameters
@ -56,13 +57,13 @@ Var ADD_TO_PATH ; x bool
Var AUTOMATIC_UPDATE
Var AUTOMATIC_BACKUP
# determine_possible_install_scope sets:
Var AllowGlobalInstall
Var ChooseInstallPath
Var BackupPath
VAR TRI_INSTALL_SERVICE ; x bool
VAR TRI_INSTALL_SCOPE_ALL ; x bool => All / ThisUser
Var newCfgValues ; keep new config file values
@ -72,11 +73,11 @@ Var ServiceUp ; did the service start?
Var DATADIR
Var APPDIR
Var LOGFILE
; Var LOGFILE
Var ini_DATADIR
Var ini_APPDIR
Var ini_LOGFILE
; Var ini_LOGFILE
Var UpgradeInstall
Var LaunchAfterInstall
@ -124,6 +125,17 @@ RequestExecutionLevel highest
!include "WaitForService.nsh"
!include "ReadINIFileKeys.nsh"
!macro determine_possible_install_scope
UserInfo::GetAccountType
pop $0
${If} $0 == "admin"
StrCpy $AllowGlobalInstall "1"
${Else}
StrCpy $AllowGlobalInstall "0"
${EndIf}
!macroend
!macro determine_install_scope un
Function ${un}determine_install_scope
Pop $0
@ -210,11 +222,6 @@ OldFound:
StrCpy $UpgradeInstall "1"
FunctionEnd
Function disableBackButton
GetDlgItem $0 $HWNDParent 3
EnableWindow $0 0
FunctionEnd
Function stop_old_service
${If} $TRI_INSTALL_SERVICE == 1
SimpleSC::StopService '${TRI_SVC_NAME}' 0 30
@ -498,7 +505,6 @@ Function InstallOptionsPage1
continueUI:
!insertmacro determineInstallScope 1
Push ${TEMP1}
displayAgain:
!insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@"
@ -715,36 +721,34 @@ FunctionEnd
Function UpgradeExisting
; Check whether we acutally should upgrade:
!insertmacro StripBackslash DATADIR
!insertmacro StripSlash DATADIR
DetailPrint "Checking whether an existing database needs upgrade: "
ExecWait "$INSTDIR\${SBIN_DIR}\arangod.exe --server.rest-server false --log.foreground-tty false --database.check-version" $0
DetailPrint "done Checking whether an existing database needs upgrade: $0"
${If} $0 != 0
${AndIf} $0 != 11
!insertmacro printExitCode $0 "failed to detect whether we need to Upgrade"
${ElseIf} $0 == 11
${AndIf} $0 != ${ARANGO_EXIT_UPGRADE_REQUIRED}
!insertmacro printExitCode $0 "failed to detect whether we need to Upgrade" ""
${ElseIf} $0 == ${ARANGO_EXIT_UPGRADE_REQUIRED}
${AndIf} $AUTOMATIC_UPDATE == "1"
DetailPrint "Yes."
DetailPrint "Update required."
${If} $AUTOMATIC_BACKUP == "1"
; We should and we should keep a backup:
StrCpy $BackupPath "$DATADIR"
!insertmacro StripBackslash BackupPath
!insertmacro StripSlash BackupPath
${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6
StrCpy $BackupPath "$BackupPath_$2-$1-$0_$4_$5_$6"
CreateDirectory "$BackupPath"
ClearErrors
DetailPrint "Copying old database from $DATADIR to backup directory $BackupPath"
CopyFiles "$DATADIR" "$BackupPath"
IfErrors 0 +2
MessageBox MB_ICONEXCLAMATION "The upgrade failed to copy the files $\r$\nfrom '$DATADIR'$\r$\nto '$BackupPath'; please do it manually.$\r$\n$\r$\nClick OK to continue."
DetailPrint "Copying old database from $DATADIR"
DetailPrint "to backup directory $BackupPath"
!insertmacro xCopyDir "$DATADIR" "$BackupPath"
${EndIf}
DetailPrint "Attempting to run database upgrade: "
; Now actually do the upgrade
ExecWait "$INSTDIR\${SBIN_DIR}\arangod.exe --server.rest-server false --log.level error --database.auto-upgrade true" $0
DetailPrint "Done running database upgrade: $0"
${If} $0 != 0
!insertmacro printExitCode $0 "the Upgrade failed, please do a manual upgrade"
!insertmacro printExitCode $0 "the Upgrade failed, please do a manual upgrade" ""
Abort
${EndIf}
${EndIf}
@ -761,7 +765,7 @@ Function SetDBPassword
${If} $0 == 0
return
${Else}
!insertmacro printExitCode $0 "Failed to initialize database password.$\r$\nPlease check the Windows event log for more details$\r$\n"
!insertmacro printExitCode $0 "Failed to initialize database password$\r$\n" "Please check the Windows event log for more details$\r$\n"
Abort
${EndIf}
error:
@ -792,8 +796,9 @@ Function InstallService
${If} $2 == "1"
MessageBox MB_OK "${SC_WAITED}$\r$\nbut it exited with an error; $\r$\n${SC_SV}$\r$\n${SC_EVLOG}"
Abort
${ElseIf} $2 == "2"
MessageBox MB_OK "${SC_WAITED}$\r$\nbut it exited with a fatal error; $\r$\n${SC_SV}$\r$\n${SC_EVLOG}"
${Else}
!insertmacro printExitCode $2 "${SC_WAITED}$\r$\nbut it exited with a fatal error" "$\r$\n${SC_SV}$\r$\n${SC_EVLOG};$\r$\nExit status: $2"
; MessageBox MB_OK "${SC_WAITED}$\r$\nbut it exited with a fatal error; $\r$\n${SC_SV}$\r$\n${SC_EVLOG}"
Abort
${EndIf}
${ElseIf} $1 != "0"
@ -928,9 +933,9 @@ Section "-Core installation"
${If} $APPDIR != ""
StrCpy $ini_APPDIR "[javascript]$\r$\napp-path = $APPDIR$\r$\n"
${EndIf}
${If} $LOGFILE != ""
StrCpy $ini_LOGFILE "[log]$\r$\nfile = $LOGFILE$\r$\n"
${EndIf}
;${If} $LOGFILE != ""
; StrCpy $ini_LOGFILE "[log]$\r$\nfile = $LOGFILE$\r$\n"
;${EndIf}
StrCpy $newCfgValues "$ini_APPDIR$ini_DATADIR[server]$\r$\nstorage-engine = $STORAGE_ENGINE$\r$\n"
StrCpy $newCfgValuesFile "$INSTDIR\etc\arangodb3\newValues.ini"
FileOpen $4 "$newCfgValuesFile" w
@ -1021,13 +1026,8 @@ FunctionEnd
;--------------------------------
; determine admin versus local install
Function un.onInit
UserInfo::GetAccountType
pop $0
${If} $0 == "admin"
StrCpy $AllowGlobalInstall "1"
${Else}
StrCpy $AllowGlobalInstall "0"
${EndIf}
; are we allowed to un.install admin in first place?
!insertmacro determine_possible_install_scope
; ArangoDB may be installed in different places
; Determine if the ArangoDB was installed for a local user
@ -1227,18 +1227,11 @@ SectionEnd
; Choose different default installation folder based on SV_ALLUSERS...
; "Program Files" for AllUsers, "My Documents" for JustMe...
var allPathOpts
var CMDINSTDIR
Function .onInit
UserInfo::GetAccountType
pop $0
${If} $0 == "admin"
StrCpy $AllowGlobalInstall "1"
${Else}
StrCpy $AllowGlobalInstall "0"
${EndIf}
; are we allowed to install admin in first place?
!insertmacro determine_possible_install_scope
${GetParameters} $R0
ClearErrors
${GetOptions} $R0 "/INSTALL_SCOPE_ALL=" $0

View File

@ -26,6 +26,7 @@
#include <iostream>
#include <thread>
#include "Basics/exitcodes.h"
#include "Basics/FileUtils.h"
#include "Basics/terminal-utils.h"
#include "Cluster/ServerState.h"
@ -151,7 +152,7 @@ void InitDatabaseFeature::checkEmptyDatabase() {
bool empty = false;
std::string message;
int code = 2;
int code = TRI_EXIT_CODE_RESOLVING_FAILED;
if (FileUtils::exists(path)) {
if (!FileUtils::isDirectory(path)) {
@ -176,6 +177,7 @@ void InitDatabaseFeature::checkEmptyDatabase() {
if (!empty) {
message = "database already initialized, refusing to initialize it again";
code = TRI_EXIT_DB_NOT_EMPTY;
goto doexit;
}

View File

@ -8,6 +8,7 @@ set(CPACK_NSIS_MODIFY_PATH ON)
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL 1)
set(CPACK_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Installation/Windows/Templates")
set(CPACK_PLUGIN_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Installation/Windows/Plugins")
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME} ${CPACK_PACKAGE_VERSION}-${ARANGODB_PACKAGE_REVISION}_${ARANGODB_PACKAGE_ARCHITECTURE}")
# want @ in @only nsis template:
set(CPACK_ROOTDIR "@ROOTDIR@")
if (CMAKE_CL_64)

View File

@ -453,9 +453,9 @@ void WindowsServiceFeature::shutDownFailure () {
/// @brief wrap ArangoDB server so we can properly emmit a status on shutdown
/// starting
//////////////////////////////////////////////////////////////////////////////
void WindowsServiceFeature::abortFailure () {
void WindowsServiceFeature::abortFailure (uint16_t exitCode) {
// startup finished - signalize we're running.
SetServiceStatus(SERVICE_STOP, ERROR_SERVICE_SPECIFIC_ERROR, 0, 0, 2);
SetServiceStatus(SERVICE_STOP, ERROR_SERVICE_SPECIFIC_ERROR, 0, 0, exitCode);
}
////////////////////////////////////////////////////////////////////////////////
@ -549,10 +549,10 @@ void WindowsServiceFeature::collectOptions(std::shared_ptr<ProgramOptions> optio
new BooleanParameter(&_stopWaitService));
}
void WindowsServiceFeature::abortService() {
void WindowsServiceFeature::abortService(uint16_t exitCode) {
if (ArangoInstance != nullptr) {
ArangoInstance->_server = nullptr;
ArangoInstance->abortFailure();
ArangoInstance->abortFailure(exitCode);
}
exit(EXIT_FAILURE);
}

View File

@ -54,8 +54,8 @@ class WindowsServiceFeature final : public application_features::ApplicationFeat
void shutDownBegins ();
void shutDownComplete ();
void shutDownFailure ();
void abortFailure();
static void abortService();
void abortFailure(uint16_t exitCode);
static void abortService(uint16_t exitCode);
public:
bool _installService = false;

View File

@ -20,4 +20,5 @@ void TRI_InitializeExitMessages() {
REG_EXIT(EXIT_COULD_NOT_BIND_PORT, "port blocked");
REG_EXIT(EXIT_COULD_NOT_LOCK, "could not lock - another process could be running");
REG_EXIT(EXIT_RECOVERY, "recovery failed");
REG_EXIT(EXIT_DB_NOT_EMPTY, "database not empty");
}

View File

@ -5,10 +5,10 @@
# general
EXIT_SUCCESS,0,"success","No error has occurred."
EXIT_FAILED,1,"exit with error","Will be returned when a general error occurred."
EXIT_CODE_RESOLVING_FAILED,2,"exit code resolving failed","fill me"
EXIT_CODE_RESOLVING_FAILED,2,"exit code resolving failed","unspecified exit code"
EXIT_BINARY_NOT_FOUND,5,"binary not found","fill me"
EXIT_CONFIG_NOT_FOUND,6,"config not found","fill me"
EXIT_BINARY_NOT_FOUND,5,"binary not found","Will be returned if a referenced binary was not found"
EXIT_CONFIG_NOT_FOUND,6,"config not found","Will be returned if no valid configuration was found"
# internal
EXIT_UPGRADE_FAILED,10,"upgrade failed","Will be returned when the database upgrade failed"
@ -18,11 +18,12 @@ EXIT_VERSION_CHECK_FAILED,13,"version check failed","Will be returned when there
# startup
EXIT_ALREADY_RUNNING,20,"already running","Will be returned when arangod is already running according to PID-file"
EXIT_COULD_NOT_BIND_PORT,21,"port blocked","Will be returned when endpoint is taken by another process"
EXIT_COULD_NOT_LOCK,22,"could not lock - another process could be running","fill me"
EXIT_RECOVERY,23,"recovery failed","Will be returned if the recovery fails"
EXIT_COULD_NOT_BIND_PORT,21,"port blocked","Will be returned when the configured tcp endpoint is already occupied by another process"
EXIT_COULD_NOT_LOCK,22,"could not lock - another process could be running","Will be returned if another ArangoDB process is running, or the state can not be cleared"
EXIT_RECOVERY,23,"recovery failed","Will be returned if the automatic database startup recovery fails"
EXIT_DB_NOT_EMPTY,24,"database not empty","Will be returned when commanding to initialize a non empty directory as database"
# network
#EXIT_NO_COORDINATOR
#EXIT_NO_AGENCY
#EXIT_NO_CONNECTIVITY
#EXIT_NO_CONNECTIVITY

View File

@ -18,17 +18,17 @@ constexpr int TRI_EXIT_FAILED
/// 2: EXIT_CODE_RESOLVING_FAILED
/// exit code resolving failed
/// fill me
/// unspecified exit code
constexpr int TRI_EXIT_CODE_RESOLVING_FAILED = 2;
/// 5: EXIT_BINARY_NOT_FOUND
/// binary not found
/// fill me
/// Will be returned if a referenced binary was not found
constexpr int TRI_EXIT_BINARY_NOT_FOUND = 5;
/// 6: EXIT_CONFIG_NOT_FOUND
/// config not found
/// fill me
/// Will be returned if no valid configuration was found
constexpr int TRI_EXIT_CONFIG_NOT_FOUND = 6;
/// 10: EXIT_UPGRADE_FAILED
@ -58,19 +58,27 @@ constexpr int TRI_EXIT_ALREADY_RUNNING
/// 21: EXIT_COULD_NOT_BIND_PORT
/// port blocked
/// Will be returned when endpoint is taken by another process
/// Will be returned when the configured tcp endpoint is already occupied by
/// another process
constexpr int TRI_EXIT_COULD_NOT_BIND_PORT = 21;
/// 22: EXIT_COULD_NOT_LOCK
/// could not lock - another process could be running
/// fill me
/// Will be returned if another ArangoDB process is running, or the state can
/// not be cleared
constexpr int TRI_EXIT_COULD_NOT_LOCK = 22;
/// 23: EXIT_RECOVERY
/// recovery failed
/// Will be returned if the recovery fails
/// Will be returned if the automatic database startup recovery fails
constexpr int TRI_EXIT_RECOVERY = 23;
/// 24: EXIT_DB_NOT_EMPTY
/// database not empty
/// Will be returned when commanding to initialize a non empty directory as
/// database
constexpr int TRI_EXIT_DB_NOT_EMPTY = 24;
/// register all exit codes for ArangoDB
void TRI_InitializeExitMessages();

View File

@ -526,7 +526,7 @@ void TRI_SetWindowsServiceAbortFunction(TRI_serviceAbort_t f) {
void ADB_WindowsExitFunction(int exitCode, void* data) {
if (serviceAbort != nullptr) {
serviceAbort();
serviceAbort(exitCode);
}
exit(exitCode);

View File

@ -83,7 +83,7 @@ int TRI_MapSystemError(DWORD);
bool TRI_InitWindowsEventLog(void);
void TRI_CloseWindowsEventlog(void);
typedef void (*TRI_serviceAbort_t)(void);
typedef void (*TRI_serviceAbort_t)(uint16_t exitCode);
void TRI_SetWindowsServiceAbortFunction(TRI_serviceAbort_t);

View File

@ -59,22 +59,32 @@ def genNSISFile(errors, filename):
impl = """
!include "LogicLib.nsh"
!macro printExitCode exitCode Message
"""
for e in errors:
impl += """!define ARANGO_%s %s
""" % (
e[0],
e[1]
)
impl +="""
!macro printExitCode exitCode Message DetailMessage
Push "${exitCode}"
Push "${Message}"
Push "${DetailMessage}"
Call printExitCode
!macroend
Function printExitCode
pop $1
pop $3
pop $2
${Switch} $0\n
pop $1
${Switch} $1\n
"""
# print individual errors
for e in errors:
impl += """
${Case} %s # %s
MessageBox MB_ICONEXCLAMATION '$1:$\\r$\\n%s'
; %s
MessageBox MB_ICONEXCLAMATION '$2:$\\r$\\n>> %s <<$\\r$\\n"%s"$\\r$\\n$3'
${Break}
""" % (
e[1],
@ -84,6 +94,11 @@ ${Switch} $0\n
)
impl = impl + """
${Default}
MessageBox MB_ICONEXCLAMATION '$2:$\\r$\\nUnknown exit code $1!'
; Will be returned if the recovery fails
${Break}
${EndSwitch}
FunctionEnd
"""