#? stdtmpl(subsChar='?') | standard #proc generateNsisSetup(c: ConfigData): string = # result = "; NSIS script generated by niminst\n" & # "; To regenerate run ``niminst nsis`` or ``koch nsis``\n" ;-------------------------------- ; Included headers ; Modern User Interface 2.0 Header !include "MUI2.nsh" ; File Functions Header, used to get the current drive root. !include "FileFunc.nsh" ;-------------------------------- ; Global variables and defines !define PRODUCT_NAME "?c.displayName" !define PRODUCT_VERSION "?c.version" !define PRODUCT_PUBLISHER "?c.authors" !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\?{c.name}.exe" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKCU" !define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir" ;-------------------------------- ; General Setup Information ; Name and output file Name "?{c.name} ?{c.version}" OutFile "?{c.name}_?{c.version}.exe" ; Default installation folder ; This is changed later (in .onInit) to the root directory, if possible. InstallDir "$PROGRAMFILES?{when sizeof(int) == 8: "64" else: ""}\?{c.name}-?{c.version}\" ; Get installation folder from registry if available InstallDirRegKey HKCU "Software\c.name\c.version" "" ; Request user level application privileges. RequestExecutionLevel user ; Allow installation to the root drive directory. AllowRootDirInstall false ; Maximum compression! SetCompressor /SOLID /FINAL lzma ; Installer and Uninstaller Icons ; Icon "nim.ico" ; UninstallIcon "nim.ico" ; Set installation details to be shown by default ShowInstDetails show ShowUnInstDetails show ;-------------------------------- ; Interface Settings ; Warn the user if aborting during installation/uninstallation !define MUI_ABORTWARNING !define MUI_UNABORTWARNING ; Don't show a description for sections !define MUI_COMPONENTSPAGE_NODESC ;-------------------------------- ; Pages ; Setup the installer pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "?{expandFilename(c.license)}" !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY ; Setup the start menu entry page var ICONS_GROUP !define MUI_STARTMENUPAGE_DEFAULTFOLDER "?{c.displayName}" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}" !define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}" !insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH ; Setup the uninstaller pages !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ;Installer Sections ; The core section. This is comprised of a base Nim installation, ; such as what would be retrieved via git, and an already bootstrapped ; Nim binary. Section "Core Files" CoreSection ; This is a mandotory section SectionIn RO ; Output files to the base installation directory SetOutPath "$INSTDIR" ; Only overwrite newer files SetOverwrite ifnewer ; Write all the files to the output directory. #for i in low(FileCategory)..fcWindows: # for f in items(c.cat[i]): SetOutPath "$INSTDIR\?{splitFile(f).dir.toWin}" File "?{expandFilename(f).toWin}" # end for #end for ; Write out the uninstaller WriteUninstaller "$INSTDIR\uninstaller.exe" SectionEnd Section "-Add Registry Keys" RegistrySection ; Write application registry keys WriteRegStr HKCU "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\bin\?{c.name}.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninstaller.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\?{c.name}.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" ; Reset the output path SetOutPath "$INSTDIR" SectionEnd ; Section for adding the shortcuts related to files and applications Section "-Setup Shortcuts" ShortcutsSection !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory "$SMPROGRAMS\$ICONS_GROUP" #if c.app == appConsole: CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{c.displayName}.lnk" "$INSTDIR\start.bat" CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\start.bat" #else: CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe" CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe" #end if ; Write the shortcut to the uninstaller CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninstaller.exe" !insertmacro MUI_STARTMENU_WRITE_END SectionEnd ; Section for adding tools to the PATH variable Section "Setup Path Environment" PathSection Push "$INSTDIR\bin" Call AddToPath Push "$INSTDIR\dist\mingw" Call AddToPath Push "$INSTDIR\dist\mingw\bin" Call AddToPath Push "$PROFILE\.nimble\bin" Call AddToPath SectionEnd ; The downloadable sections. These sections are automatically generated by ; niminst and the template filters. #var i = 0 #for download in c.downloads: # inc i # let d = download.split('|') # if d.len != 5 and d.len != 6: # quit("download string needs 5..6 parts: " & download) # end if # let sectionName = d[0] # let dir = d[1] # let zipName = d[2] # let size = d[3] # let url = d[4] Section /o "?sectionName" ?{i}Section ; Add the section size to the total size. AddSize ?size ; Download the file, and if successful, extract it to the given directory ; otherwise, retry: NSISdl::download "?url" "$TEMP\?zipName" Pop $0 ${If} $0 == "success" ZipDLL::extractall "$TEMP\?zipName" "$INSTDIR\?dir" Delete "$TEMP\?zipName" ${ElseIf} $0 == "cancel" MessageBox MB_ICONQUESTION|MB_YESNO|MB_TOPMOST \ "Download of component '?sectionName' cancelled. Continue installation process??" \ IDYES ignore abort ${Else} MessageBox MB_ICONSTOP|MB_ABORTRETRYIGNORE|MB_TOPMOST "Error: $0" \ IDRETRY retry IDIGNORE ignore abort ${EndIf} ; Shortcuts # if d.len >= 6: # let startMenuEntry = d[5] # let e = splitFile(startMenuEntry).name.capitalizeAscii !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{e}.lnk" "$INSTDIR\?dir\?{startMenuEntry.toWin}" !insertmacro MUI_STARTMENU_WRITE_END # end if ignore: SectionEnd #end ;-------------------------------- ; Section Descriptions ; Series of strings describing each section ; LangString DESC_CoreSection ${LANG_ENGLISH} "Core Nim files" ; The macros to actually insert the descriptions into the sections. ; Each description above should have a corresponding MUI_DESCRIPTION_TEXT ; macro linking the section to the description. ; !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN ; !insertmacro MUI_DESCRIPTION_TEXT ${CoreSection} $(DESC_CoreSection) ; !insertmacro MUI_FUNCTION_DESCRIPTION_END ;-------------------------------- ; Uninstaller Sections Section "Uninstall" ; Remove previously created shortcuts !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP Delete "$DESKTOP\?{c.displayName}.lnk" ; Remove installed application files RMDir /r "$SMPROGRAMS\$ICONS_GROUP" RMDir /r "$INSTDIR" ; Remove the previously created registry key DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" DeleteRegKey HKCU "${PRODUCT_DIR_REGKEY}" SetAutoClose true ; Remove entries from the PATH environment variable Push "$INSTDIR\bin" Call un.RemoveFromPath Push "$INSTDIR\dist\mingw" Call un.RemoveFromPath Push "$INSTDIR\dist\mingw\bin" Call un.RemoveFromPath Push "$PROFILE\.nimble\bin" Call un.RemoveFromPath SectionEnd ;-------------------------------- ; Function hooks Function .onInit ${GetRoot} "$EXEDIR" $R0 strCpy $INSTDIR "$R0\?{c.name}" FunctionEnd ;-------------------------------------------------------------------- ; Path functions ; ; Based on example from: ; http://nsis.sourceforge.net/Path_Manipulation ; ; Actually based on: ; https://www.smartmontools.org/browser/trunk/smartmontools/os_win32/installer.nsi#L636 !include "WinMessages.nsh" ; Registry Entry for environment (NT4,2000,XP) ; All users: ;!define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' ; Current user only: !define Environ 'HKCU "Environment"' ; AddToPath - Appends dir to PATH ; (does not work on Win9x/ME) ; ; Usage: ; Push "dir" ; Call AddToPath Function AddToPath Exch $0 Push $1 Push $2 Push $3 Push $4 ; NSIS ReadRegStr returns empty string on string overflow ; Native calls are used here to check actual length of PATH ; $4 = RegOpenKey(HKEY_CURRENT_USER, "Environment", &$3) System::Call "advapi32::RegOpenKey(i 0x80000001, t'Environment', *i.r3) i.r4" IntCmp $4 0 0 done done ; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2)) ; RegCloseKey($3) System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4" System::Call "advapi32::RegCloseKey(i $3)" IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}" MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}" Goto done IntCmp $4 0 +5 ; $4 != NO_ERROR IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND DetailPrint "AddToPath: unexpected error code $4" Goto done StrCpy $1 "" ; Check if already in PATH Push "$1;" Push "$0;" Call StrStr Pop $2 StrCmp $2 "" 0 done Push "$1;" Push "$0\;" Call StrStr Pop $2 StrCmp $2 "" 0 done ; Prevent NSIS string overflow StrLen $2 $0 StrLen $3 $1 IntOp $2 $2 + $3 IntOp $2 $2 + 2 ; $2 = strlen(dir) + strlen(PATH) + sizeof(";") IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0 DetailPrint "AddToPath: new length $2 > ${NSIS_MAX_STRLEN}" MessageBox MB_OK "PATH not updated, new length $2 > ${NSIS_MAX_STRLEN}." Goto done ; Append dir to PATH DetailPrint "Add to PATH: $0" StrCpy $2 $1 1 -1 StrCmp $2 ";" 0 +2 StrCpy $1 $1 -1 ; remove trailing ';' StrCmp $1 "" +2 ; no leading ';' StrCpy $0 "$1;$0" WriteRegExpandStr ${Environ} "PATH" $0 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 done: Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; RemoveFromPath - Removes dir from PATH ; ; Usage: ; Push "dir" ; Call RemoveFromPath Function un.RemoveFromPath Exch $0 Push $1 Push $2 Push $3 Push $4 Push $5 Push $6 ReadRegStr $1 ${Environ} "PATH" StrCpy $5 $1 1 -1 StrCmp $5 ";" +2 StrCpy $1 "$1;" ; ensure trailing ';' Push $1 Push "$0;" Call un.StrStr Pop $2 ; pos of our dir StrCmp $2 "" done DetailPrint "Remove from PATH: $0" StrLen $3 "$0;" StrLen $4 $2 StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove StrCpy $3 "$5$6" StrCpy $5 $3 1 -1 StrCmp $5 ";" 0 +2 StrCpy $3 $3 -1 ; remove trailing ';' WriteRegExpandStr ${Environ} "PATH" $3 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 done: Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; StrStr - find substring in a string ; ; Usage: ; Push "this is some string" ; Push "some" ; Call StrStr ; Pop $0 ; "some string" !macro StrStr un Function ${un}StrStr Exch $R1 ; $R1=substring, stack=[old$R1,string,...] Exch ; stack=[string,old$R1,...] Exch $R2 ; $R2=string, stack=[old$R2,old$R1,...] Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 ; $R1=substring, $R2=string, $R3=strlen(substring) ; $R4=count, $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 ; $R1=old$R1, stack=[result,...] FunctionEnd !macroend !insertmacro StrStr "" !insertmacro StrStr "un."