223 lines
9.1 KiB
NSIS
223 lines
9.1 KiB
NSIS
|
|
;
|
||
|
|
; NSIS installer for QuickSearch.
|
||
|
|
;
|
||
|
|
; Compiled by packaging/build-installer.sh, which supplies every define below
|
||
|
|
; and stages the files this installs. Running makensis on this file by hand
|
||
|
|
; will fail on the !error checks rather than build something half-configured.
|
||
|
|
;
|
||
|
|
; VERSION workspace version, e.g. 0.9.1
|
||
|
|
; VERSION_QUAD the same padded to a.b.c.d, which is all VIProductVersion takes
|
||
|
|
; STAGE directory holding the exact files to install
|
||
|
|
; OUTFILE path of the installer to write
|
||
|
|
;
|
||
|
|
; makensis runs on Linux, so the installer comes out of the same cross-compile
|
||
|
|
; job as the .zip and no Windows machine is involved anywhere in the pipeline.
|
||
|
|
; That also means file paths below use forward slashes: they are read by
|
||
|
|
; makensis on the build host, unlike $INSTDIR paths, which are Windows strings.
|
||
|
|
|
||
|
|
!ifndef VERSION | VERSION_QUAD | STAGE | OUTFILE
|
||
|
|
!error "build this with packaging/build-installer.sh, which defines VERSION, VERSION_QUAD, STAGE and OUTFILE"
|
||
|
|
!endif
|
||
|
|
|
||
|
|
Unicode true
|
||
|
|
; The payload is two ~20 MB binaries; solid LZMA is worth the compression time.
|
||
|
|
SetCompressor /SOLID lzma
|
||
|
|
|
||
|
|
!include "MUI2.nsh"
|
||
|
|
!include "LogicLib.nsh"
|
||
|
|
!include "FileFunc.nsh"
|
||
|
|
!include "x64.nsh"
|
||
|
|
|
||
|
|
!define APP "QuickSearch"
|
||
|
|
!define PUBLISHER "Jeremy <jeremy@karsttech.com>"
|
||
|
|
!define HOMEPAGE "https://code.karsttech.com/jeremy/quick_search"
|
||
|
|
; Where Add/Remove Programs looks, and where an upgrade finds the directory the
|
||
|
|
; previous version went into.
|
||
|
|
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP}"
|
||
|
|
|
||
|
|
Name "${APP} ${VERSION}"
|
||
|
|
OutFile "${OUTFILE}"
|
||
|
|
InstallDir "$PROGRAMFILES64\${APP}"
|
||
|
|
; Program Files and HKLM both need elevation, and it is what puts the shortcuts
|
||
|
|
; in front of every account on the machine rather than just the installing one.
|
||
|
|
RequestExecutionLevel admin
|
||
|
|
ShowInstDetails show
|
||
|
|
ShowUninstDetails show
|
||
|
|
|
||
|
|
VIProductVersion "${VERSION_QUAD}"
|
||
|
|
VIAddVersionKey "ProductName" "${APP}"
|
||
|
|
VIAddVersionKey "ProductVersion" "${VERSION}"
|
||
|
|
VIAddVersionKey "FileVersion" "${VERSION_QUAD}"
|
||
|
|
VIAddVersionKey "CompanyName" "${PUBLISHER}"
|
||
|
|
VIAddVersionKey "LegalCopyright" "GPL-3.0-or-later"
|
||
|
|
VIAddVersionKey "FileDescription" "${APP} ${VERSION} installer"
|
||
|
|
|
||
|
|
!define MUI_ABORTWARNING
|
||
|
|
!define MUI_ICON "${STAGE}/quicksearch.ico"
|
||
|
|
!define MUI_UNICON "${STAGE}/quicksearch.ico"
|
||
|
|
|
||
|
|
!insertmacro MUI_PAGE_WELCOME
|
||
|
|
!insertmacro MUI_PAGE_LICENSE "${STAGE}/LICENSE.txt"
|
||
|
|
!insertmacro MUI_PAGE_COMPONENTS
|
||
|
|
!insertmacro MUI_PAGE_DIRECTORY
|
||
|
|
!insertmacro MUI_PAGE_INSTFILES
|
||
|
|
!define MUI_FINISHPAGE_RUN
|
||
|
|
!define MUI_FINISHPAGE_RUN_TEXT "Run ${APP}"
|
||
|
|
!define MUI_FINISHPAGE_RUN_FUNCTION LaunchAsUser
|
||
|
|
!insertmacro MUI_PAGE_FINISH
|
||
|
|
|
||
|
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||
|
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||
|
|
|
||
|
|
!insertmacro MUI_LANGUAGE "English"
|
||
|
|
|
||
|
|
; ------------------------------------------------------------------ init ----
|
||
|
|
|
||
|
|
Function .onInit
|
||
|
|
${IfNot} ${RunningX64}
|
||
|
|
MessageBox MB_OK|MB_ICONSTOP \
|
||
|
|
"${APP} is 64-bit only and this is a 32-bit Windows installation." /SD IDOK
|
||
|
|
Abort
|
||
|
|
${EndIf}
|
||
|
|
; The installer stub is 32-bit (it runs anywhere), so without this every
|
||
|
|
; HKLM write below would be redirected into Wow6432Node - out of sight of
|
||
|
|
; 64-bit Add/Remove Programs and of the lookup two lines down.
|
||
|
|
SetRegView 64
|
||
|
|
; Shortcuts and the uninstall entry are machine-wide, matching where the
|
||
|
|
; files go.
|
||
|
|
SetShellVarContext all
|
||
|
|
|
||
|
|
; Deliberately not InstallDirRegKey: that is read before .onInit runs, which
|
||
|
|
; is before SetRegView 64, so it would look in the wrong registry view.
|
||
|
|
; $INSTDIR still holds the InstallDir default unless /D= overrode it on the
|
||
|
|
; command line, and an explicit /D= must win over the previous location.
|
||
|
|
${If} $INSTDIR == "$PROGRAMFILES64\${APP}"
|
||
|
|
ReadRegStr $0 HKLM "${UNINST_KEY}" "InstallLocation"
|
||
|
|
${If} $0 != ""
|
||
|
|
StrCpy $INSTDIR $0
|
||
|
|
${EndIf}
|
||
|
|
${EndIf}
|
||
|
|
FunctionEnd
|
||
|
|
|
||
|
|
Function un.onInit
|
||
|
|
SetRegView 64
|
||
|
|
SetShellVarContext all
|
||
|
|
FunctionEnd
|
||
|
|
|
||
|
|
; -------------------------------------------------------------- sections ----
|
||
|
|
|
||
|
|
Section "!${APP}" SecApp
|
||
|
|
SectionIn RO
|
||
|
|
SetOutPath "$INSTDIR"
|
||
|
|
|
||
|
|
; Windows will not replace a running executable, and the File commands below
|
||
|
|
; would stop halfway through with a write error. Delete fails on a mapped
|
||
|
|
; image and succeeds quietly when there is nothing there, which makes it a
|
||
|
|
; plugin-free "is it still running?" test.
|
||
|
|
ClearErrors
|
||
|
|
Delete "$INSTDIR\quicksearch.exe"
|
||
|
|
Delete "$INSTDIR\quicksearch-cli.exe"
|
||
|
|
${If} ${Errors}
|
||
|
|
MessageBox MB_OK|MB_ICONSTOP \
|
||
|
|
"${APP} is still running. Close it and start this installer again." /SD IDOK
|
||
|
|
Abort
|
||
|
|
${EndIf}
|
||
|
|
|
||
|
|
File "${STAGE}/quicksearch.exe"
|
||
|
|
File "${STAGE}/quicksearch-cli.exe"
|
||
|
|
File "${STAGE}/quicksearch.ico"
|
||
|
|
File "${STAGE}/README.md"
|
||
|
|
File "${STAGE}/LICENSE.txt"
|
||
|
|
File "${STAGE}/config_example.toml"
|
||
|
|
; No config.toml is installed, for the same reason the .deb ships none: one
|
||
|
|
; sitting next to the binary is portable mode, and it would override the
|
||
|
|
; personal config of every account on the machine. The app writes
|
||
|
|
; %APPDATA%\quicksearch\config.toml on first run instead.
|
||
|
|
|
||
|
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||
|
|
|
||
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${APP}"
|
||
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${VERSION}"
|
||
|
|
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\quicksearch.ico"
|
||
|
|
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${PUBLISHER}"
|
||
|
|
WriteRegStr HKLM "${UNINST_KEY}" "URLInfoAbout" "${HOMEPAGE}"
|
||
|
|
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
|
||
|
|
; Add/Remove Programs reads this as a DWORD of kilobytes, which is exactly
|
||
|
|
; what /S=0K returns.
|
||
|
|
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
|
||
|
|
IntFmt $0 "0x%08X" $0
|
||
|
|
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" $0
|
||
|
|
SectionEnd
|
||
|
|
|
||
|
|
Section "Start Menu shortcut" SecStartMenu
|
||
|
|
; One shortcut, no program folder: a single-application folder is noise in
|
||
|
|
; the Windows 10/11 Start menu, and the uninstaller lives in Add/Remove
|
||
|
|
; Programs rather than next to it.
|
||
|
|
CreateShortcut "$SMPROGRAMS\${APP}.lnk" "$INSTDIR\quicksearch.exe" "" "$INSTDIR\quicksearch.ico"
|
||
|
|
SectionEnd
|
||
|
|
|
||
|
|
Section /o "Desktop shortcut" SecDesktop
|
||
|
|
CreateShortcut "$DESKTOP\${APP}.lnk" "$INSTDIR\quicksearch.exe" "" "$INSTDIR\quicksearch.ico"
|
||
|
|
SectionEnd
|
||
|
|
|
||
|
|
; There is deliberately no "add to PATH" section, tempting as one is for
|
||
|
|
; quicksearch-cli. Editing PATH means reading the machine value, appending and
|
||
|
|
; writing it back, and NSIS strings in the standard build are capped at
|
||
|
|
; NSIS_MAX_STRLEN (1024 characters, `makensis -HDRINFO`). ReadRegStr truncates
|
||
|
|
; silently at that cap, so on any machine with a long PATH the write-back would
|
||
|
|
; destroy the rest of it - a spectacular failure for an optional checkbox. The
|
||
|
|
; README tells people to add the directory themselves.
|
||
|
|
|
||
|
|
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||
|
|
!insertmacro MUI_DESCRIPTION_TEXT ${SecApp} \
|
||
|
|
"The desktop app and quicksearch-cli, the terminal search tool."
|
||
|
|
!insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} \
|
||
|
|
"Add ${APP} to the Start menu for all users."
|
||
|
|
!insertmacro MUI_DESCRIPTION_TEXT ${SecDesktop} \
|
||
|
|
"Add a ${APP} shortcut to the desktop."
|
||
|
|
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||
|
|
|
||
|
|
; The installer is elevated and anything it starts inherits that. Handing the
|
||
|
|
; path to the already-running Explorer starts the app as the logged-on user
|
||
|
|
; instead, so a first run creates its config and index in the right profile.
|
||
|
|
Function LaunchAsUser
|
||
|
|
Exec '"$WINDIR\explorer.exe" "$INSTDIR\quicksearch.exe"'
|
||
|
|
FunctionEnd
|
||
|
|
|
||
|
|
; ----------------------------------------------------------- uninstaller ----
|
||
|
|
|
||
|
|
Section "Uninstall"
|
||
|
|
; Same running-process test as the install side. Stopping here leaves the
|
||
|
|
; installation intact rather than gutted.
|
||
|
|
ClearErrors
|
||
|
|
Delete "$INSTDIR\quicksearch.exe"
|
||
|
|
Delete "$INSTDIR\quicksearch-cli.exe"
|
||
|
|
${If} ${Errors}
|
||
|
|
MessageBox MB_OK|MB_ICONSTOP \
|
||
|
|
"${APP} is still running. Close it and try again." /SD IDOK
|
||
|
|
Abort
|
||
|
|
${EndIf}
|
||
|
|
|
||
|
|
Delete "$INSTDIR\quicksearch.ico"
|
||
|
|
Delete "$INSTDIR\README.md"
|
||
|
|
Delete "$INSTDIR\LICENSE.txt"
|
||
|
|
Delete "$INSTDIR\config_example.toml"
|
||
|
|
Delete "$INSTDIR\uninstall.exe"
|
||
|
|
Delete "$SMPROGRAMS\${APP}.lnk"
|
||
|
|
Delete "$DESKTOP\${APP}.lnk"
|
||
|
|
; Plain RMDir, never /r: a portable-mode config.toml and the index beside it
|
||
|
|
; may be sitting in this directory, and neither is ours to delete. A
|
||
|
|
; directory holding anything the installer did not put there simply stays.
|
||
|
|
RMDir "$INSTDIR"
|
||
|
|
|
||
|
|
DeleteRegKey HKLM "${UNINST_KEY}"
|
||
|
|
; The per-user config in %APPDATA%\quicksearch and the index in
|
||
|
|
; %LOCALAPPDATA%\quicksearch are left alone, the way apt leaves ~/.config
|
||
|
|
; alone: reinstalling picks up where the last install left off, and nobody
|
||
|
|
; loses an index to an upgrade.
|
||
|
|
SectionEnd
|