Files
Hein c277171963
CI / Test (push) Successful in 28s
CI / Build (push) Successful in 25s
feat(pkg-nsis): add Windows installer workflow
2026-07-01 18:01:25 +02:00

227 lines
6.1 KiB
NSIS

; 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