Added windows installer
This commit is contained in:
parent
9621a23c79
commit
e19c9509d3
BIN
dist/livetrace-3.3.2-setup.exe
vendored
Normal file
BIN
dist/livetrace-3.3.2-setup.exe
vendored
Normal file
Binary file not shown.
30
installer/Dockerfile.installer
Normal file
30
installer/Dockerfile.installer
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Dockerfile.installer
|
||||||
|
# Builds the livetrace Windows installer (.exe) using NSIS on Linux.
|
||||||
|
#
|
||||||
|
# Usage (from your project root):
|
||||||
|
# docker build -f Dockerfile.installer -t livetrace-installer .
|
||||||
|
# docker run --rm -v "$PWD/dist":/out livetrace-installer
|
||||||
|
#
|
||||||
|
# The finished installer lands at ./dist/livetrace-3.3.2-setup.exe
|
||||||
|
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
# Install NSIS (makensis) — no Go needed, binary is pre-built
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends nsis && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy the NSIS script and helper
|
||||||
|
COPY installer/livetrace-installer.nsi .
|
||||||
|
COPY installer/EnvVarUpdate.nsh .
|
||||||
|
|
||||||
|
# Copy the pre-built Windows binary from dist/
|
||||||
|
COPY dist/livetrace-windows-amd64.exe .
|
||||||
|
|
||||||
|
# Build the installer
|
||||||
|
RUN makensis livetrace-installer.nsi
|
||||||
|
|
||||||
|
# Default: copy the output to /out (bind-mount your dist/ folder there)
|
||||||
|
CMD ["sh", "-c", "cp livetrace-*.exe /out/ && echo 'Installer written to /out/'"]
|
||||||
142
installer/EnvVarUpdate.nsh
Normal file
142
installer/EnvVarUpdate.nsh
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
; EnvVarUpdate.nsh
|
||||||
|
; Adds/removes a value from a Windows environment variable (PATH-style, semicolon-delimited)
|
||||||
|
; Usage:
|
||||||
|
; ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR" ; append
|
||||||
|
; ${UnEnvVarUpdate} $0 "PATH" "HKLM" "$INSTDIR" ; remove
|
||||||
|
|
||||||
|
!ifndef ENVVARUPDATE_NSH
|
||||||
|
!define ENVVARUPDATE_NSH
|
||||||
|
|
||||||
|
!include "LogicLib.nsh"
|
||||||
|
!include "WinMessages.nsh"
|
||||||
|
|
||||||
|
; --------------------------------------------------------------------------
|
||||||
|
; Macro: _EnvVarUpdate
|
||||||
|
; Action: "A" = Append, "P" = Prepend, "R" = Remove
|
||||||
|
; --------------------------------------------------------------------------
|
||||||
|
!macro _EnvVarUpdate OUTVAR EnvVarName Action RegLoc PathString
|
||||||
|
|
||||||
|
Push $0
|
||||||
|
Push $1
|
||||||
|
Push $2
|
||||||
|
Push $3
|
||||||
|
Push $4
|
||||||
|
Push $5
|
||||||
|
|
||||||
|
; Read current value
|
||||||
|
ReadRegStr $1 ${RegLoc} \
|
||||||
|
"SYSTEM\CurrentControlSet\Control\Session Manager\Environment" \
|
||||||
|
"${EnvVarName}"
|
||||||
|
|
||||||
|
; Strip trailing semicolon
|
||||||
|
StrCpy $5 $1 1 -1
|
||||||
|
${If} $5 == ";"
|
||||||
|
StrCpy $1 $1 -1
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
; Check if PathString already exists
|
||||||
|
Push "${PathString}"
|
||||||
|
Push $1
|
||||||
|
Call _EnvVarUpdateStrStr
|
||||||
|
Pop $2 ; $2 = position, or "" if not found
|
||||||
|
|
||||||
|
${If} "${Action}" == "A"
|
||||||
|
${If} $2 == ""
|
||||||
|
${If} $1 == ""
|
||||||
|
StrCpy $3 "${PathString}"
|
||||||
|
${Else}
|
||||||
|
StrCpy $3 "$1;${PathString}"
|
||||||
|
${EndIf}
|
||||||
|
WriteRegExpandStr ${RegLoc} \
|
||||||
|
"SYSTEM\CurrentControlSet\Control\Session Manager\Environment" \
|
||||||
|
"${EnvVarName}" "$3"
|
||||||
|
${EndIf}
|
||||||
|
${ElseIf} "${Action}" == "P"
|
||||||
|
${If} $2 == ""
|
||||||
|
${If} $1 == ""
|
||||||
|
StrCpy $3 "${PathString}"
|
||||||
|
${Else}
|
||||||
|
StrCpy $3 "${PathString};$1"
|
||||||
|
${EndIf}
|
||||||
|
WriteRegExpandStr ${RegLoc} \
|
||||||
|
"SYSTEM\CurrentControlSet\Control\Session Manager\Environment" \
|
||||||
|
"${EnvVarName}" "$3"
|
||||||
|
${EndIf}
|
||||||
|
${ElseIf} "${Action}" == "R"
|
||||||
|
${If} $2 != ""
|
||||||
|
; Remove entry
|
||||||
|
StrLen $4 "${PathString}"
|
||||||
|
StrCpy $0 $1 $2 ; everything before the match
|
||||||
|
IntOp $4 $2 + $4 ; position after the match
|
||||||
|
StrCpy $5 $1 "" $4 ; everything after the match
|
||||||
|
; Strip leading/trailing semicolons from join point
|
||||||
|
StrCpy $4 $5 1
|
||||||
|
${If} $4 == ";"
|
||||||
|
StrCpy $5 $5 "" 1
|
||||||
|
${EndIf}
|
||||||
|
StrCpy $4 $0 1 -1
|
||||||
|
${If} $4 == ";"
|
||||||
|
StrCpy $0 $0 -1
|
||||||
|
${EndIf}
|
||||||
|
${If} $0 == ""
|
||||||
|
StrCpy $3 $5
|
||||||
|
${ElseIf} $5 == ""
|
||||||
|
StrCpy $3 $0
|
||||||
|
${Else}
|
||||||
|
StrCpy $3 "$0;$5"
|
||||||
|
${EndIf}
|
||||||
|
WriteRegExpandStr ${RegLoc} \
|
||||||
|
"SYSTEM\CurrentControlSet\Control\Session Manager\Environment" \
|
||||||
|
"${EnvVarName}" "$3"
|
||||||
|
${EndIf}
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
; Broadcast change to all windows
|
||||||
|
SendMessage ${HWND_BROADCAST} ${WM_SETTINGCHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||||
|
|
||||||
|
Pop $5
|
||||||
|
Pop $4
|
||||||
|
Pop $3
|
||||||
|
Pop $2
|
||||||
|
Pop $1
|
||||||
|
Pop $0
|
||||||
|
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
; Helper: find substring position (returns "" if not found)
|
||||||
|
Function _EnvVarUpdateStrStr
|
||||||
|
Exch $R0 ; haystack
|
||||||
|
Exch
|
||||||
|
Exch $R1 ; needle
|
||||||
|
Push $R2
|
||||||
|
Push $R3
|
||||||
|
Push $R4
|
||||||
|
Push $R5
|
||||||
|
StrLen $R3 $R1
|
||||||
|
StrLen $R4 $R0
|
||||||
|
IntOp $R4 $R4 - $R3
|
||||||
|
StrCpy $R2 0
|
||||||
|
loop:
|
||||||
|
IntCmp $R2 $R4 done done
|
||||||
|
StrCpy $R5 $R0 $R3 $R2
|
||||||
|
StrCmp $R5 $R1 found
|
||||||
|
IntOp $R2 $R2 + 1
|
||||||
|
Goto loop
|
||||||
|
found:
|
||||||
|
StrCpy $R0 $R2
|
||||||
|
Goto end
|
||||||
|
done:
|
||||||
|
StrCpy $R0 ""
|
||||||
|
end:
|
||||||
|
Pop $R5
|
||||||
|
Pop $R4
|
||||||
|
Pop $R3
|
||||||
|
Pop $R2
|
||||||
|
Pop $R1
|
||||||
|
Exch $R0
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
!define EnvVarUpdate `!insertmacro _EnvVarUpdate`
|
||||||
|
!define UnEnvVarUpdate `!insertmacro _EnvVarUpdate "" "${__LINE__}" "R"`
|
||||||
|
|
||||||
|
!endif ; ENVVARUPDATE_NSH
|
||||||
62
installer/build-installer.sh
Executable file
62
installer/build-installer.sh
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# build-installer.sh
|
||||||
|
# Builds livetrace-3.3.2-setup.exe on Linux — natively or via Docker.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./installer/build-installer.sh # requires: apt install nsis
|
||||||
|
# ./installer/build-installer.sh --docker # requires: docker
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
VERSION="3.3.2"
|
||||||
|
OUTPUT="livetrace-${VERSION}-setup.exe"
|
||||||
|
|
||||||
|
# ── Docker build ───────────────────────────────────────────────────────────
|
||||||
|
if [[ "${1:-}" == "--docker" ]]; then
|
||||||
|
echo ">>> Building installer via Docker …"
|
||||||
|
docker build \
|
||||||
|
-f "${SCRIPT_DIR}/Dockerfile.installer" \
|
||||||
|
-t livetrace-installer \
|
||||||
|
"${PROJECT_ROOT}"
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
-v "${PROJECT_ROOT}/dist":/out \
|
||||||
|
livetrace-installer
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Done: ${PROJECT_ROOT}/dist/${OUTPUT}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Native build ───────────────────────────────────────────────────────────
|
||||||
|
if ! command -v makensis &>/dev/null; then
|
||||||
|
echo "ERROR: makensis not found."
|
||||||
|
echo " Install: sudo apt install nsis"
|
||||||
|
echo " Or run: $0 --docker"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SRC_EXE="${PROJECT_ROOT}/dist/livetrace-windows-amd64.exe"
|
||||||
|
if [[ ! -f "${SRC_EXE}" ]]; then
|
||||||
|
echo "ERROR: ${SRC_EXE} not found."
|
||||||
|
echo " Run your Go build first, e.g.:"
|
||||||
|
echo " GOOS=windows GOARCH=amd64 go build -o dist/livetrace-windows-amd64.exe ./src"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ">>> Building installer with makensis …"
|
||||||
|
# Copy binary next to the .nsi script so NSIS can find it
|
||||||
|
cp "${SRC_EXE}" "${SCRIPT_DIR}/livetrace-windows-amd64.exe"
|
||||||
|
|
||||||
|
cd "${SCRIPT_DIR}"
|
||||||
|
makensis livetrace-installer.nsi
|
||||||
|
|
||||||
|
# Move the output to dist/
|
||||||
|
mv "${SCRIPT_DIR}/${OUTPUT}" "${PROJECT_ROOT}/dist/${OUTPUT}"
|
||||||
|
rm -f "${SCRIPT_DIR}/livetrace-windows-amd64.exe"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Done: ${PROJECT_ROOT}/dist/${OUTPUT}"
|
||||||
|
echo " Size: $(du -sh "${PROJECT_ROOT}/dist/${OUTPUT}" | cut -f1)"
|
||||||
138
installer/livetrace-installer.nsi
Normal file
138
installer/livetrace-installer.nsi
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
; livetrace-installer.nsi
|
||||||
|
; NSIS installer for livetrace v3.3.2
|
||||||
|
; Builds on Linux (or in Docker) with: makensis livetrace-installer.nsi
|
||||||
|
;
|
||||||
|
; Place livetrace-windows-amd64.exe in the same directory before building.
|
||||||
|
|
||||||
|
Unicode True
|
||||||
|
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
; Metadata
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
!define APPNAME "livetrace"
|
||||||
|
!define APPVERSION "3.3.2"
|
||||||
|
!define PUBLISHER "ngtech1ltd"
|
||||||
|
|
||||||
|
; Source binary name (as built by Go)
|
||||||
|
!define SRC_EXE "livetrace-windows-amd64.exe"
|
||||||
|
; Name it will have after installation
|
||||||
|
!define INST_EXE "livetrace.exe"
|
||||||
|
|
||||||
|
; Registry key for Add/Remove Programs
|
||||||
|
!define REG_UNINSTALL \
|
||||||
|
"Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"
|
||||||
|
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
; Installer settings
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
Name "${APPNAME} ${APPVERSION}"
|
||||||
|
OutFile "livetrace-${APPVERSION}-setup.exe"
|
||||||
|
InstallDir "$PROGRAMFILES64\${APPNAME}"
|
||||||
|
InstallDirRegKey HKLM "${REG_UNINSTALL}" "InstallLocation"
|
||||||
|
|
||||||
|
; Administrator rights required (Program Files + system PATH)
|
||||||
|
RequestExecutionLevel admin
|
||||||
|
|
||||||
|
SetCompressor /SOLID lzma
|
||||||
|
SetCompressorDictSize 32
|
||||||
|
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
; UI
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
|
||||||
|
!define MUI_ABORTWARNING
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||||||
|
|
||||||
|
!insertmacro MUI_LANGUAGE "English"
|
||||||
|
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
; Version info (visible in Properties → Details)
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
VIProductVersion "3.3.2.0"
|
||||||
|
VIAddVersionKey "ProductName" "${APPNAME}"
|
||||||
|
VIAddVersionKey "ProductVersion" "${APPVERSION}"
|
||||||
|
VIAddVersionKey "CompanyName" "${PUBLISHER}"
|
||||||
|
VIAddVersionKey "FileDescription" "${APPNAME} Installer"
|
||||||
|
VIAddVersionKey "FileVersion" "${APPVERSION}"
|
||||||
|
VIAddVersionKey "LegalCopyright" "(c) ${PUBLISHER}"
|
||||||
|
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
; PATH helpers (PowerShell – avoids NSIS macro
|
||||||
|
; namespace issues between install / uninstall)
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
; Append $INSTDIR to the machine-wide PATH
|
||||||
|
; Note: $$p / $$parts / $$_ are PowerShell variables — $$ escapes the $ for NSIS
|
||||||
|
!macro AddToPath
|
||||||
|
DetailPrint "Adding $INSTDIR to system PATH …"
|
||||||
|
nsExec::ExecToLog \
|
||||||
|
'powershell.exe -NonInteractive -NoProfile -Command \
|
||||||
|
"$$p = [Environment]::GetEnvironmentVariable(\"Path\",\"Machine\"); \
|
||||||
|
if ($$p -notlike \"*$INSTDIR*\") { \
|
||||||
|
[Environment]::SetEnvironmentVariable(\"Path\", \"$$p;$INSTDIR\", \"Machine\") \
|
||||||
|
}"'
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
; Remove $INSTDIR from the machine-wide PATH
|
||||||
|
!macro RemoveFromPath
|
||||||
|
DetailPrint "Removing $INSTDIR from system PATH …"
|
||||||
|
nsExec::ExecToLog \
|
||||||
|
'powershell.exe -NonInteractive -NoProfile -Command \
|
||||||
|
"$$parts = [Environment]::GetEnvironmentVariable(\"Path\",\"Machine\") -split \";\"; \
|
||||||
|
$$parts = $$parts | Where-Object { $$_ -ne \"$INSTDIR\" }; \
|
||||||
|
[Environment]::SetEnvironmentVariable(\"Path\", ($$parts -join \";\"), \"Machine\")"'
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
; Install section
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
Section "livetrace (required)" SecMain
|
||||||
|
|
||||||
|
SectionIn RO ; cannot be deselected
|
||||||
|
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
|
||||||
|
; Copy binary — rename to plain "livetrace.exe" on the way in
|
||||||
|
File "/oname=${INST_EXE}" "${SRC_EXE}"
|
||||||
|
|
||||||
|
; Add install dir to system PATH
|
||||||
|
!insertmacro AddToPath
|
||||||
|
|
||||||
|
; Register with Add/Remove Programs
|
||||||
|
WriteRegStr HKLM "${REG_UNINSTALL}" "DisplayName" "${APPNAME} ${APPVERSION}"
|
||||||
|
WriteRegStr HKLM "${REG_UNINSTALL}" "DisplayVersion" "${APPVERSION}"
|
||||||
|
WriteRegStr HKLM "${REG_UNINSTALL}" "Publisher" "${PUBLISHER}"
|
||||||
|
WriteRegStr HKLM "${REG_UNINSTALL}" "InstallLocation" "$INSTDIR"
|
||||||
|
WriteRegStr HKLM "${REG_UNINSTALL}" "UninstallString" '"$INSTDIR\uninstall.exe"'
|
||||||
|
WriteRegStr HKLM "${REG_UNINSTALL}" "QuietUninstallString" '"$INSTDIR\uninstall.exe" /S'
|
||||||
|
WriteRegDWORD HKLM "${REG_UNINSTALL}" "NoModify" 1
|
||||||
|
WriteRegDWORD HKLM "${REG_UNINSTALL}" "NoRepair" 1
|
||||||
|
|
||||||
|
; Write the uninstaller
|
||||||
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
; Uninstall section
|
||||||
|
; ──────────────────────────────────────────────
|
||||||
|
Section "Uninstall"
|
||||||
|
|
||||||
|
; Remove from system PATH
|
||||||
|
!insertmacro RemoveFromPath
|
||||||
|
|
||||||
|
; Delete files
|
||||||
|
Delete "$INSTDIR\${INST_EXE}"
|
||||||
|
Delete "$INSTDIR\uninstall.exe"
|
||||||
|
RMDir "$INSTDIR"
|
||||||
|
|
||||||
|
; Remove Add/Remove Programs entry
|
||||||
|
DeleteRegKey HKLM "${REG_UNINSTALL}"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
Loading…
x
Reference in New Issue
Block a user