; PgTidy Windows installer ; ; Build with (VERSION must match the release tag, without the leading "v"): ; makensis /DVERSION=1.2.3 /DSRC_EXE=path\to\pgtidy.exe windows\installer.nsi ; ; Installs pgtidy.exe into Program Files, adds the install dir to the ; machine-wide PATH, and on startup checks the git.warky.dev Gitea API for a ; newer release than the one being installed. !ifndef VERSION !define VERSION "0.0.0" !endif !ifndef SRC_EXE !define SRC_EXE "..\dist\pgtidy.exe" !endif !define PRODUCT_NAME "PgTidy" !define PRODUCT_PUBLISHER "Warky Devs" !define PRODUCT_HOMEPAGE "https://git.warky.dev/wdevs/pgtidy" !define RELEASES_API_URL "https://git.warky.dev/api/v1/repos/wdevs/pgtidy/releases/latest" !define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\PgTidy" !define ENV_KEY 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !include "MUI2.nsh" !include "LogicLib.nsh" Name "${PRODUCT_NAME} ${VERSION}" OutFile "pgtidy-setup-${VERSION}.exe" InstallDir "$PROGRAMFILES64\PgTidy" InstallDirRegKey HKLM "${UNINST_KEY}" "InstallLocation" RequestExecutionLevel admin Unicode true !define MUI_ABORTWARNING !define MUI_ICON "..\assets\logo_128.ico" !define MUI_UNICON "..\assets\logo_128.ico" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "..\LICENSE" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_LANGUAGE "English" ; --------------------------------------------------------------------------- ; Check the Gitea releases API for a newer version than the one we are about ; to install. Best-effort only: any failure (offline, API down, no ; PowerShell) is swallowed and the installer proceeds silently. ; --------------------------------------------------------------------------- Function .onInit StrCpy $1 "$TEMP\pgtidy-latest-version.txt" Delete "$1" DetailPrint "Checking ${PRODUCT_HOMEPAGE} for a newer release..." nsExec::ExecToLog 'powershell -NoProfile -NonInteractive -Command "try { $$r = Invoke-RestMethod -Uri ''${RELEASES_API_URL}'' -UseBasicParsing -TimeoutSec 5; $$r.tag_name | Out-File -Encoding ascii -NoNewline ''$1'' } catch { exit 0 }"' ${IfNot} ${FileExists} "$1" Return ${EndIf} FileOpen $2 "$1" r FileRead $2 $3 FileClose $2 Delete "$1" StrCpy $4 $3 ; Trim a leading "v" if the tag is e.g. "v1.2.3" StrCpy $5 $4 1 ${If} $5 == "v" StrCpy $4 $4 "" 1 ${EndIf} ${If} $4 != "" ${AndIf} $4 != "${VERSION}" MessageBox MB_YESNO|MB_ICONINFORMATION \ "A newer version of PgTidy is available: $4 (this installer is ${VERSION}).$\n$\nOpen the releases page to download it now?$\n$\nChoosing No continues installing ${VERSION}." \ IDNO +2 ExecShell "open" "${PRODUCT_HOMEPAGE}/releases/latest" ${EndIf} FunctionEnd ; --------------------------------------------------------------------------- ; Adds $INSTDIR to the machine PATH if it isn't already present. ; --------------------------------------------------------------------------- Function AddToPath ReadRegStr $0 ${ENV_KEY} "Path" Push "$0" Push "$INSTDIR" Call StrContains Pop $1 ${If} $1 == "" ${If} $0 == "" StrCpy $0 "$INSTDIR" ${Else} StrCpy $0 "$0;$INSTDIR" ${EndIf} WriteRegExpandStr ${ENV_KEY} "Path" "$0" SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 ${EndIf} FunctionEnd ; --------------------------------------------------------------------------- ; Removes $INSTDIR from the machine PATH. ; --------------------------------------------------------------------------- Function un.RemoveFromPath ReadRegStr $0 ${ENV_KEY} "Path" Push "$0;" Push "$INSTDIR;" Push "" Call un.StrReplace Pop $0 Push "$0" Push "$INSTDIR" Push "" Call un.StrReplace Pop $0 ; Drop a trailing separator left behind by the replacements above. StrCpy $1 $0 1 -1 ${If} $1 == ";" StrCpy $0 $0 -1 ${EndIf} WriteRegExpandStr ${ENV_KEY} "Path" "$0" SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 FunctionEnd ; Returns the index of needle in haystack via $R0, or "" if absent. ; Push haystack, Push needle -> Pop result Function StrContains Exch $R1 ; needle Exch Exch $R2 ; haystack Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 ${Do} StrCpy $R5 $R2 $R3 $R4 ${If} $R5 == $R1 StrCpy $R0 $R4 ${ExitDo} ${EndIf} ${If} $R5 == "" StrCpy $R0 "" ${ExitDo} ${EndIf} IntOp $R4 $R4 + 1 ${Loop} Pop $R5 Pop $R4 Pop $R3 Pop $R2 Pop $R1 Push $R0 Exch Pop $R0 FunctionEnd ; Push string, Push search, Push replace -> Pop result Function un.StrReplace Exch $R0 ; replace Exch Exch $R1 ; search Exch 2 Exch $R2 ; string Push $R3 Push $R4 Push $R5 Push $R6 StrLen $R3 $R1 StrCpy $R4 "" ${Do} StrCpy $R5 $R2 $R3 ${If} $R5 == $R1 StrCpy $R4 "$R4$R0" StrCpy $R2 $R2 "" $R3 ${ElseIf} $R2 == "" ${ExitDo} ${Else} StrCpy $R6 $R2 1 StrCpy $R4 "$R4$R6" StrCpy $R2 $R2 "" 1 ${EndIf} ${Loop} Pop $R6 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Pop $R1 Pop $R0 Push $R4 FunctionEnd Section "PgTidy" SEC_MAIN SectionIn RO SetOutPath "$INSTDIR" File "${SRC_EXE}" File "..\LICENSE" Call AddToPath WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}" WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${VERSION}" WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" WriteRegStr HKLM "${UNINST_KEY}" "InstallLocation" "$INSTDIR" WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$INSTDIR\uninstall.exe /S" WriteRegDWORD HKLM "${UNINST_KEY}" "NoModify" 1 WriteRegDWORD HKLM "${UNINST_KEY}" "NoRepair" 1 WriteUninstaller "$INSTDIR\uninstall.exe" SectionEnd Section "Uninstall" Call un.RemoveFromPath Delete "$INSTDIR\pgtidy.exe" Delete "$INSTDIR\LICENSE" Delete "$INSTDIR\uninstall.exe" RMDir "$INSTDIR" DeleteRegKey HKLM "${UNINST_KEY}" SectionEnd